From 65265e1297f47a5e8e85ade620095c5af1082290 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Thu, 4 May 2023 03:42:37 -0400 Subject: [PATCH] fix(core): crossRegionReferences don't work across multiple regions (#25384) The first attempt to fix this in #25190 didn't work because it didn't account for the fact that when exporting to multiple regions, we create multiple `ExportWriter`s that all use the same provider (and provider role). This PR fixes that by adding the policy cross region ARNs directly to the custom resource provider (1 per stack) rather than the `ExportWriter` (multiple per stack). I also updated the test case to better account for this scenario. fixes #25377 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../cross-region-producer.assets.json | 4 +- .../cross-region-producer.template.json | 12 + ...efaultTestDeployAssertAB7415FD.assets.json | 4 +- ...aultTestDeployAssertAB7415FD.template.json | 4 +- .../manifest.json | 4 +- .../export-writer-provider.ts | 75 ++- packages/aws-cdk-lib/core/lib/private/refs.ts | 6 +- .../export-writer-provider.test.ts | 570 +++++++++--------- 8 files changed, 352 insertions(+), 327 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.assets.json index e720a602ff858..3f4511cfd464b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.assets.json @@ -29,7 +29,7 @@ } } }, - "a645bb0b063dc77d60a1af0c1e427999161c49fe9008543153cb48fed642a943": { + "f93ad4a2004b446276ef3fac1ada613b58a45257e6bfd66f18ab8119232f6131": { "source": { "path": "cross-region-producer.template.json", "packaging": "file" @@ -37,7 +37,7 @@ "destinations": { "current_account-us-east-1": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", - "objectKey": "a645bb0b063dc77d60a1af0c1e427999161c49fe9008543153cb48fed642a943.json", + "objectKey": "f93ad4a2004b446276ef3fac1ada613b58a45257e6bfd66f18ab8119232f6131.json", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.template.json index 89ec44a959bd4..0bc0cfef373a0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/cross-region-producer.template.json @@ -98,6 +98,18 @@ ":parameter/cdk/exports/*" ] ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:ssm:us-west-2:", + { + "Ref": "AWS::AccountId" + }, + ":parameter/cdk/exports/*" + ] + ] } ], "Action": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.assets.json index c5bd3a3dee7f5..65386b78ec7b6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.assets.json @@ -14,7 +14,7 @@ } } }, - "a916bc3a5655b0f9f8fc2ca727c849da1870288a890fc7a778f18859c60dc3b2": { + "abfdad43ef2795ab9e253a1b3cb3bfd72c1d00fa011b42ce99ffdff17b83c947": { "source": { "path": "crossregionreferencesDefaultTestDeployAssertAB7415FD.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "a916bc3a5655b0f9f8fc2ca727c849da1870288a890fc7a778f18859c60dc3b2.json", + "objectKey": "abfdad43ef2795ab9e253a1b3cb3bfd72c1d00fa011b42ce99ffdff17b83c947.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.template.json index 5f3d89d217be8..d188d7934d654 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/crossregionreferencesDefaultTestDeployAssertAB7415FD.template.json @@ -15,7 +15,7 @@ "StackName": "cross-region-producer" }, "flattenResponse": "false", - "salt": "1682378118042" + "salt": "1682942114901" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -118,7 +118,7 @@ "StackName": "cross-region-producer" }, "flattenResponse": "false", - "salt": "1682378118042" + "salt": "1682942114901" }, "DependsOn": [ "AwsApiCallCloudFormationdeleteStack" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/manifest.json index b859e07e1597c..866326ff7e4d6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.js.snapshot/manifest.json @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/a645bb0b063dc77d60a1af0c1e427999161c49fe9008543153cb48fed642a943.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/f93ad4a2004b446276ef3fac1ada613b58a45257e6bfd66f18ab8119232f6131.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -328,7 +328,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a916bc3a5655b0f9f8fc2ca727c849da1870288a890fc7a778f18859c60dc3b2.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/abfdad43ef2795ab9e253a1b3cb3bfd72c1d00fa011b42ce99ffdff17b83c947.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/aws-cdk-lib/core/lib/custom-resource-provider/cross-region-export-providers/export-writer-provider.ts b/packages/aws-cdk-lib/core/lib/custom-resource-provider/cross-region-export-providers/export-writer-provider.ts index d881fabf80db2..d46bc5046770c 100644 --- a/packages/aws-cdk-lib/core/lib/custom-resource-provider/cross-region-export-providers/export-writer-provider.ts +++ b/packages/aws-cdk-lib/core/lib/custom-resource-provider/cross-region-export-providers/export-writer-provider.ts @@ -9,8 +9,8 @@ import { Intrinsic } from '../../private/intrinsic'; import { makeUniqueId } from '../../private/uniqueid'; import { Reference } from '../../reference'; import { Stack } from '../../stack'; -import { builtInCustomResourceProviderNodeRuntime, CustomResourceProvider } from '../custom-resource-provider'; import { Token } from '../../token'; +import { builtInCustomResourceProviderNodeRuntime, CustomResourceProvider, CustomResourceProviderProps } from '../custom-resource-provider'; /** * Properties for an ExportReader @@ -24,6 +24,43 @@ export interface ExportWriterProps { readonly region?: string; } +/** + * Create our own CustomResourceProvider so that we can add a single policy + * with a list of ARNs instead of having to create a separate policy statement per ARN. + */ +class CRProvider extends CustomResourceProvider { + public static getOrCreateProvider(scope: Construct, uniqueid: string, props: CustomResourceProviderProps): CRProvider { + const id = `${uniqueid}CustomResourceProvider`; + const stack = Stack.of(scope); + const provider = stack.node.tryFindChild(id) as CRProvider + ?? new CRProvider(stack, id, props); + + return provider; + } + + private readonly resourceArns = new Set(); + constructor(scope: Construct, id: string, props: CustomResourceProviderProps) { + super(scope, id, props); + this.addToRolePolicy({ + Effect: 'Allow', + Resource: Lazy.list({ produce: () => Array.from(this.resourceArns) }), + Action: [ + 'ssm:DeleteParameters', + 'ssm:ListTagsForResource', + 'ssm:GetParameters', + 'ssm:PutParameter', + ], + }); + } + + /** + * Add a resource ARN to the existing policy statement + */ + public addResourceArn(arn: string): void { + this.resourceArns.add(arn); + } +} + /** * Creates a custom resource that will return a list of stack exports from a given * AWS region. The export can then be referenced by the export name. @@ -55,34 +92,20 @@ export class ExportWriter extends Construct { }); } private readonly _references: CrossRegionExports = {}; - private readonly provider: CustomResourceProvider; - private readonly resourceArns = new Set; + private readonly provider: CRProvider; constructor(scope: Construct, id: string, props: ExportWriterProps) { super(scope, id); const stack = Stack.of(this); const region = props.region ?? stack.region; - this.addRegionToPolicy(region); const resourceType = 'Custom::CrossRegionExportWriter'; - this.provider = CustomResourceProvider.getOrCreateProvider(this, resourceType, { + this.provider = CRProvider.getOrCreateProvider(this, resourceType, { codeDirectory: path.join(__dirname, 'cross-region-ssm-writer-handler'), runtime: builtInCustomResourceProviderNodeRuntime(this), - policyStatements: [{ - Effect: 'Allow', - Resource: Lazy.list({ - produce: () => [ - ...Array.from(this.resourceArns), - ], - }), - Action: [ - 'ssm:DeleteParameters', - 'ssm:ListTagsForResource', - 'ssm:GetParameters', - 'ssm:PutParameter', - ], - }], }); + this.addRegionToPolicy(region); + const properties: ExportWriterCRProps = { region: region, exports: Lazy.any({ produce: () => this._references }), @@ -126,14 +149,12 @@ export class ExportWriter extends Construct { */ private addRegionToPolicy(region: string): void { if (!Token.isUnresolved(region)) { - this.resourceArns.add( - Stack.of(this).formatArn({ - service: 'ssm', - resource: 'parameter', - region, - resourceName: `${SSM_EXPORT_PATH_PREFIX}*`, - }), - ); + this.provider.addResourceArn(Stack.of(this).formatArn({ + service: 'ssm', + resource: 'parameter', + region, + resourceName: `${SSM_EXPORT_PATH_PREFIX}*`, + })); } } diff --git a/packages/aws-cdk-lib/core/lib/private/refs.ts b/packages/aws-cdk-lib/core/lib/private/refs.ts index cdc62723e146a..0da1eb3f22c42 100644 --- a/packages/aws-cdk-lib/core/lib/private/refs.ts +++ b/packages/aws-cdk-lib/core/lib/private/refs.ts @@ -2,12 +2,12 @@ // CROSS REFERENCES // ---------------------------------------------------- -import * as cxapi from '../../../cx-api'; import { IConstruct } from 'constructs'; import { CfnReference } from './cfn-reference'; import { Intrinsic } from './intrinsic'; import { findTokens } from './resolve'; import { makeUniqueId } from './uniqueid'; +import * as cxapi from '../../../cx-api'; import { CfnElement } from '../cfn-element'; import { CfnOutput } from '../cfn-output'; import { CfnParameter } from '../cfn-parameter'; @@ -233,11 +233,11 @@ function createCrossRegionImportValue(reference: Reference, importStack: Stack): // get or create the export writer const writerConstructName = makeUniqueId(['ExportsWriter', importStack.region]); - const exportReader = ExportWriter.getOrCreate(exportingStack, writerConstructName, { + const exportWriter = ExportWriter.getOrCreate(exportingStack, writerConstructName, { region: importStack.region, }); - const exported = exportReader.exportValue(exportName, reference, importStack); + const exported = exportWriter.exportValue(exportName, reference, importStack); if (importStack.nestedStackParent) { return createNestedStackParameter(importStack, (exported as CfnReference), exported); } diff --git a/packages/aws-cdk-lib/core/test/custom-resource-provider/export-writer-provider.test.ts b/packages/aws-cdk-lib/core/test/custom-resource-provider/export-writer-provider.test.ts index a338da6f30cb3..55b51fa98eb4d 100644 --- a/packages/aws-cdk-lib/core/test/custom-resource-provider/export-writer-provider.test.ts +++ b/packages/aws-cdk-lib/core/test/custom-resource-provider/export-writer-provider.test.ts @@ -34,104 +34,104 @@ describe('export writer provider', () => { expect(cfn).toEqual({ Mappings: { DefaultCrNodeVersionMap: { - "af-south-1": { - "value": "nodejs16.x", + 'af-south-1': { + value: 'nodejs16.x', }, - "ap-east-1": { - "value": "nodejs16.x", + 'ap-east-1': { + value: 'nodejs16.x', }, - "ap-northeast-1": { - "value": "nodejs16.x", + 'ap-northeast-1': { + value: 'nodejs16.x', }, - "ap-northeast-2": { - "value": "nodejs16.x", + 'ap-northeast-2': { + value: 'nodejs16.x', }, - "ap-northeast-3": { - "value": "nodejs16.x", + 'ap-northeast-3': { + value: 'nodejs16.x', }, - "ap-south-1": { - "value": "nodejs16.x", + 'ap-south-1': { + value: 'nodejs16.x', }, - "ap-south-2": { - "value": "nodejs16.x", + 'ap-south-2': { + value: 'nodejs16.x', }, - "ap-southeast-1": { - "value": "nodejs16.x", + 'ap-southeast-1': { + value: 'nodejs16.x', }, - "ap-southeast-2": { - "value": "nodejs16.x", + 'ap-southeast-2': { + value: 'nodejs16.x', }, - "ap-southeast-3": { - "value": "nodejs16.x", + 'ap-southeast-3': { + value: 'nodejs16.x', }, - "ca-central-1": { - "value": "nodejs16.x", + 'ca-central-1': { + value: 'nodejs16.x', }, - "cn-north-1": { - "value": "nodejs16.x", + 'cn-north-1': { + value: 'nodejs16.x', }, - "cn-northwest-1": { - "value": "nodejs16.x", + 'cn-northwest-1': { + value: 'nodejs16.x', }, - "eu-central-1": { - "value": "nodejs16.x", + 'eu-central-1': { + value: 'nodejs16.x', }, - "eu-central-2": { - "value": "nodejs16.x", + 'eu-central-2': { + value: 'nodejs16.x', }, - "eu-north-1": { - "value": "nodejs16.x", + 'eu-north-1': { + value: 'nodejs16.x', }, - "eu-south-1": { - "value": "nodejs16.x", + 'eu-south-1': { + value: 'nodejs16.x', }, - "eu-south-2": { - "value": "nodejs16.x", + 'eu-south-2': { + value: 'nodejs16.x', }, - "eu-west-1": { - "value": "nodejs16.x", + 'eu-west-1': { + value: 'nodejs16.x', }, - "eu-west-2": { - "value": "nodejs16.x", + 'eu-west-2': { + value: 'nodejs16.x', }, - "eu-west-3": { - "value": "nodejs16.x", + 'eu-west-3': { + value: 'nodejs16.x', }, - "me-central-1": { - "value": "nodejs16.x", + 'me-central-1': { + value: 'nodejs16.x', }, - "me-south-1": { - "value": "nodejs16.x", + 'me-south-1': { + value: 'nodejs16.x', }, - "sa-east-1": { - "value": "nodejs16.x", + 'sa-east-1': { + value: 'nodejs16.x', }, - "us-east-1": { - "value": "nodejs16.x", + 'us-east-1': { + value: 'nodejs16.x', }, - "us-east-2": { - "value": "nodejs16.x", + 'us-east-2': { + value: 'nodejs16.x', }, - "us-gov-east-1": { - "value": "nodejs16.x", + 'us-gov-east-1': { + value: 'nodejs16.x', }, - "us-gov-west-1": { - "value": "nodejs16.x", + 'us-gov-west-1': { + value: 'nodejs16.x', }, - "us-iso-east-1": { - "value": "nodejs14.x", + 'us-iso-east-1': { + value: 'nodejs14.x', }, - "us-iso-west-1": { - "value": "nodejs14.x", + 'us-iso-west-1': { + value: 'nodejs14.x', }, - "us-isob-east-1": { - "value": "nodejs14.x", + 'us-isob-east-1': { + value: 'nodejs14.x', }, - "us-west-1": { - "value": "nodejs16.x", + 'us-west-1': { + value: 'nodejs16.x', }, - "us-west-2": { - "value": "nodejs16.x", + 'us-west-2': { + value: 'nodejs16.x', }, }, }, @@ -249,104 +249,104 @@ describe('export writer provider', () => { expect(stack2Cfn).toEqual({ Mappings: { DefaultCrNodeVersionMap: { - "af-south-1": { - "value": "nodejs16.x", + 'af-south-1': { + value: 'nodejs16.x', }, - "ap-east-1": { - "value": "nodejs16.x", + 'ap-east-1': { + value: 'nodejs16.x', }, - "ap-northeast-1": { - "value": "nodejs16.x", + 'ap-northeast-1': { + value: 'nodejs16.x', }, - "ap-northeast-2": { - "value": "nodejs16.x", + 'ap-northeast-2': { + value: 'nodejs16.x', }, - "ap-northeast-3": { - "value": "nodejs16.x", + 'ap-northeast-3': { + value: 'nodejs16.x', }, - "ap-south-1": { - "value": "nodejs16.x", + 'ap-south-1': { + value: 'nodejs16.x', }, - "ap-south-2": { - "value": "nodejs16.x", + 'ap-south-2': { + value: 'nodejs16.x', }, - "ap-southeast-1": { - "value": "nodejs16.x", + 'ap-southeast-1': { + value: 'nodejs16.x', }, - "ap-southeast-2": { - "value": "nodejs16.x", + 'ap-southeast-2': { + value: 'nodejs16.x', }, - "ap-southeast-3": { - "value": "nodejs16.x", + 'ap-southeast-3': { + value: 'nodejs16.x', }, - "ca-central-1": { - "value": "nodejs16.x", + 'ca-central-1': { + value: 'nodejs16.x', }, - "cn-north-1": { - "value": "nodejs16.x", + 'cn-north-1': { + value: 'nodejs16.x', }, - "cn-northwest-1": { - "value": "nodejs16.x", + 'cn-northwest-1': { + value: 'nodejs16.x', }, - "eu-central-1": { - "value": "nodejs16.x", + 'eu-central-1': { + value: 'nodejs16.x', }, - "eu-central-2": { - "value": "nodejs16.x", + 'eu-central-2': { + value: 'nodejs16.x', }, - "eu-north-1": { - "value": "nodejs16.x", + 'eu-north-1': { + value: 'nodejs16.x', }, - "eu-south-1": { - "value": "nodejs16.x", + 'eu-south-1': { + value: 'nodejs16.x', }, - "eu-south-2": { - "value": "nodejs16.x", + 'eu-south-2': { + value: 'nodejs16.x', }, - "eu-west-1": { - "value": "nodejs16.x", + 'eu-west-1': { + value: 'nodejs16.x', }, - "eu-west-2": { - "value": "nodejs16.x", + 'eu-west-2': { + value: 'nodejs16.x', }, - "eu-west-3": { - "value": "nodejs16.x", + 'eu-west-3': { + value: 'nodejs16.x', }, - "me-central-1": { - "value": "nodejs16.x", + 'me-central-1': { + value: 'nodejs16.x', }, - "me-south-1": { - "value": "nodejs16.x", + 'me-south-1': { + value: 'nodejs16.x', }, - "sa-east-1": { - "value": "nodejs16.x", + 'sa-east-1': { + value: 'nodejs16.x', }, - "us-east-1": { - "value": "nodejs16.x", + 'us-east-1': { + value: 'nodejs16.x', }, - "us-east-2": { - "value": "nodejs16.x", + 'us-east-2': { + value: 'nodejs16.x', }, - "us-gov-east-1": { - "value": "nodejs16.x", + 'us-gov-east-1': { + value: 'nodejs16.x', }, - "us-gov-west-1": { - "value": "nodejs16.x", + 'us-gov-west-1': { + value: 'nodejs16.x', }, - "us-iso-east-1": { - "value": "nodejs14.x", + 'us-iso-east-1': { + value: 'nodejs14.x', }, - "us-iso-west-1": { - "value": "nodejs14.x", + 'us-iso-west-1': { + value: 'nodejs14.x', }, - "us-isob-east-1": { - "value": "nodejs14.x", + 'us-isob-east-1': { + value: 'nodejs14.x', }, - "us-west-1": { - "value": "nodejs16.x", + 'us-west-1': { + value: 'nodejs16.x', }, - "us-west-2": { - "value": "nodejs16.x", + 'us-west-2': { + value: 'nodejs16.x', }, }, }, @@ -465,22 +465,30 @@ describe('export writer provider', () => { // GIVEN const app = new App(); const stack = new Stack(app, 'Stack1', { env: { region: 'producer-region' } }); - const stack2 = new Stack(app, 'Stack2', { env: { region: 'consumer-region1' } }); - const stack3 = new Stack(app, 'Stack3', { env: { region: 'consumer-region2' } }); + const stack2 = new Stack(app, 'Stack2', { env: { region: 'consumer-region1' }, crossRegionReferences: true }); + const stack3 = new Stack(app, 'Stack3', { env: { region: 'consumer-region2' }, crossRegionReferences: true }); + + // WHEN const resource = new CfnResource(stack, 'MyResource', { type: 'Custom::MyResource', }); - - // WHEN - const exportWriter = new ExportWriter(stack, 'ExportWriter', { - region: 'us-east-1', + new CfnResource(stack2, 'MyResource', { + type: 'Custom::MyResource', + properties: { + Prop: resource.getAtt('arn'), + }, + }); + new CfnResource(stack3, 'MyResource', { + type: 'Custom::MyResource', + properties: { + Prop: resource.getAtt('arn'), + }, }); - exportWriter.exportValue('MyResourceName', resource.getAtt('arn'), stack2); - exportWriter.exportValue('MyResourceName', resource.getAtt('arn'), stack3); + // THEN + app.synth(); const cfn = toCloudFormation(stack); - expect(cfn).toMatchObject({ Resources: { MyResource: { @@ -514,22 +522,6 @@ describe('export writer provider', () => { ], Effect: 'Allow', Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:us-east-1:', - { - Ref: 'AWS::AccountId', - }, - ':parameter/cdk/exports/*', - ], - ], - }, { 'Fn::Join': [ '', @@ -609,104 +601,104 @@ describe('export writer provider', () => { expect(cfn).toEqual({ Mappings: { DefaultCrNodeVersionMap: { - "af-south-1": { - "value": "nodejs16.x", + 'af-south-1': { + value: 'nodejs16.x', }, - "ap-east-1": { - "value": "nodejs16.x", + 'ap-east-1': { + value: 'nodejs16.x', }, - "ap-northeast-1": { - "value": "nodejs16.x", + 'ap-northeast-1': { + value: 'nodejs16.x', }, - "ap-northeast-2": { - "value": "nodejs16.x", + 'ap-northeast-2': { + value: 'nodejs16.x', }, - "ap-northeast-3": { - "value": "nodejs16.x", + 'ap-northeast-3': { + value: 'nodejs16.x', }, - "ap-south-1": { - "value": "nodejs16.x", + 'ap-south-1': { + value: 'nodejs16.x', }, - "ap-south-2": { - "value": "nodejs16.x", + 'ap-south-2': { + value: 'nodejs16.x', }, - "ap-southeast-1": { - "value": "nodejs16.x", + 'ap-southeast-1': { + value: 'nodejs16.x', }, - "ap-southeast-2": { - "value": "nodejs16.x", + 'ap-southeast-2': { + value: 'nodejs16.x', }, - "ap-southeast-3": { - "value": "nodejs16.x", + 'ap-southeast-3': { + value: 'nodejs16.x', }, - "ca-central-1": { - "value": "nodejs16.x", + 'ca-central-1': { + value: 'nodejs16.x', }, - "cn-north-1": { - "value": "nodejs16.x", + 'cn-north-1': { + value: 'nodejs16.x', }, - "cn-northwest-1": { - "value": "nodejs16.x", + 'cn-northwest-1': { + value: 'nodejs16.x', }, - "eu-central-1": { - "value": "nodejs16.x", + 'eu-central-1': { + value: 'nodejs16.x', }, - "eu-central-2": { - "value": "nodejs16.x", + 'eu-central-2': { + value: 'nodejs16.x', }, - "eu-north-1": { - "value": "nodejs16.x", + 'eu-north-1': { + value: 'nodejs16.x', }, - "eu-south-1": { - "value": "nodejs16.x", + 'eu-south-1': { + value: 'nodejs16.x', }, - "eu-south-2": { - "value": "nodejs16.x", + 'eu-south-2': { + value: 'nodejs16.x', }, - "eu-west-1": { - "value": "nodejs16.x", + 'eu-west-1': { + value: 'nodejs16.x', }, - "eu-west-2": { - "value": "nodejs16.x", + 'eu-west-2': { + value: 'nodejs16.x', }, - "eu-west-3": { - "value": "nodejs16.x", + 'eu-west-3': { + value: 'nodejs16.x', }, - "me-central-1": { - "value": "nodejs16.x", + 'me-central-1': { + value: 'nodejs16.x', }, - "me-south-1": { - "value": "nodejs16.x", + 'me-south-1': { + value: 'nodejs16.x', }, - "sa-east-1": { - "value": "nodejs16.x", + 'sa-east-1': { + value: 'nodejs16.x', }, - "us-east-1": { - "value": "nodejs16.x", + 'us-east-1': { + value: 'nodejs16.x', }, - "us-east-2": { - "value": "nodejs16.x", + 'us-east-2': { + value: 'nodejs16.x', }, - "us-gov-east-1": { - "value": "nodejs16.x", + 'us-gov-east-1': { + value: 'nodejs16.x', }, - "us-gov-west-1": { - "value": "nodejs16.x", + 'us-gov-west-1': { + value: 'nodejs16.x', }, - "us-iso-east-1": { - "value": "nodejs14.x", + 'us-iso-east-1': { + value: 'nodejs14.x', }, - "us-iso-west-1": { - "value": "nodejs14.x", + 'us-iso-west-1': { + value: 'nodejs14.x', }, - "us-isob-east-1": { - "value": "nodejs14.x", + 'us-isob-east-1': { + value: 'nodejs14.x', }, - "us-west-1": { - "value": "nodejs16.x", + 'us-west-1': { + value: 'nodejs16.x', }, - "us-west-2": { - "value": "nodejs16.x", + 'us-west-2': { + value: 'nodejs16.x', }, }, }, @@ -825,104 +817,104 @@ describe('export writer provider', () => { expect(stack2Cfn).toEqual({ Mappings: { DefaultCrNodeVersionMap: { - "af-south-1": { - "value": "nodejs16.x", + 'af-south-1': { + value: 'nodejs16.x', }, - "ap-east-1": { - "value": "nodejs16.x", + 'ap-east-1': { + value: 'nodejs16.x', }, - "ap-northeast-1": { - "value": "nodejs16.x", + 'ap-northeast-1': { + value: 'nodejs16.x', }, - "ap-northeast-2": { - "value": "nodejs16.x", + 'ap-northeast-2': { + value: 'nodejs16.x', }, - "ap-northeast-3": { - "value": "nodejs16.x", + 'ap-northeast-3': { + value: 'nodejs16.x', }, - "ap-south-1": { - "value": "nodejs16.x", + 'ap-south-1': { + value: 'nodejs16.x', }, - "ap-south-2": { - "value": "nodejs16.x", + 'ap-south-2': { + value: 'nodejs16.x', }, - "ap-southeast-1": { - "value": "nodejs16.x", + 'ap-southeast-1': { + value: 'nodejs16.x', }, - "ap-southeast-2": { - "value": "nodejs16.x", + 'ap-southeast-2': { + value: 'nodejs16.x', }, - "ap-southeast-3": { - "value": "nodejs16.x", + 'ap-southeast-3': { + value: 'nodejs16.x', }, - "ca-central-1": { - "value": "nodejs16.x", + 'ca-central-1': { + value: 'nodejs16.x', }, - "cn-north-1": { - "value": "nodejs16.x", + 'cn-north-1': { + value: 'nodejs16.x', }, - "cn-northwest-1": { - "value": "nodejs16.x", + 'cn-northwest-1': { + value: 'nodejs16.x', }, - "eu-central-1": { - "value": "nodejs16.x", + 'eu-central-1': { + value: 'nodejs16.x', }, - "eu-central-2": { - "value": "nodejs16.x", + 'eu-central-2': { + value: 'nodejs16.x', }, - "eu-north-1": { - "value": "nodejs16.x", + 'eu-north-1': { + value: 'nodejs16.x', }, - "eu-south-1": { - "value": "nodejs16.x", + 'eu-south-1': { + value: 'nodejs16.x', }, - "eu-south-2": { - "value": "nodejs16.x", + 'eu-south-2': { + value: 'nodejs16.x', }, - "eu-west-1": { - "value": "nodejs16.x", + 'eu-west-1': { + value: 'nodejs16.x', }, - "eu-west-2": { - "value": "nodejs16.x", + 'eu-west-2': { + value: 'nodejs16.x', }, - "eu-west-3": { - "value": "nodejs16.x", + 'eu-west-3': { + value: 'nodejs16.x', }, - "me-central-1": { - "value": "nodejs16.x", + 'me-central-1': { + value: 'nodejs16.x', }, - "me-south-1": { - "value": "nodejs16.x", + 'me-south-1': { + value: 'nodejs16.x', }, - "sa-east-1": { - "value": "nodejs16.x", + 'sa-east-1': { + value: 'nodejs16.x', }, - "us-east-1": { - "value": "nodejs16.x", + 'us-east-1': { + value: 'nodejs16.x', }, - "us-east-2": { - "value": "nodejs16.x", + 'us-east-2': { + value: 'nodejs16.x', }, - "us-gov-east-1": { - "value": "nodejs16.x", + 'us-gov-east-1': { + value: 'nodejs16.x', }, - "us-gov-west-1": { - "value": "nodejs16.x", + 'us-gov-west-1': { + value: 'nodejs16.x', }, - "us-iso-east-1": { - "value": "nodejs14.x", + 'us-iso-east-1': { + value: 'nodejs14.x', }, - "us-iso-west-1": { - "value": "nodejs14.x", + 'us-iso-west-1': { + value: 'nodejs14.x', }, - "us-isob-east-1": { - "value": "nodejs14.x", + 'us-isob-east-1': { + value: 'nodejs14.x', }, - "us-west-1": { - "value": "nodejs16.x", + 'us-west-1': { + value: 'nodejs16.x', }, - "us-west-2": { - "value": "nodejs16.x", + 'us-west-2': { + value: 'nodejs16.x', }, }, },