diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts index c4facf9fd4f19..9bf124c31c71d 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts @@ -42,6 +42,13 @@ export interface AwsCloudFormationStackProperties { */ readonly assumeRoleArn?: string; + /** + * External ID to use when assuming role for cloudformation deployments + * + * @default - No external ID + */ + readonly assumeRoleExternalId?: string; + /** * The role that is passed to CloudFormation to execute the change set * @@ -149,4 +156,4 @@ export interface NestedCloudAssemblyProperties { export type ArtifactProperties = AwsCloudFormationStackProperties | AssetManifestProperties | TreeArtifactProperties -| NestedCloudAssemblyProperties; \ No newline at end of file +| NestedCloudAssemblyProperties; diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json index 3c0f38f598570..171c57d064b93 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json @@ -299,6 +299,10 @@ "description": "The role that needs to be assumed to deploy the stack (Default - No role is assumed (current credentials are used))", "type": "string" }, + "assumeRoleExternalId": { + "description": "External ID to use when assuming role for cloudformation deployments (Default - No external ID)", + "type": "string" + }, "cloudFormationExecutionRoleArn": { "description": "The role that is passed to CloudFormation to execute the change set (Default - No role is passed (currently assumed role/credentials are used))", "type": "string" diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index 42c883f995fd4..72764c536bcd9 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"12.0.0"} \ No newline at end of file +{"version":"13.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index 3030b687f1244..5c4072c3efc5c 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -98,6 +98,13 @@ export interface DefaultStackSynthesizerProps { */ readonly imageAssetPublishingExternalId?: string; + /** + * External ID to use when assuming role for cloudformation deployments + * + * @default - No external ID + */ + readonly deployRoleExternalId?: string; + /** * The role to assume to initiate a deployment in this environment * @@ -424,6 +431,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer { const artifactId = this.writeAssetManifest(session); this.emitStackArtifact(this.stack, session, { + assumeRoleExternalId: this.props.deployRoleExternalId, assumeRoleArn: this._deployRoleArn, cloudFormationExecutionRoleArn: this._cloudFormationExecutionRoleArn, stackTemplateAssetObjectUrl: templateManifestUrl, diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts index 1a43f9da11316..3b283eaae24ce 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/stack-synthesizer.ts @@ -86,6 +86,13 @@ export interface SynthesizeStackArtifactOptions { */ readonly assumeRoleArn?: string; + /** + * The externalID to use with the assumeRoleArn + * + * @default - No externalID is used + */ + readonly assumeRoleExternalId?: string; + /** * The role that is passed to CloudFormation to execute the change set * @@ -121,4 +128,4 @@ export interface SynthesizeStackArtifactOptions { * @default - Bootstrap stack version number looked up */ readonly bootstrapStackVersionSsmParameter?: string; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts b/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts index 93ba7be190e48..67e8fcbfaae17 100644 --- a/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts +++ b/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts @@ -273,6 +273,26 @@ nodeunitShim({ test.done(); }, + 'customize deploy role externalId'(test: Test) { + // GIVEN + const myapp = new App(); + + // WHEN + const mystack = new Stack(myapp, 'mystack', { + synthesizer: new DefaultStackSynthesizer({ + deployRoleExternalId: 'deploy-external-id', + }), + }); + + // THEN + const asm = myapp.synth(); + + const stackArtifact = asm.getStack(mystack.stackName); + expect(stackArtifact.assumeRoleExternalId).toEqual('deploy-external-id'); + + test.done(); + }, + 'synthesis with bucketPrefix'(test: Test) { // GIVEN const myapp = new App(); diff --git a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts index dba5bacb6beb0..225f256e85f5f 100644 --- a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts @@ -61,6 +61,13 @@ export class CloudFormationStackArtifact extends CloudArtifact { */ public readonly assumeRoleArn?: string; + /** + * External ID to use when assuming role for cloudformation deployments + * + * @default - No external ID + */ + readonly assumeRoleExternalId?: string; + /** * The role that is passed to CloudFormation to execute the change set * @@ -121,6 +128,7 @@ export class CloudFormationStackArtifact extends CloudArtifact { // from the stack metadata this.tags = properties.tags ?? this.tagsFromMetadata(); this.assumeRoleArn = properties.assumeRoleArn; + this.assumeRoleExternalId = properties.assumeRoleExternalId; this.cloudFormationExecutionRoleArn = properties.cloudFormationExecutionRoleArn; this.stackTemplateAssetObjectUrl = properties.stackTemplateAssetObjectUrl; this.requiresBootstrapStackVersion = properties.requiresBootstrapStackVersion; @@ -165,4 +173,4 @@ export class CloudFormationStackArtifact extends CloudArtifact { } return ret; } -} \ No newline at end of file +} diff --git a/packages/aws-cdk/lib/api/cloudformation-deployments.ts b/packages/aws-cdk/lib/api/cloudformation-deployments.ts index 84fac5cb15922..ed783e0826fd7 100644 --- a/packages/aws-cdk/lib/api/cloudformation-deployments.ts +++ b/packages/aws-cdk/lib/api/cloudformation-deployments.ts @@ -251,6 +251,7 @@ export class CloudFormationDeployments { const stackSdk = await this.sdkProvider.forEnvironment(resolvedEnvironment, mode, { assumeRoleArn: arns.assumeRoleArn, + assumeRoleExternalId: stack.assumeRoleExternalId, }); return {