From 8e2325cfb7dc5377755b561532b6c81caebc688f Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Tue, 6 Apr 2021 14:52:09 +0200 Subject: [PATCH] fix(cloudfront): cannot use same EdgeFunction in multiple stacks (#13790) Using the same `EdgeFunction` in multiple stacks correctly created multiple stacks in `us-east-1` but with the same SSM parameter name. As a consquence, only one stack could be deployed. Fix it by including the stack unique address in the SSM parameter name. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/experimental/edge-function.ts | 14 ++++----- .../test/experimental/edge-function.test.ts | 31 ++++++++++++++++--- ...ribution-lambda-cross-region.expected.json | 10 +++--- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index b12a56fe67e80..ab8d94e79baa1 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -148,8 +148,11 @@ export class EdgeFunction extends Resource implements lambda.IVersion { /** Create a support stack and function in us-east-1, and a SSM reader in-region */ private createCrossRegionFunction(id: string, props: EdgeFunctionProps): FunctionConfig { - const parameterNamePrefix = 'EdgeFunctionArn'; - const parameterName = `${parameterNamePrefix}${id}`; + const parameterNamePrefix = '/cdk/EdgeFunctionArn'; + if (Token.isUnresolved(this.env.region)) { + throw new Error('stacks which use EdgeFunctions must have an explicitly set region'); + } + const parameterName = `${parameterNamePrefix}/${this.env.region}/${this.node.path}`; const functionStack = this.edgeStack(props.stackId); const edgeFunction = new lambda.Function(functionStack, id, props); @@ -174,7 +177,8 @@ export class EdgeFunction extends Resource implements lambda.IVersion { service: 'ssm', region: EdgeFunction.EDGE_REGION, resource: 'parameter', - resourceName: parameterNamePrefix + '*', + resourceName: parameterNamePrefix + '/*', + sep: '', }); const resourceType = 'Custom::CrossRegionStringParameterReader'; @@ -206,10 +210,6 @@ export class EdgeFunction extends Resource implements lambda.IVersion { if (!stage) { throw new Error('stacks which use EdgeFunctions must be part of a CDK app or stage'); } - const region = this.env.region; - if (Token.isUnresolved(region)) { - throw new Error('stacks which use EdgeFunctions must have an explicitly set region'); - } const edgeStackId = stackId ?? `edge-lambda-stack-${this.stack.node.addr}`; let edgeStack = stage.node.tryFindChild(edgeStackId) as Stack; diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 55b0c2f4aeaac..36edf19a39056 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -39,7 +39,7 @@ describe('stacks', () => { Statement: [{ Effect: 'Allow', Resource: { - 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:us-east-1:111111111111:parameter/EdgeFunctionArn*']], + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:us-east-1:111111111111:parameter/cdk/EdgeFunctionArn/*']], }, Action: ['ssm:GetParameter'], }], @@ -57,7 +57,7 @@ describe('stacks', () => { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, Region: 'us-east-1', - ParameterName: 'EdgeFunctionArnMyFn', + ParameterName: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', }); }); @@ -98,7 +98,7 @@ describe('stacks', () => { expect(fnStack).toHaveResource('AWS::SSM::Parameter', { Type: 'String', Value: { Ref: 'MyFnCurrentVersion309B29FC29686ce94039b6e08d1645be854b3ac9' }, - Name: 'EdgeFunctionArnMyFn', + Name: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', }); }); @@ -201,7 +201,30 @@ describe('stacks', () => { 'Fn::GetAtt': ['CustomCrossRegionStringParameterReaderCustomResourceProviderHandler65B5F33A', 'Arn'], }, Region: 'us-east-1', - ParameterName: 'EdgeFunctionArnMyFn', + ParameterName: '/cdk/EdgeFunctionArn/testregion/Stage/Stack/MyFn', + }); + }); + + test('a single EdgeFunction used in multiple stacks creates mutiple stacks in us-east-1', () => { + const firstStack = new cdk.Stack(app, 'FirstStack', { + env: { account: '111111111111', region: 'testregion' }, + }); + const secondStack = new cdk.Stack(app, 'SecondStack', { + env: { account: '111111111111', region: 'testregion' }, + }); + new cloudfront.experimental.EdgeFunction(firstStack, 'MyFn', defaultEdgeFunctionProps()); + new cloudfront.experimental.EdgeFunction(secondStack, 'MyFn', defaultEdgeFunctionProps()); + + // Two stacks in us-east-1 + const firstFnStack = app.node.findChild(`edge-lambda-stack-${firstStack.node.addr}`) as cdk.Stack; + const secondFnStack = app.node.findChild(`edge-lambda-stack-${secondStack.node.addr}`) as cdk.Stack; + + // Two SSM parameters + expect(firstFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Name: '/cdk/EdgeFunctionArn/testregion/FirstStack/MyFn', + }); + expect(secondFnStack).toHaveResourceLike('AWS::SSM::Parameter', { + Name: '/cdk/EdgeFunctionArn/testregion/SecondStack/MyFn', }); }); }); diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json index c251765b20980..6da7e8717d61f 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json @@ -11,7 +11,7 @@ ] }, "Region": "us-east-1", - "ParameterName": "EdgeFunctionArnLambda", + "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda", "RefreshToken": "4412ddb0ae449da20173ca211c51fddc" }, "UpdateReplacePolicy": "Delete", @@ -57,7 +57,7 @@ { "Ref": "AWS::AccountId" }, - ":parameter/EdgeFunctionArn*" + ":parameter/cdk/EdgeFunctionArn/*" ] ] }, @@ -137,7 +137,7 @@ ] }, "Region": "us-east-1", - "ParameterName": "EdgeFunctionArnLambda2", + "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda2", "RefreshToken": "8f81ceb404ac454f09648e62822d9ca9" }, "UpdateReplacePolicy": "Delete", @@ -278,7 +278,7 @@ "Value": { "Ref": "LambdaCurrentVersionDF706F6A97fb843e9bd06fcd2bb15eeace80e13e" }, - "Name": "EdgeFunctionArnLambda" + "Name": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda" } }, "LambdaAliaslive79C8A712": { @@ -372,7 +372,7 @@ "Value": { "Ref": "Lambda2CurrentVersion72012B74b9eef8becb98501bc795baca3c6169c4" }, - "Name": "EdgeFunctionArnLambda2" + "Name": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda2" } }, "Lambda2Aliaslive77F6085F": {