Skip to content

Commit d06b27f

Browse files
authored
fix(lambda): support Lambda's new Invoke with Qualifier authorization strategy (#19318)
‼️ Lambda is changing their authorization strategy, which means that some behavior that was previously valid now results in `access-denied` errors. Under the new behavior, customer lambda invocations will fail if the CDK generates a policy with an unqualified ARN as the resource, and the customer invokes lambda with the unqualified ARN and the `Qualifier` request parameter. Example of an affected setup: ``` Statement: { Effect: "Allow", Action: "lambda:InvokeFunction", Resource: "arn:aws:lambda:...:function:MyFunction", } API Call: lambda.Invoke({ FunctionName: "MyFunction", Qualifier: "1234", }) ``` This `Invoke` call *used* to succeed, but under the new authorization strategy it will fail. The required statement to make the call succeed would be (note the qualified ARN): ``` { Effect: "Allow", Action: "lambda:InvokeFunction", Resource: "arn:aws:lambda:...:function:MyFunction:1234", } ``` This PR aims to align the CDK with the new authorization strategy. The PR introduces changes to the `grantInvoke()` api on a lambda function. Now, when calling `grantInvoke()` on a lambda function, `[ARN, ARN:*]` is used in the identity policy, so that identities that are granted permission to invoke the Function may also invoke all of its Versions and Aliases. When calling `grantInvoke()` on a lambda function Version or Alias, the generated identity policy will remain the same, and only include `ARN:<version/alias>` in the policy. This is part of #19273 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 3c9ea5f commit d06b27f

File tree

39 files changed

+862
-267
lines changed

39 files changed

+862
-267
lines changed

packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json

