Skip to content

Commit

Permalink
fix(s3): Bucket Key cannot be used with KMS_MANAGED key (#22331)
Browse files Browse the repository at this point in the history
- BucketEncryption.KMS means: bring your own key.
- BucketEncryption.KMS_MANAGED means: use the AWS default key (which is free).

Bucket Key means "S3 uses a shadow key to reduce cost on encryption operations". It should apply to both KMS use cases, but was written to only apply to the BYOK scenario.

Also allow the other one.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr committed Oct 4, 2022
1 parent 2c8195a commit 63d3c54
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 20 deletions.
24 changes: 16 additions & 8 deletions packages/@aws-cdk/aws-s3/lib/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1354,10 +1354,15 @@ export interface BucketProps {
readonly enforceSSL?: boolean;

/**
* Specifies whether Amazon S3 should use an S3 Bucket Key with server-side
* encryption using KMS (SSE-KMS) for new objects in the bucket.
* Whether Amazon S3 should use its own intermediary key to generate data keys.
*
* Only relevant, when Encryption is set to {@link BucketEncryption.KMS}
* Only relevant when using KMS for encryption.
*
* - If not enabled, every object GET and PUT will cause an API call to KMS (with the
* attendant cost implications of that).
* - If enabled, S3 will use its own time-limited key instead.
*
* Only relevant, when Encryption is set to `BucketEncryption.KMS` or `BucketEncryption.KMS_MANAGED`.
*
* @default - false
*/
Expand Down Expand Up @@ -1943,7 +1948,7 @@ export class Bucket extends BucketBase {
}

// if bucketKeyEnabled is set, encryption must be set to KMS.
if (props.bucketKeyEnabled && encryptionType !== BucketEncryption.KMS) {
if (props.bucketKeyEnabled && ![BucketEncryption.KMS, BucketEncryption.KMS_MANAGED].includes(encryptionType)) {
throw new Error(`bucketKeyEnabled is specified, so 'encryption' must be set to KMS (value: ${encryptionType})`);
}

Expand Down Expand Up @@ -1983,7 +1988,10 @@ export class Bucket extends BucketBase {
if (encryptionType === BucketEncryption.KMS_MANAGED) {
const bucketEncryption = {
serverSideEncryptionConfiguration: [
{ serverSideEncryptionByDefault: { sseAlgorithm: 'aws:kms' } },
{
bucketKeyEnabled: props.bucketKeyEnabled,
serverSideEncryptionByDefault: { sseAlgorithm: 'aws:kms' },
},
],
};
return { bucketEncryption };
Expand Down Expand Up @@ -2288,17 +2296,17 @@ export enum BucketEncryption {
/**
* Objects in the bucket are not encrypted.
*/
UNENCRYPTED = 'NONE',
UNENCRYPTED = 'UNENCRYPTED',

/**
* Server-side KMS encryption with a master key managed by KMS.
*/
KMS_MANAGED = 'MANAGED',
KMS_MANAGED = 'KMS_MANAGED',

/**
* Server-side encryption with a master key managed by S3.
*/
S3_MANAGED = 'S3MANAGED',
S3_MANAGED = 'S3_MANAGED',

/**
* Server-side encryption with a KMS key managed by the user.
Expand Down
18 changes: 6 additions & 12 deletions packages/@aws-cdk/aws-s3/test/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,25 +306,19 @@ describe('bucket', () => {
});
});

test('bucketKeyEnabled can be enabled', () => {
test.each([s3.BucketEncryption.KMS, s3.BucketEncryption.KMS_MANAGED])('bucketKeyEnabled can be enabled with %p encryption', (encryption) => {
const stack = new cdk.Stack();

new s3.Bucket(stack, 'MyBucket', { bucketKeyEnabled: true, encryption: s3.BucketEncryption.KMS });
new s3.Bucket(stack, 'MyBucket', { bucketKeyEnabled: true, encryption });

Template.fromStack(stack).hasResourceProperties('AWS::S3::Bucket', {
'BucketEncryption': {
'ServerSideEncryptionConfiguration': [
{
'BucketKeyEnabled': true,
'ServerSideEncryptionByDefault': {
'KMSMasterKeyID': {
'Fn::GetAtt': [
'MyBucketKeyC17130CF',
'Arn',
],
},
'ServerSideEncryptionByDefault': Match.objectLike({
'SSEAlgorithm': 'aws:kms',
},
}),
},
],
},
Expand All @@ -336,10 +330,10 @@ describe('bucket', () => {

expect(() => {
new s3.Bucket(stack, 'MyBucket', { bucketKeyEnabled: true, encryption: s3.BucketEncryption.S3_MANAGED });
}).toThrow("bucketKeyEnabled is specified, so 'encryption' must be set to KMS (value: S3MANAGED)");
}).toThrow("bucketKeyEnabled is specified, so 'encryption' must be set to KMS (value: S3_MANAGED)");
expect(() => {
new s3.Bucket(stack, 'MyBucket3', { bucketKeyEnabled: true });
}).toThrow("bucketKeyEnabled is specified, so 'encryption' must be set to KMS (value: NONE)");
}).toThrow("bucketKeyEnabled is specified, so 'encryption' must be set to KMS (value: UNENCRYPTED)");

});

Expand Down

0 comments on commit 63d3c54

Please sign in to comment.