From 627b719e104372b7b4fb6df74de9c1ccb784adc8 Mon Sep 17 00:00:00 2001 From: Son Hyunbin <147061193+SickofU@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:59:10 +0900 Subject: [PATCH] fix(cli): bootstrap FilePublishingRoleDefaultPolicy KMS ARN when FileAssetsBucketKmsKeyId is an ARN The bootstrap template always constructed the KMS resource ARN for the FilePublishingRoleDefaultPolicy as 'arn:${Partition}:kms:${Region}:${AccountId}:key/${FileAssetsBucketKmsKeyId}'. The FileAssetsBucketKmsKeyId parameter description explicitly permits either a key ID or a full key ARN, so when a (cross-account) key ARN is supplied this produced a malformed 'arn:...:key/arn:aws:kms:...' value and an invalid IAM policy statement. Add a HasCustomKmsKeyArn condition that detects the ARN form (first ':'-delimited token equals 'arn') and, in that case, uses the value directly as the resource; bare key IDs keep the existing 'key/${...}' construction. The create-new-key and AWS_MANAGED_KEY paths are unaffected. --- .../api/bootstrap/bootstrap-template.test.ts | 34 +++++++++++++++++++ .../lib/api/bootstrap/bootstrap-template.yaml | 16 ++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/toolkit-lib/test/api/bootstrap/bootstrap-template.test.ts b/packages/@aws-cdk/toolkit-lib/test/api/bootstrap/bootstrap-template.test.ts index 57b8a65ac..ecc80c099 100644 --- a/packages/@aws-cdk/toolkit-lib/test/api/bootstrap/bootstrap-template.test.ts +++ b/packages/@aws-cdk/toolkit-lib/test/api/bootstrap/bootstrap-template.test.ts @@ -74,4 +74,38 @@ describe('bootstrap template', () => { test('has the same values for BootstrapVersion Parameter and Output', async () => { expect(template.Outputs.BootstrapVersion.Value).toEqual(template.Resources.CdkBootstrapVersion.Properties.Value); }); + + test('uses FileAssetsBucketKmsKeyId directly when it is already an ARN', async () => { + // The parameter description allows FileAssetsBucketKmsKeyId to be either a key ID or a key ARN. + // Verify the condition that distinguishes the two forms exists. + expect(template.Conditions.HasCustomKmsKeyArn).toEqual({ + 'Fn::Equals': [ + 'arn', + { 'Fn::Select': [0, { 'Fn::Split': [':', { Ref: 'FileAssetsBucketKmsKeyId' }] }] }, + ], + }); + + // Locate the KMS statement in the FilePublishingRoleDefaultPolicy. + const statements = template.Resources.FilePublishingRoleDefaultPolicy.Properties.PolicyDocument.Statement; + const kmsStatement = statements.find( + (stmt: any) => Array.isArray(stmt.Action) && stmt.Action.includes('kms:Decrypt'), + ); + expect(kmsStatement).toBeDefined(); + + // When a custom key is supplied, an ARN value must be used verbatim (no 'key/${...}' wrapping), + // while a bare key ID keeps the constructed 'arn:...:key/${...}' form. + expect(kmsStatement.Resource).toEqual({ + 'Fn::If': [ + 'CreateNewKey', + { 'Fn::Sub': '${FileAssetsBucketEncryptionKey.Arn}' }, + { + 'Fn::If': [ + 'HasCustomKmsKeyArn', + { 'Fn::Sub': '${FileAssetsBucketKmsKeyId}' }, + { 'Fn::Sub': 'arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${FileAssetsBucketKmsKeyId}' }, + ], + }, + ], + }); + }); }); diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml index 69a325a5c..f0af0c0e2 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml @@ -103,6 +103,17 @@ Conditions: Fn::Equals: - 'AWS_MANAGED_KEY' - Ref: FileAssetsBucketKmsKeyId + # FileAssetsBucketKmsKeyId may be either a bare key ID or a full key ARN (see the + # parameter description). Detect the ARN form by checking whether the first ':'-delimited + # token is 'arn', so we don't wrap an ARN inside another 'arn:...:key/...' construction. + HasCustomKmsKeyArn: + Fn::Equals: + - 'arn' + - Fn::Select: + - 0 + - Fn::Split: + - ':' + - Ref: FileAssetsBucketKmsKeyId ShouldCreatePermissionsBoundary: Fn::Equals: - 'true' @@ -539,7 +550,10 @@ Resources: Fn::If: - CreateNewKey - Fn::Sub: "${FileAssetsBucketEncryptionKey.Arn}" - - Fn::Sub: arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${FileAssetsBucketKmsKeyId} + - Fn::If: + - HasCustomKmsKeyArn + - Fn::Sub: "${FileAssetsBucketKmsKeyId}" + - Fn::Sub: arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${FileAssetsBucketKmsKeyId} Version: '2012-10-17' Roles: - Ref: FilePublishingRole