You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
S3 SSE-C encryption support.
This feature (enabled with --repo-s3-sse-customer-key) provides an encryption key to encrypt the data after it has been transmitted to the server. While not as secure as encrypting data before transmission (--repo-cipher-type), this may be useful in certain configurations.
This commit is contained in:
@@ -748,8 +748,8 @@ hrnHostConfig(HrnHost *const this)
|
||||
this->pub.repo1Storage = storageS3New(
|
||||
hrnHostRepo1Path(this), true, NULL, STRDEF(HRN_HOST_S3_BUCKET), STRDEF(HRN_HOST_S3_ENDPOINT),
|
||||
storageS3UriStyleHost, STR(HRN_HOST_S3_REGION), storageS3KeyTypeShared, STRDEF(HRN_HOST_S3_ACCESS_KEY),
|
||||
STRDEF(HRN_HOST_S3_ACCESS_SECRET_KEY), NULL, NULL, NULL, NULL, 5 * 1024 * 1024, NULL, hrnHostIp(s3),
|
||||
443, ioTimeoutMs(), false, NULL, NULL);
|
||||
STRDEF(HRN_HOST_S3_ACCESS_SECRET_KEY), NULL, NULL, NULL, NULL, NULL, 5 * 1024 * 1024, NULL,
|
||||
hrnHostIp(s3), 443, ioTimeoutMs(), false, NULL, NULL);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
|
||||
|
||||
@@ -321,6 +321,7 @@ testRun(void)
|
||||
" --repo-s3-kms-key-id S3 repository KMS key\n"
|
||||
" --repo-s3-region S3 repository region\n"
|
||||
" --repo-s3-role S3 repository role\n"
|
||||
" --repo-s3-sse-customer-key S3 Repository SSE Customer Key\n"
|
||||
" --repo-s3-token S3 repository security token\n"
|
||||
" --repo-s3-uri-style S3 URI Style [default=host]\n"
|
||||
" --repo-sftp-host SFTP repository host\n"
|
||||
|
||||
@@ -29,6 +29,7 @@ typedef struct TestRequestParam
|
||||
const char *securityToken;
|
||||
const char *range;
|
||||
const char *kms;
|
||||
const char *sseC;
|
||||
const char *ttl;
|
||||
const char *token;
|
||||
const char *tag;
|
||||
@@ -82,6 +83,14 @@ testRequest(IoWrite *write, Storage *s3, const char *verb, const char *path, Tes
|
||||
if (param.kms != NULL)
|
||||
strCatZ(request, ";x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id");
|
||||
|
||||
if (param.sseC != NULL)
|
||||
{
|
||||
strCatZ(
|
||||
request,
|
||||
";x-amz-server-side-encryption-customer-algorithm;x-amz-server-side-encryption-customer-key"
|
||||
";x-amz-server-side-encryption-customer-key-md5");
|
||||
}
|
||||
|
||||
if (param.tag != NULL)
|
||||
strCatZ(request, ";x-amz-tagging");
|
||||
|
||||
@@ -136,6 +145,16 @@ testRequest(IoWrite *write, Storage *s3, const char *verb, const char *path, Tes
|
||||
strCatFmt(request, "x-amz-server-side-encryption-aws-kms-key-id:%s\r\n", param.kms);
|
||||
}
|
||||
|
||||
// Add sseC key
|
||||
if (param.sseC != NULL)
|
||||
{
|
||||
strCatZ(request, "x-amz-server-side-encryption-customer-algorithm:AES256\r\n");
|
||||
strCatFmt(request, "x-amz-server-side-encryption-customer-key:%s\r\n", param.sseC);
|
||||
strCatFmt(
|
||||
request, "x-amz-server-side-encryption-customer-key-md5:%s\r\n",
|
||||
strZ(strNewEncode(encodingBase64, cryptoHashOne(hashTypeMd5, bufNewDecode(encodingBase64, STR(param.sseC))))));
|
||||
}
|
||||
|
||||
// Add tags
|
||||
if (param.tag != NULL)
|
||||
strCatFmt(request, "x-amz-tagging:%s\r\n", param.tag);
|
||||
@@ -492,9 +511,11 @@ testRun(void)
|
||||
hrnCfgArgRaw(argList, cfgOptRepoS3Role, credRole);
|
||||
hrnCfgArgRawStrId(argList, cfgOptRepoS3KeyType, storageS3KeyTypeAuto);
|
||||
hrnCfgArgRawZ(argList, cfgOptRepoS3KmsKeyId, "kmskey1");
|
||||
hrnCfgEnvRawZ(cfgOptRepoS3SseCustomerKey, "rA1P");
|
||||
hrnCfgArgRawZ(argList, cfgOptRepoStorageTag, "Key1=Value1");
|
||||
hrnCfgArgRawZ(argList, cfgOptRepoStorageTag, " Key 2= Value 2");
|
||||
HRN_CFG_LOAD(cfgCmdArchivePush, argList);
|
||||
hrnCfgEnvRemoveRaw(cfgOptRepoS3SseCustomerKey);
|
||||
|
||||
s3 = storageRepoGet(0, true);
|
||||
driver = (StorageS3 *)storageDriver(s3);
|
||||
@@ -660,7 +681,7 @@ testRun(void)
|
||||
|
||||
hrnServerScriptClose(auth);
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_GET, "/file.txt", .accessKey = "x", .securityToken = "z");
|
||||
testRequestP(service, s3, HTTP_VERB_GET, "/file.txt", .accessKey = "x", .securityToken = "z", .sseC = "rA1P");
|
||||
testResponseP(service, .code = 303, .content = "CONTENT");
|
||||
|
||||
StorageRead *read = NULL;
|
||||
@@ -680,6 +701,9 @@ testRun(void)
|
||||
"x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n"
|
||||
"x-amz-date: <redacted>\n"
|
||||
"x-amz-security-token: <redacted>\n"
|
||||
"x-amz-server-side-encryption-customer-algorithm: AES256\n"
|
||||
"x-amz-server-side-encryption-customer-key: <redacted>\n"
|
||||
"x-amz-server-side-encryption-customer-key-md5: <redacted>\n"
|
||||
"*** Response Headers ***:\n"
|
||||
"content-length: 7\n"
|
||||
"*** Response Content ***:\n"
|
||||
@@ -713,7 +737,7 @@ testRun(void)
|
||||
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt", .content = "ABCD", .accessKey = "xx", .securityToken = "zz",
|
||||
.kms = "kmskey1", .tag = "%20Key%202=%20Value%202&Key1=Value1");
|
||||
.kms = "kmskey1", .sseC = "rA1P", .tag = "%20Key%202=%20Value%202&Key1=Value1");
|
||||
testResponseP(service);
|
||||
|
||||
// Make a copy of the signing key to verify that it gets changed when the keys are updated
|
||||
@@ -746,7 +770,7 @@ testRun(void)
|
||||
TEST_TITLE("write zero-length file");
|
||||
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt", .content = "", .kms = "kmskey1",
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt", .content = "", .kms = "kmskey1", .sseC = "rA1P",
|
||||
.tag = "%20Key%202=%20Value%202&Key1=Value1");
|
||||
testResponseP(service);
|
||||
|
||||
@@ -757,7 +781,7 @@ testRun(void)
|
||||
TEST_TITLE("write file in chunks with nothing left over on close");
|
||||
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1",
|
||||
service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1", .sseC = "rA1P",
|
||||
.tag = "%20Key%202=%20Value%202&Key1=Value1");
|
||||
testResponseP(
|
||||
service,
|
||||
@@ -769,10 +793,14 @@ testRun(void)
|
||||
"<UploadId>WxRt</UploadId>"
|
||||
"</InitiateMultipartUploadResult>");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=WxRt", .content = "1234567890123456");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=WxRt", .content = "1234567890123456",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "etag:WxRt1");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=WxRt", .content = "7890123456789012");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=WxRt", .content = "7890123456789012",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "eTag:WxRt2");
|
||||
|
||||
testRequestP(
|
||||
@@ -798,7 +826,7 @@ testRun(void)
|
||||
// Stop writing tags
|
||||
driver->tag = NULL;
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1");
|
||||
testRequestP(service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1", .sseC = "rA1P");
|
||||
testResponseP(
|
||||
service,
|
||||
.content =
|
||||
@@ -809,10 +837,14 @@ testRun(void)
|
||||
"<UploadId>WxRt</UploadId>"
|
||||
"</InitiateMultipartUploadResult>");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=WxRt", .content = "1234567890123456");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=WxRt", .content = "1234567890123456",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "etag:WxRt1");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=WxRt", .content = "7890123456789012");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=WxRt", .content = "7890123456789012",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "eTag:WxRt2");
|
||||
|
||||
testRequestP(
|
||||
@@ -852,7 +884,7 @@ testRun(void)
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("write file in chunks with something left over on close");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1");
|
||||
testRequestP(service, s3, HTTP_VERB_POST, "/file.txt?uploads=", .kms = "kmskey1", .sseC = "rA1P");
|
||||
testResponseP(
|
||||
service,
|
||||
.content =
|
||||
@@ -863,10 +895,14 @@ testRun(void)
|
||||
"<UploadId>RR55</UploadId>"
|
||||
"</InitiateMultipartUploadResult>");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=RR55", .content = "1234567890123456");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=1&uploadId=RR55", .content = "1234567890123456",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "etag:RR551");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=RR55", .content = "7890");
|
||||
testRequestP(
|
||||
service, s3, HTTP_VERB_PUT, "/file.txt?partNumber=2&uploadId=RR55", .content = "7890",
|
||||
.sseC = "rA1P");
|
||||
testResponseP(service, .header = "eTag:RR552");
|
||||
|
||||
testRequestP(
|
||||
@@ -889,7 +925,7 @@ testRun(void)
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("file missing");
|
||||
|
||||
testRequestP(service, s3, HTTP_VERB_HEAD, "/BOGUS");
|
||||
testRequestP(service, s3, HTTP_VERB_HEAD, "/BOGUS", .sseC = "rA1P");
|
||||
testResponseP(service, .code = 404);
|
||||
|
||||
TEST_RESULT_BOOL(storageExistsP(s3, STRDEF("BOGUS")), false, "check");
|
||||
|
||||
Reference in New Issue
Block a user