+22-6
Original file line numberDiff line numberDiff line change
@@ -1051,12 +1051,28 @@
10511051
{
10521052
"Action": "lambda:InvokeFunction",
10531053
"Effect": "Allow",
1054-
"Resource": {
1055-
"Fn::GetAtt": [
1056-
"nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99",
1057-
"Arn"
1058-
]
1059-
}
1054+
"Resource": [
1055+
{
1056+
"Fn::GetAtt": [
1057+
"nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99",
1058+
"Arn"
1059+
]
1060+
},
1061+
{
1062+
"Fn::Join": [
1063+
"",
1064+
[
1065+
{
1066+
"Fn::GetAtt": [
1067+
"nameserviceTaskRecordManagerCleanupResourceProviderHandler08068F99",
1068+
"Arn"
1069+
]
1070+
},
1071+
":*"
1072+
]
1073+
]
1074+
}
1075+
]
10601076
}
10611077
],
10621078
"Version": "2012-10-17"

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer {
105105
this.role.attachInlinePolicy(new iam.Policy(this, 'authorizerInvokePolicy', {
106106
statements: [
107107
new iam.PolicyStatement({
108-
resources: [this.handler.functionArn],
108+
resources: this.handler.resourceArnsForGrantInvoke,
109109
actions: ['lambda:InvokeFunction'],
110110
}),
111111
],

packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json

+22-6
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,28 @@
176176
{
177177
"Action": "lambda:InvokeFunction",
178178
"Effect": "Allow",
179-
"Resource": {
180-
"Fn::GetAtt": [
181-
"MyAuthorizerFunction70F1223E",
182-
"Arn"
183-
]
184-
}
179+
"Resource": [
180+
{
181+
"Fn::GetAtt": [
182+
"MyAuthorizerFunction70F1223E",
183+
"Arn"
184+
]
185+
},
186+
{
187+
"Fn::Join": [
188+
"",
189+
[
190+
{
191+
"Fn::GetAtt": [
192+
"MyAuthorizerFunction70F1223E",
193+
"Arn"
194+
]
195+
},
196+
":*"
197+
]
198+
]
199+
}
200+
]
185201
}
186202
],
187203
"Version": "2012-10-17"

packages/@aws-cdk/aws-apigateway/test/authorizers/lambda.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ describe('lambda authorizer', () => {
393393
PolicyDocument: {
394394
Statement: [
395395
{
396-
Resource: stack.resolve(func.functionArn),
396+
Resource: stack.resolve(func.resourceArnsForGrantInvoke),
397397
Action: 'lambda:InvokeFunction',
398398
Effect: 'Allow',
399399
},
@@ -485,7 +485,7 @@ describe('lambda authorizer', () => {
485485
PolicyDocument: {
486486
Statement: [
487487
{
488-
Resource: stack.resolve(func.functionArn),
488+
Resource: stack.resolve(func.resourceArnsForGrantInvoke),
489489
Action: 'lambda:InvokeFunction',
490490
Effect: 'Allow',
491491
},

packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json

+22-6
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,28 @@
5858
{
5959
"Action": "lambda:InvokeFunction",
6060
"Effect": "Allow",
61-
"Resource": {
62-
"Fn::GetAtt": [
63-
"funcC3A0C2E2",
64-
"Arn"
65-
]
66-
}
61+
"Resource": [
62+
{
63+
"Fn::GetAtt": [
64+
"funcC3A0C2E2",
65+
"Arn"
66+
]
67+
},
68+
{
69+
"Fn::Join": [
70+
"",
71+
[
72+
{
73+
"Fn::GetAtt": [
74+
"funcC3A0C2E2",
75+
"Arn"
76+
]
77+
},
78+
":*"
79+
]
80+
]
81+
}
82+
]
6783
}
6884
],
6985
"Version": "2012-10-17"

packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class EdgeFunction extends Resource implements lambda.IVersion {
4747
public readonly role?: iam.IRole;
4848
public readonly version: string;
4949
public readonly architecture: lambda.Architecture;
50+
public readonly resourceArnsForGrantInvoke: string[];
5051

5152
private readonly _edgeFunction: lambda.Function;
5253

@@ -68,6 +69,7 @@ export class EdgeFunction extends Resource implements lambda.IVersion {
6869
this.permissionsNode = this._edgeFunction.permissionsNode;
6970
this.version = lambda.extractQualifierFromArn(this.functionArn);
7071
this.architecture = this._edgeFunction.architecture;
72+
this.resourceArnsForGrantInvoke = this._edgeFunction.resourceArnsForGrantInvoke;
7173

7274
this.node.defaultChild = this._edgeFunction;
7375
}

packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts

+16-24
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => {
299299
PolicyDocument: {
300300
Statement: [{
301301
Action: 'lambda:InvokeFunction',
302-
Resource: {
303-
'Fn::GetAtt': [
304-
'PreHook8B53F672',
305-
'Arn',
306-
],
307-
},
302+
Resource: [
303+
{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] },
304+
{ 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, ':*']] },
305+
],
308306
Effect: 'Allow',
309307
}],
310308
Version: '2012-10-17',
@@ -347,12 +345,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => {
347345
PolicyDocument: {
348346
Statement: [{
349347
Action: 'lambda:InvokeFunction',
350-
Resource: {
351-
'Fn::GetAtt': [
352-
'PreHook8B53F672',
353-
'Arn',
354-
],
355-
},
348+
Resource: [
349+
{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] },
350+
{ 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PreHook8B53F672', 'Arn'] }, ':*']] },
351+
],
356352
Effect: 'Allow',
357353
}],
358354
Version: '2012-10-17',
@@ -395,12 +391,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => {
395391
PolicyDocument: {
396392
Statement: [{
397393
Action: 'lambda:InvokeFunction',
398-
Resource: {
399-
'Fn::GetAtt': [
400-
'PostHookF2E49B30',
401-
'Arn',
402-
],
403-
},
394+
Resource: [
395+
{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] },
396+
{ 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, ':*']] },
397+
],
404398
Effect: 'Allow',
405399
}],
406400
Version: '2012-10-17',
@@ -443,12 +437,10 @@ describe('CodeDeploy Lambda DeploymentGroup', () => {
443437
PolicyDocument: {
444438
Statement: [{
445439
Action: 'lambda:InvokeFunction',
446-
Resource: {
447-
'Fn::GetAtt': [
448-
'PostHookF2E49B30',
449-
'Arn',
450-
],
451-
},
440+
Resource: [
441+
{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] },
442+
{ 'Fn::Join': ['', [{ 'Fn::GetAtt': ['PostHookF2E49B30', 'Arn'] }, ':*']] },
443+
],
452444
Effect: 'Allow',
453445
}],
454446
Version: '2012-10-17',

packages/@aws-cdk/aws-codedeploy/test/lambda/integ.deployment-group.expected.json

+28
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,34 @@
495495
"PreHook8B53F672",
496496
"Arn"
497497
]
498+
},
499+
{
500+
"Fn::Join": [
501+
"",
502+
[
503+
{
504+
"Fn::GetAtt": [
505+
"PostHookF2E49B30",
506+
"Arn"
507+
]
508+
},
509+
":*"
510+
]
511+
]
512+
},
513+
{
514+
"Fn::Join": [
515+
"",
516+
[
517+
{
518+
"Fn::GetAtt": [
519+
"PreHook8B53F672",
520+
"Arn"
521+
]
522+
},
523+
":*"
524+
]
525+
]
498526
}
499527
]
500528
}

packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,7 @@ export class LambdaInvokeAction extends Action {
115115
}));
116116

117117
// allow pipeline to invoke this lambda functionn
118-
options.role.addToPolicy(new iam.PolicyStatement({
119-
actions: ['lambda:InvokeFunction'],
120-
resources: [this.props.lambda.functionArn],
121-
}));
118+
this.props.lambda.grantInvoke(options.role);
122119

123120
// allow the Role access to the Bucket, if there are any inputs/outputs
124121
if ((this.actionProperties.inputs || []).length > 0) {

packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json

+22-6
Original file line numberDiff line numberDiff line change
@@ -551,12 +551,28 @@
551551
{
552552
"Action": "lambda:InvokeFunction",
553553
"Effect": "Allow",
554-
"Resource": {
555-
"Fn::GetAtt": [
556-
"LambdaFun98622869",
557-
"Arn"
558-
]
559-
}
554+
"Resource": [
555+
{
556+
"Fn::GetAtt": [
557+
"LambdaFun98622869",
558+
"Arn"
559+
]
560+
},
561+
{
562+
"Fn::Join": [
563+
"",
564+
[
565+
{
566+
"Fn::GetAtt": [
567+
"LambdaFun98622869",
568+
"Arn"
569+
]
570+
},
571+
":*"
572+
]
573+
]
574+
}
575+
]
560576
}
561577
],
562578
"Version": "2012-10-17"

0 commit comments

Comments
 (0)