diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index ec92e7ced4ff2..0969088346491 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -345,50 +345,6 @@ test('encrypted table: SSE-KMS (implicitly created key)', () => { equal(table.encryptionKey, table.bucket.encryptionKey); cdkExpect(stack).to(haveResource('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, Description: 'Created by Default/Table/Bucket', })); @@ -462,7 +418,9 @@ test('encrypted table: SSE-KMS (explicitly created key)', () => { const database = new glue.Database(stack, 'Database', { databaseName: 'database', }); - const encryptionKey = new kms.Key(stack, 'MyKey'); + const encryptionKey = new kms.Key(stack, 'MyKey', { + description: 'OurKey', + }); const table = new glue.Table(stack, 'Table', { database, @@ -480,50 +438,7 @@ test('encrypted table: SSE-KMS (explicitly created key)', () => { notEqual(table.encryptionKey, undefined); cdkExpect(stack).to(haveResource('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, + Description: 'OurKey', })); cdkExpect(stack).to(haveResource('AWS::S3::Bucket', { @@ -690,52 +605,7 @@ test('encrypted table: CSE-KMS (implicitly created key)', () => { notEqual(table.encryptionKey, undefined); equal(table.bucket.encryptionKey, undefined); - cdkExpect(stack).to(haveResource('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - })); + cdkExpect(stack).to(haveResource('AWS::KMS::Key')); cdkExpect(stack).to(haveResource('AWS::Glue::Table', { CatalogId: { @@ -789,7 +659,9 @@ test('encrypted table: CSE-KMS (explicitly created key)', () => { const database = new glue.Database(stack, 'Database', { databaseName: 'database', }); - const encryptionKey = new kms.Key(stack, 'MyKey'); + const encryptionKey = new kms.Key(stack, 'MyKey', { + description: 'MyKey', + }); const table = new glue.Table(stack, 'Table', { database, @@ -807,50 +679,7 @@ test('encrypted table: CSE-KMS (explicitly created key)', () => { equal(table.bucket.encryptionKey, undefined); cdkExpect(stack).to(haveResource('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, + Description: 'MyKey', })); cdkExpect(stack).to(haveResource('AWS::Glue::Table', { @@ -906,7 +735,9 @@ test('encrypted table: CSE-KMS (explicitly passed bucket and key)', () => { databaseName: 'database', }); const bucket = new s3.Bucket(stack, 'Bucket'); - const encryptionKey = new kms.Key(stack, 'MyKey'); + const encryptionKey = new kms.Key(stack, 'MyKey', { + description: 'MyKey', + }); const table = new glue.Table(stack, 'Table', { database, @@ -925,50 +756,7 @@ test('encrypted table: CSE-KMS (explicitly passed bucket and key)', () => { equal(table.bucket.encryptionKey, undefined); cdkExpect(stack).to(haveResource('AWS::KMS::Key', { - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, + Description: 'MyKey', })); cdkExpect(stack).to(haveResource('AWS::Glue::Table', { diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index b9bcf8b92bca8..9c3cdc1eb7125 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -1,7 +1,9 @@ import '@aws-cdk/assert/jest'; +import { arrayWith } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, Duration, Stack, CfnParameter } from '@aws-cdk/core'; +import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import { Stream, StreamEncryption } from '../lib'; /* eslint-disable quote-props */ @@ -329,77 +331,18 @@ describe('Kinesis data streams', () => { test('auto-creates KMS key if encryption type is KMS but no key is provided', () => { const stack = new Stack(); - new Stream(stack, 'MyStream', { + const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS, }); - expect(stack).toMatchTemplate({ - Resources: { - MyStreamKey76F3300E: { - Type: 'AWS::KMS::Key', - Properties: { - Description: 'Created by Default/MyStream', - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - }, - DeletionPolicy: 'Retain', - UpdateReplacePolicy: 'Retain', - }, - MyStream5C050E93: { - Type: 'AWS::Kinesis::Stream', - Properties: { - RetentionPeriodHours: 24, - ShardCount: 1, - StreamEncryption: { - EncryptionType: 'KMS', - KeyId: { - 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'], - }, - }, - }, - }, + expect(stack).toHaveResource('AWS::KMS::Key', { + Description: 'Created by Default/MyStream', + }); + + expect(stack).toHaveResource('AWS::Kinesis::Stream', { + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: stack.resolve(stream.encryptionKey?.keyArn), }, }); }), @@ -416,78 +359,21 @@ describe('Kinesis data streams', () => { encryptionKey: explicitKey, }); - expect(stack).toMatchTemplate({ - Resources: { - ExplicitKey7DF42F37: { - Type: 'AWS::KMS::Key', - Properties: { - Description: 'Explicit Key', - KeyPolicy: { - Statement: [ - { - Action: [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - Effect: 'Allow', - Principal: { - AWS: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::', - { - Ref: 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - }, - DeletionPolicy: 'Retain', - UpdateReplacePolicy: 'Retain', - }, - MyStream5C050E93: { - Type: 'AWS::Kinesis::Stream', - Properties: { - RetentionPeriodHours: 24, - ShardCount: 1, - StreamEncryption: { - EncryptionType: 'KMS', - KeyId: { - 'Fn::GetAtt': ['ExplicitKey7DF42F37', 'Arn'], - }, - }, - }, - }, + expect(stack).toHaveResource('AWS::KMS::Key', { + Description: 'Explicit Key', + }); + + expect(stack).toHaveResource('AWS::Kinesis::Stream', { + RetentionPeriodHours: 24, + ShardCount: 1, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: stack.resolve(explicitKey.keyArn), }, }); }), - test('grantRead creates and attaches a policy with read only access to Stream and EncryptionKey', () => { + test('grantRead creates and attaches a policy with read only access to the principal', () => { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS, @@ -496,6 +382,34 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: stack.resolve(stream.encryptionKey?.keyArn), + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + StreamEncryption: { + KeyId: stack.resolve(stream.encryptionKey?.keyArn), + }, + }); + }); + + // only applicable to legacy behaviour + // With the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag, KMS key policy is not updated. + testLegacyBehavior('grantRead creates and attaches a policy with read only access to EncryptionKey', App, (app) => { + const stack = new Stack(app); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.KMS, + }); + + const user = new iam.User(stack, 'MyUser'); + stream.grantRead(user); + expect(stack).toMatchTemplate({ Resources: { MyStreamKey76F3300E: { @@ -616,7 +530,7 @@ describe('Kinesis data streams', () => { }); }), - test('grantWrite creates and attaches a policy with write only access to Stream and EncryptionKey', () => { + test('grantWrite creates and attaches a policy with write only access to the principal', () => { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS, @@ -625,6 +539,34 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + Action: ['kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Resource: stack.resolve(stream.encryptionKey?.keyArn), + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + StreamEncryption: { + KeyId: stack.resolve(stream.encryptionKey?.keyArn), + }, + }); + }); + + // only applicable to legacy behaviour + // With the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag, KMS key policy is not updated. + testLegacyBehavior('grantWrite creates and attaches a policy with write only access to EncryptionKey', App, (app) => { + const stack = new Stack(app); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.KMS, + }); + + const user = new iam.User(stack, 'MyUser'); + stream.grantWrite(user); + expect(stack).toMatchTemplate({ Resources: { MyStreamKey76F3300E: { @@ -739,7 +681,7 @@ describe('Kinesis data streams', () => { }); }), - test('grantReadWrite creates and attaches a policy with access to Stream and EncryptionKey', () => { + test('grantReadWrite creates and attaches a policy to the principal', () => { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS, @@ -748,6 +690,34 @@ describe('Kinesis data streams', () => { const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + Action: ['kms:Decrypt', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Resource: stack.resolve(stream.encryptionKey?.keyArn), + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + StreamEncryption: { + KeyId: stack.resolve(stream.encryptionKey?.keyArn), + }, + }); + }); + + // only applicable to legacy behaviour + // With the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag, KMS key policy is not updated. + testLegacyBehavior('grantReadWrite creates and attaches a policy with access to EncryptionKey', App, (app) => { + const stack = new Stack(app); + const stream = new Stream(stack, 'MyStream', { + encryption: StreamEncryption.KMS, + }); + + const user = new iam.User(stack, 'MyUser'); + stream.grantReadWrite(user); + expect(stack).toMatchTemplate({ Resources: { MyStreamKey76F3300E: { @@ -1270,8 +1240,8 @@ describe('Kinesis data streams', () => { }); }), - test('fails with encryption due to cyclic dependency', () => { - const app = new App(); + // legacy behaviour as this is fixed with the feature flag. see subsequent test. + testLegacyBehavior('fails with encryption due to cyclic dependency', App, (app) => { const stackA = new Stack(app, 'stackA'); const streamFromStackA = new Stream(stackA, 'MyStream', { encryption: StreamEncryption.KMS, @@ -1285,6 +1255,29 @@ describe('Kinesis data streams', () => { }).toThrow(/'stack.' depends on 'stack.'/); }); + testFutureBehavior('cross stack permissions - with encryption', { '@aws-cdk/aws-kms:defaultKeyPolicies': true }, App, (app) => { + const stackA = new Stack(app, 'stackA'); + const streamFromStackA = new Stream(stackA, 'MyStream', { + encryption: StreamEncryption.KMS, + }); + + const stackB = new Stack(app, 'stackB'); + const user = new iam.User(stackB, 'UserWhoNeedsAccess'); + streamFromStackA.grantRead(user); + + expect(stackB).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith({ + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: { + 'Fn::ImportValue': 'stackA:ExportsOutputFnGetAttMyStreamKey76F3300EArn190947B4', + }, + }), + }, + }); + }); + test('accepts if retentionPeriodHours is a Token', () => { const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index adf4858bae8c8..51b2874311af8 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -5,6 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; +import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as s3 from '../lib'; // to make it easy to copy & paste from output: @@ -254,82 +255,23 @@ describe('bucket', () => { new s3.Bucket(stack, 'MyBucket', { encryptionKey, encryption: s3.BucketEncryption.KMS }); - expect(stack).toMatchTemplate({ - 'Resources': { - 'MyKey6AB29FA6': { - 'Type': 'AWS::KMS::Key', - 'Properties': { - 'Description': 'hello, world', - 'KeyPolicy': { - 'Statement': [ - { - 'Action': [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::', - { - 'Ref': 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - }, - 'DeletionPolicy': 'Retain', - 'UpdateReplacePolicy': 'Retain', - }, - 'MyBucketF68F3FF0': { - 'Type': 'AWS::S3::Bucket', - 'Properties': { - 'BucketEncryption': { - 'ServerSideEncryptionConfiguration': [ - { - 'ServerSideEncryptionByDefault': { - 'KMSMasterKeyID': { - 'Fn::GetAtt': [ - 'MyKey6AB29FA6', - 'Arn', - ], - }, - 'SSEAlgorithm': 'aws:kms', - }, - }, - ], + expect(stack).toHaveResource('AWS::KMS::Key'); + + expect(stack).toHaveResource('AWS::S3::Bucket', { + 'BucketEncryption': { + 'ServerSideEncryptionConfiguration': [ + { + 'ServerSideEncryptionByDefault': { + 'KMSMasterKeyID': { + 'Fn::GetAtt': [ + 'MyKey6AB29FA6', + 'Arn', + ], + }, + 'SSEAlgorithm': 'aws:kms', }, }, - 'DeletionPolicy': 'Retain', - 'UpdateReplacePolicy': 'Retain', - }, + ], }, }); @@ -918,23 +860,9 @@ describe('bucket', () => { }, }); - expect(stack).toHaveResource('AWS::KMS::Key', { + expect(stack).toHaveResourceLike('AWS::KMS::Key', { 'KeyPolicy': { - 'Statement': [ - { - 'Action': ['kms:Create*', 'kms:Describe*', 'kms:Enable*', 'kms:List*', 'kms:Put*', 'kms:Update*', - 'kms:Revoke*', 'kms:Disable*', 'kms:Get*', 'kms:Delete*', 'kms:ScheduleKeyDeletion', 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', 'kms:TagResource', 'kms:UntagResource'], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { - 'Fn::Join': ['', [ - 'arn:', { 'Ref': 'AWS::Partition' }, ':iam::', { 'Ref': 'AWS::AccountId' }, ':root', - ]], - }, - }, - 'Resource': '*', - }, + 'Statement': arrayWith( { 'Action': ['kms:Decrypt', 'kms:DescribeKey'], 'Effect': 'Allow', @@ -942,7 +870,7 @@ describe('bucket', () => { 'Principal': '*', 'Condition': { 'StringEquals': { 'aws:PrincipalOrgID': 'o-1234' } }, }, - ], + ), 'Version': '2012-10-17', }, @@ -951,8 +879,8 @@ describe('bucket', () => { }); - test('if an encryption key is included, encrypt/decrypt permissions are also added both ways', () => { - const stack = new cdk.Stack(); + testLegacyBehavior('if an encryption key is included, encrypt/decrypt permissions are also added both ways', cdk.App, (app) => { + const stack = new cdk.Stack(app); const bucket = new s3.Bucket(stack, 'MyBucket', { encryption: s3.BucketEncryption.KMS }); const user = new iam.User(stack, 'MyUser'); bucket.grantReadWrite(user); @@ -1122,8 +1050,6 @@ describe('bucket', () => { }, }, }); - - }); test('does not grant PutObjectAcl when the S3_GRANT_WRITE_WITHOUT_ACL feature is enabled', () => { @@ -1175,165 +1101,63 @@ describe('bucket', () => { const user = new iam.User(stack, 'MyUser'); bucket.grantWrite(user); - expect(stack).toMatchTemplate({ - 'Resources': { - 'MyBucketKeyC17130CF': { - 'Type': 'AWS::KMS::Key', - 'Properties': { - 'KeyPolicy': { - 'Statement': [ - { - 'Action': [ - 'kms:Create*', - 'kms:Describe*', - 'kms:Enable*', - 'kms:List*', - 'kms:Put*', - 'kms:Update*', - 'kms:Revoke*', - 'kms:Disable*', - 'kms:Get*', - 'kms:Delete*', - 'kms:ScheduleKeyDeletion', - 'kms:CancelKeyDeletion', - 'kms:GenerateDataKey', - 'kms:TagResource', - 'kms:UntagResource', - ], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::', - { - 'Ref': 'AWS::AccountId', - }, - ':root', - ], - ], - }, - }, - 'Resource': '*', - }, - { - 'Action': [ - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - 'kms:Decrypt', - ], - 'Effect': 'Allow', - 'Principal': { - 'AWS': { - 'Fn::GetAtt': [ - 'MyUserDC45028B', - 'Arn', - ], - }, - }, - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'Description': 'Created by Default/MyBucket', - }, - 'UpdateReplacePolicy': 'Retain', - 'DeletionPolicy': 'Retain', - }, - 'MyBucketF68F3FF0': { - 'Type': 'AWS::S3::Bucket', - 'Properties': { - 'BucketEncryption': { - 'ServerSideEncryptionConfiguration': [ - { - 'ServerSideEncryptionByDefault': { - 'KMSMasterKeyID': { - 'Fn::GetAtt': [ - 'MyBucketKeyC17130CF', - 'Arn', - ], - }, - 'SSEAlgorithm': 'aws:kms', - }, - }, - ], - }, - }, - 'UpdateReplacePolicy': 'Retain', - 'DeletionPolicy': 'Retain', - }, - 'MyUserDC45028B': { - 'Type': 'AWS::IAM::User', - }, - 'MyUserDefaultPolicy7B897426': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 's3:DeleteObject*', - 's3:PutObject*', - 's3:Abort*', - ], - 'Effect': 'Allow', - 'Resource': [ + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 's3:DeleteObject*', + 's3:PutObject*', + 's3:Abort*', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ { 'Fn::GetAtt': [ 'MyBucketF68F3FF0', 'Arn', ], }, - { - 'Fn::Join': [ - '', - [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - '/*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - 'kms:Decrypt', + '/*', ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyBucketKeyC17130CF', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyUserDefaultPolicy7B897426', - 'Users': [ - { - 'Ref': 'MyUserDC45028B', + ], }, ], }, - }, + { + 'Action': [ + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + 'kms:Decrypt', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyBucketKeyC17130CF', + 'Arn', + ], + }, + }, + ], + 'Version': '2012-10-17', }, + 'PolicyName': 'MyUserDefaultPolicy7B897426', + 'Users': [ + { + 'Ref': 'MyUserDC45028B', + }, + ], });