From aadaafcb4f97baa86a25fbc715061b9bca21a1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20G=C3=A5rdebrink?= Date: Thu, 14 Dec 2023 00:07:42 +0000 Subject: [PATCH] Update with tests for cross-account KMS key grant --- .../test/params-and-secrets.test.ts | 55 ++- .../aws-secretsmanager/lib/secret.ts | 2 +- .../aws-secretsmanager/test/secret.test.ts | 356 ++++++++++++++++-- 3 files changed, 350 insertions(+), 63 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts b/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts index 93e94462e28cb..95da7dd4fe22a 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts @@ -433,6 +433,32 @@ describe('params and secrets', () => { Ref: 'SecretA720EF05', }, }, + { + Action: 'kms:Decrypt', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }, ], Version: '2012-10-17', }, @@ -555,35 +581,6 @@ describe('params and secrets', () => { }, Resource: '*', }, - { - Action: 'kms:Decrypt', - Condition: { - StringEquals: { - 'kms:ViaService': { - 'Fn::Join': [ - '', - [ - 'secretsmanager.', - { - Ref: 'AWS::Region', - }, - '.amazonaws.com', - ], - ], - }, - }, - }, - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'FunctionServiceRole675BB04A', - 'Arn', - ], - }, - }, - Resource: '*', - }, ]), }, }); diff --git a/packages/aws-cdk-lib/aws-secretsmanager/lib/secret.ts b/packages/aws-cdk-lib/aws-secretsmanager/lib/secret.ts index 9c73f0fb55545..2eeb47c16fb77 100644 --- a/packages/aws-cdk-lib/aws-secretsmanager/lib/secret.ts +++ b/packages/aws-cdk-lib/aws-secretsmanager/lib/secret.ts @@ -382,7 +382,7 @@ abstract class SecretBase extends Resource implements ISecret { if (this.encryptionKey) { // @see https://docs.aws.amazon.com/kms/latest/developerguide/services-secrets-manager.html this.encryptionKey.grantDecrypt( - new kms.ViaServicePrincipal(`secretsmanager.${Stack.of(this).region}.amazonaws.com`, grantee.grantPrincipal), + new kms.ViaServicePrincipal(`secretsmanager.${Stack.of(this).region}.amazonaws.com`, grantee.grantPrincipal) ); } diff --git a/packages/aws-cdk-lib/aws-secretsmanager/test/secret.test.ts b/packages/aws-cdk-lib/aws-secretsmanager/test/secret.test.ts index 38ed48e3fbf55..3bf2892b94975 100644 --- a/packages/aws-cdk-lib/aws-secretsmanager/test/secret.test.ts +++ b/packages/aws-cdk-lib/aws-secretsmanager/test/secret.test.ts @@ -138,6 +138,53 @@ test('secret with kms', () => { }); }); +test('imported cross-account secret with kms key', () => { + // GIVEN + const key = kms.Key.fromKeyArn(stack, 'kms', 'arn:aws:kms:eu-west-1:111111111111:key/1234abcd-12ab-34cd-56ef-1234567890ab'); + const user = new iam.User(stack, 'User'); + + // WHEN + const secret = secretsmanager.Secret.fromSecretAttributes(stack, 'Secret', { + secretCompleteArn: 'arn:aws:secretsmanager:eu-west-1:111111111111:secret:MySecret-f3gDy9', + encryptionKey: key, + }); + + secret.grantRead(user); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([{ + Action: ['secretsmanager:GetSecretValue', 'secretsmanager:DescribeSecret'], + Effect: 'Allow', + Resource: 'arn:aws:secretsmanager:eu-west-1:111111111111:secret:MySecret-f3gDy9', + }, + { + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: 'arn:aws:kms:eu-west-1:111111111111:key/1234abcd-12ab-34cd-56ef-1234567890ab', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + }]), + Version: '2012-10-17', + }, + }); +}); + test('secret with generate secret string options', () => { // WHEN new secretsmanager.Secret(stack, 'Secret', { @@ -337,6 +384,32 @@ test('grantRead with KMS Key', () => { ], Effect: 'Allow', Resource: { Ref: 'SecretA720EF05' }, + }, + { + Action: 'kms:Decrypt', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'KMS6B14D45A', + 'Arn', + ], + }, }], }, }); @@ -344,7 +417,32 @@ test('grantRead with KMS Key', () => { KeyPolicy: { Statement: Match.arrayWith([ { - Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, Condition: { StringEquals: { 'kms:ViaService': { @@ -361,16 +459,48 @@ test('grantRead with KMS Key', () => { }, }, }, + }, + { Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:CreateGrant', + 'kms:DescribeKey', + ], Principal: { AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], ], }, }, - Resource: '*', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, }, ]), Version: '2012-10-17', @@ -498,12 +628,8 @@ test('grantRead with version label constraint', () => { 'secretsmanager:VersionStage': ['FOO', 'bar'], }, }, - }], - }, - }); - Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { - KeyPolicy: { - Statement: Match.arrayWith([{ + }, + { Action: 'kms:Decrypt', Condition: { StringEquals: { @@ -522,16 +648,100 @@ test('grantRead with version label constraint', () => { }, }, Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', - ], + Resource: { 'Fn::GetAtt': ['KMS6B14D45A', 'Arn'] }, + }], + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { + KeyPolicy: { + Statement: Match.arrayWith([ + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, }, }, - Resource: '*', - }]), + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:CreateGrant', + 'kms:DescribeKey', + ], + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + }, + ]), Version: '2012-10-17', }, }); @@ -581,12 +791,8 @@ test('grantWrite with kms', () => { ], Effect: 'Allow', Resource: { Ref: 'SecretA720EF05' }, - }], - }, - }); - Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { - KeyPolicy: { - Statement: Match.arrayWith([{ + }, + { Action: [ 'kms:Encrypt', 'kms:ReEncrypt*', @@ -609,16 +815,100 @@ test('grantWrite with kms', () => { }, }, Effect: 'Allow', - Principal: { - AWS: { - 'Fn::GetAtt': [ - 'Role1ABCC5F0', - 'Arn', - ], + Resource: { 'Fn::GetAtt': ['KMS6B14D45A', 'Arn'] }, + }], + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { + KeyPolicy: { + Statement: Match.arrayWith([ + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, }, }, - Resource: '*', - }]), + { + Effect: 'Allow', + Resource: '*', + Action: [ + 'kms:CreateGrant', + 'kms:DescribeKey', + ], + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + }, + ]), }, }); });