Skip to content

Commit 17fc967

Browse files
authored
fix(apigateway): cross-stack lambda integration causes a cyclic reference (#4010)
1. Token resolution of Deployment construct must not resolve the entire stack, specifically during the prepare phase. stack.resolve() works only after the CDK app has been fully prepared. During the 'prepare' phase, token resolution should instead resolve the token partially and within the local context. 2. Scope the lambda.CfnPermission construct closer to the consumer of the permission rather than being closer to the lambda function. For instance, when a lambda function is being consumed by an APIGateway RestApi Method as a cross-stack reference, placing the lambda.CfnPermission construct closer to the RestApi Method reduces the possibility of cyclic dependencies. fixes #3705, #3000
1 parent dbf0134 commit 17fc967

File tree

13 files changed

+729
-408
lines changed

13 files changed

+729
-408
lines changed

packages/@aws-cdk/aws-apigateway/lib/deployment.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Construct, Lazy, RemovalPolicy, Resource, Stack } from '@aws-cdk/core';
1+
import { Construct, DefaultTokenResolver, Lazy, RemovalPolicy, Resource, Stack, StringConcat, Tokenization } from '@aws-cdk/core';
22
import crypto = require('crypto');
33
import { CfnDeployment, CfnDeploymentProps } from './apigateway.generated';
44
import { IRestApi } from './restapi';
@@ -121,19 +121,22 @@ class LatestDeploymentResource extends CfnDeployment {
121121
* add via `addToLogicalId`.
122122
*/
123123
protected prepare() {
124-
const stack = Stack.of(this);
125-
126124
// if hash components were added to the deployment, we use them to calculate
127125
// a logical ID for the deployment resource.
128126
if (this.hashComponents.length > 0) {
129127
const md5 = crypto.createHash('md5');
130128
this.hashComponents
131-
.map(c => stack.resolve(c))
129+
.map(c => {
130+
return Tokenization.resolve(c, {
131+
scope: this,
132+
resolver: new DefaultTokenResolver(new StringConcat()),
133+
preparing: true,
134+
});
135+
})
132136
.forEach(c => md5.update(JSON.stringify(c)));
133137

134138
this.overrideLogicalId(this.originalLogicalId + md5.digest("hex"));
135139
}
136-
137140
super.prepare();
138141
}
139142
}

packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@ export class LambdaIntegration extends AwsIntegration {
5959

6060
this.handler.addPermission(`ApiPermission.${desc}`, {
6161
principal,
62+
scope: method,
6263
sourceArn: method.methodArn,
6364
});
6465

6566
// add permission to invoke from the console
6667
if (this.enableTest) {
6768
this.handler.addPermission(`ApiPermission.Test.${desc}`, {
6869
principal,
69-
sourceArn: method.testMethodArn
70+
scope: method,
71+
sourceArn: method.testMethodArn,
7072
});
7173
}
7274
}

packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.expected.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"BooksHandlerServiceRole5B6A8847"
5151
]
5252
},
53-
"BooksHandlerApiPermissionrestapibooksexamplebooksapi4538F335GETbooks727D645E": {
53+
"booksapibooksGETApiPermissionrestapibooksexamplebooksapi4538F335GETbooks391776D8": {
5454
"Type": "AWS::Lambda::Permission",
5555
"Properties": {
5656
"Action": "lambda:InvokeFunction",
@@ -91,7 +91,7 @@
9191
}
9292
}
9393
},
94-
"BooksHandlerApiPermissionTestrestapibooksexamplebooksapi4538F335GETbooksCC375808": {
94+
"booksapibooksGETApiPermissionTestrestapibooksexamplebooksapi4538F335GETbooks01FB3D1B": {
9595
"Type": "AWS::Lambda::Permission",
9696
"Properties": {
9797
"Action": "lambda:InvokeFunction",
@@ -128,7 +128,7 @@
128128
}
129129
}
130130
},
131-
"BooksHandlerApiPermissionrestapibooksexamplebooksapi4538F335POSTbooksFDED8A87": {
131+
"booksapibooksPOSTApiPermissionrestapibooksexamplebooksapi4538F335POSTbooksDFEC643F": {
132132
"Type": "AWS::Lambda::Permission",
133133
"Properties": {
134134
"Action": "lambda:InvokeFunction",
@@ -169,7 +169,7 @@
169169
}
170170
}
171171
},
172-
"BooksHandlerApiPermissionTestrestapibooksexamplebooksapi4538F335POSTbooks4667899F": {
172+
"booksapibooksPOSTApiPermissionTestrestapibooksexamplebooksapi4538F335POSTbooks1C6D24C8": {
173173
"Type": "AWS::Lambda::Permission",
174174
"Properties": {
175175
"Action": "lambda:InvokeFunction",
@@ -256,7 +256,7 @@
256256
"BookHandlerServiceRole894768AD"
257257
]
258258
},
259-
"BookHandlerApiPermissionrestapibooksexamplebooksapi4538F335GETbooksbookidA10D3CE2": {
259+
"booksapibooksbookidGETApiPermissionrestapibooksexamplebooksapi4538F335GETbooksbookidBB91DFBD": {
260260
"Type": "AWS::Lambda::Permission",
261261
"Properties": {
262262
"Action": "lambda:InvokeFunction",
@@ -297,7 +297,7 @@
297297
}
298298
}
299299
},
300-
"BookHandlerApiPermissionTestrestapibooksexamplebooksapi4538F335GETbooksbookidAB5191B6": {
300+
"booksapibooksbookidGETApiPermissionTestrestapibooksexamplebooksapi4538F335GETbooksbookidA0230B08": {
301301
"Type": "AWS::Lambda::Permission",
302302
"Properties": {
303303
"Action": "lambda:InvokeFunction",
@@ -334,7 +334,7 @@
334334
}
335335
}
336336
},
337-
"BookHandlerApiPermissionrestapibooksexamplebooksapi4538F335DELETEbooksbookidB3A85313": {
337+
"booksapibooksbookidDELETEApiPermissionrestapibooksexamplebooksapi4538F335DELETEbooksbookid76C1C947": {
338338
"Type": "AWS::Lambda::Permission",
339339
"Properties": {
340340
"Action": "lambda:InvokeFunction",
@@ -375,7 +375,7 @@
375375
}
376376
}
377377
},
378-
"BookHandlerApiPermissionTestrestapibooksexamplebooksapi4538F335DELETEbooksbookid9308C830": {
378+
"booksapibooksbookidDELETEApiPermissionTestrestapibooksexamplebooksapi4538F335DELETEbooksbookid09D6CB8A": {
379379
"Type": "AWS::Lambda::Permission",
380380
"Properties": {
381381
"Action": "lambda:InvokeFunction",
@@ -462,7 +462,7 @@
462462
"HelloServiceRole1E55EA16"
463463
]
464464
},
465-
"HelloApiPermissionrestapibooksexamplebooksapi4538F335ANYE385693C": {
465+
"booksapiANYApiPermissionrestapibooksexamplebooksapi4538F335ANY73B3CDDC": {
466466
"Type": "AWS::Lambda::Permission",
467467
"Properties": {
468468
"Action": "lambda:InvokeFunction",
@@ -503,7 +503,7 @@
503503
}
504504
}
505505
},
506-
"HelloApiPermissionTestrestapibooksexamplebooksapi4538F335ANY46B0DA7B": {
506+
"booksapiANYApiPermissionTestrestapibooksexamplebooksapi4538F335ANYB0D7D8AC": {
507507
"Type": "AWS::Lambda::Permission",
508508
"Properties": {
509509
"Action": "lambda:InvokeFunction",
@@ -546,7 +546,7 @@
546546
"Name": "books-api"
547547
}
548548
},
549-
"booksapiDeployment308B08F1c828b08824c062376eba921738884f85": {
549+
"booksapiDeployment308B08F1038c4647da4cb72c7574b891fb62b77f": {
550550
"Type": "AWS::ApiGateway::Deployment",
551551
"Properties": {
552552
"RestApiId": {
@@ -571,7 +571,7 @@
571571
"Ref": "booksapiE1885304"
572572
},
573573
"DeploymentId": {
574-
"Ref": "booksapiDeployment308B08F1c828b08824c062376eba921738884f85"
574+
"Ref": "booksapiDeployment308B08F1038c4647da4cb72c7574b891fb62b77f"
575575
},
576576
"StageName": "prod"
577577
}

packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Name": "my-api"
77
}
88
},
9-
"myapiDeployment92F2CB4919460d935da8177bcfbc418506e514ff": {
9+
"myapiDeployment92F2CB49a38a6824a90d7d4e6cc3a7f11357e163": {
1010
"Type": "AWS::ApiGateway::Deployment",
1111
"Properties": {
1212
"RestApiId": {
@@ -38,7 +38,7 @@
3838
"CacheClusterEnabled": true,
3939
"CacheClusterSize": "0.5",
4040
"DeploymentId": {
41-
"Ref": "myapiDeployment92F2CB4919460d935da8177bcfbc418506e514ff"
41+
"Ref": "myapiDeployment92F2CB49a38a6824a90d7d4e6cc3a7f11357e163"
4242
},
4343
"Description": "beta stage",
4444
"MethodSettings": [
@@ -430,7 +430,7 @@
430430
"MyHandlerServiceRoleFFA06653"
431431
]
432432
},
433-
"MyHandlerApiPermissiontestapigatewayrestapimyapi1AE401C4GETv1toys00F704BC": {
433+
"myapiv1toysGETApiPermissiontestapigatewayrestapimyapi1AE401C4GETv1toysA829D1CC": {
434434
"Type": "AWS::Lambda::Permission",
435435
"Properties": {
436436
"Action": "lambda:InvokeFunction",
@@ -471,7 +471,7 @@
471471
}
472472
}
473473
},
474-
"MyHandlerApiPermissionTesttestapigatewayrestapimyapi1AE401C4GETv1toysDBCC8082": {
474+
"myapiv1toysGETApiPermissionTesttestapigatewayrestapimyapi1AE401C4GETv1toys9E0BAE9F": {
475475
"Type": "AWS::Lambda::Permission",
476476
"Properties": {
477477
"Action": "lambda:InvokeFunction",
@@ -508,7 +508,7 @@
508508
}
509509
}
510510
},
511-
"MyHandlerApiPermissiontestapigatewayrestapimyapi1AE401C4GETv1books96EB3DB8": {
511+
"myapiv1booksGETApiPermissiontestapigatewayrestapimyapi1AE401C4GETv1books484ACD3F": {
512512
"Type": "AWS::Lambda::Permission",
513513
"Properties": {
514514
"Action": "lambda:InvokeFunction",
@@ -549,7 +549,7 @@
549549
}
550550
}
551551
},
552-
"MyHandlerApiPermissionTesttestapigatewayrestapimyapi1AE401C4GETv1books906B3BB6": {
552+
"myapiv1booksGETApiPermissionTesttestapigatewayrestapimyapi1AE401C4GETv1booksE255E31A": {
553553
"Type": "AWS::Lambda::Permission",
554554
"Properties": {
555555
"Action": "lambda:InvokeFunction",
@@ -586,7 +586,7 @@
586586
}
587587
}
588588
},
589-
"MyHandlerApiPermissiontestapigatewayrestapimyapi1AE401C4POSTv1booksA48C273B": {
589+
"myapiv1booksPOSTApiPermissiontestapigatewayrestapimyapi1AE401C4POSTv1books2B1BC62B": {
590590
"Type": "AWS::Lambda::Permission",
591591
"Properties": {
592592
"Action": "lambda:InvokeFunction",
@@ -627,7 +627,7 @@
627627
}
628628
}
629629
},
630-
"MyHandlerApiPermissionTesttestapigatewayrestapimyapi1AE401C4POSTv1booksA566985D": {
630+
"myapiv1booksPOSTApiPermissionTesttestapigatewayrestapimyapi1AE401C4POSTv1books816A6B37": {
631631
"Type": "AWS::Lambda::Permission",
632632
"Properties": {
633633
"Action": "lambda:InvokeFunction",

0 commit comments

Comments
 (0)