Skip to content

Commit bb4c950

Browse files
authored
fix(lambda): grant invoke twice with different principals (#20174)
Supercedes: #18748 (which got too messy due to conflicts) Closes #15710 ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent fc2cd48 commit bb4c950

File tree

14 files changed

+116
-22
lines changed

14 files changed

+116
-22
lines changed

packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.integ.snapshot/TestStack.template.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@
445445
"TargetType": "lambda"
446446
},
447447
"DependsOn": [
448-
"FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4"
448+
"FunInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY1CA1AAFB"
449449
]
450450
},
451451
"FunServiceRole3CC876D7": {
@@ -498,7 +498,7 @@
498498
"FunServiceRole3CC876D7"
499499
]
500500
},
501-
"FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4": {
501+
"FunInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY1CA1AAFB": {
502502
"Type": "AWS::Lambda::Permission",
503503
"Properties": {
504504
"Action": "lambda:InvokeFunction",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"17.0.0"}
1+
{"version":"18.0.0"}

packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.integ.snapshot/integ.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"version": "18.0.0",
33
"testCases": {
4-
"aws-elasticloadbalancingv2-targets/test/integ.lambda-target": {
4+
"integ.lambda-target": {
55
"stacks": [
66
"TestStack"
77
],

packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.integ.snapshot/manifest.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "17.0.0",
2+
"version": "18.0.0",
33
"artifacts": {
44
"Tree": {
55
"type": "cdk:tree",
@@ -177,10 +177,19 @@
177177
"data": "FunA2CCED21"
178178
}
179179
],
180-
"/TestStack/Fun/InvokeServicePrincipal(elasticloadbalancing.amazonaws.com)": [
180+
"/TestStack/Fun/Invoke2UTWxhlfyqbT5FTn--5jvgbLgj+FfJwzswGk55DU1H--Y=": [
181181
{
182182
"type": "aws:cdk:logicalId",
183-
"data": "FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4"
183+
"data": "FunInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY1CA1AAFB"
184+
}
185+
],
186+
"FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4": [
187+
{
188+
"type": "aws:cdk:logicalId",
189+
"data": "FunInvokeServicePrincipalelasticloadbalancingamazonawscomD2CAC0C4",
190+
"trace": [
191+
"!!DESTRUCTIVE_CHANGES: WILL_DESTROY"
192+
]
184193
}
185194
]
186195
},

packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/lambda-target.integ.snapshot/tree.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -850,9 +850,9 @@
850850
"version": "0.0.0"
851851
}
852852
},
853-
"InvokeServicePrincipal(elasticloadbalancing.amazonaws.com)": {
854-
"id": "InvokeServicePrincipal(elasticloadbalancing.amazonaws.com)",
855-
"path": "TestStack/Fun/InvokeServicePrincipal(elasticloadbalancing.amazonaws.com)",
853+
"Invoke2UTWxhlfyqbT5FTn--5jvgbLgj+FfJwzswGk55DU1H--Y=": {
854+
"id": "Invoke2UTWxhlfyqbT5FTn--5jvgbLgj+FfJwzswGk55DU1H--Y=",
855+
"path": "TestStack/Fun/Invoke2UTWxhlfyqbT5FTn--5jvgbLgj+FfJwzswGk55DU1H--Y=",
856856
"attributes": {
857857
"aws:cdk:cloudformation:type": "AWS::Lambda::Permission",
858858
"aws:cdk:cloudformation:props": {

packages/@aws-cdk/aws-lambda/lib/function-base.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createHash } from 'crypto';
12
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
23
import * as ec2 from '@aws-cdk/aws-ec2';
34
import * as iam from '@aws-cdk/aws-iam';
@@ -414,7 +415,13 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC
414415
* Grant the given identity permissions to invoke this Lambda
415416
*/
416417
public grantInvoke(grantee: iam.IGrantable): iam.Grant {
417-
const identifier = `Invoke${grantee.grantPrincipal}`; // calls the .toString() of the principal
418+
const hash = createHash('sha256')
419+
.update(JSON.stringify({
420+
principal: grantee.grantPrincipal.toString(),
421+
conditions: grantee.grantPrincipal.policyFragment.conditions,
422+
}), 'utf8')
423+
.digest('base64');
424+
const identifier = `Invoke${hash}`;
418425

419426
// Memoize the result so subsequent grantInvoke() calls are idempotent
420427
let grant = this._invocationGrants[identifier];

packages/@aws-cdk/aws-lambda/test/function.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,6 +2755,75 @@ describe('function', () => {
27552755
});
27562756
});
27572757
});
2758+
2759+
test('called twice for the same service principal but with different conditions', () => {
2760+
// GIVEN
2761+
const stack = new cdk.Stack();
2762+
const fn = new lambda.Function(stack, 'Function', {
2763+
code: lambda.Code.fromInline('xxx'),
2764+
handler: 'index.handler',
2765+
runtime: lambda.Runtime.NODEJS_14_X,
2766+
});
2767+
const sourceArnA = 'some-arn-a';
2768+
const sourceArnB = 'some-arn-b';
2769+
const service = 's3.amazonaws.com';
2770+
const conditionalPrincipalA = new iam.PrincipalWithConditions(new iam.ServicePrincipal(service), {
2771+
ArnLike: {
2772+
'aws:SourceArn': sourceArnA,
2773+
},
2774+
StringEquals: {
2775+
'aws:SourceAccount': stack.account,
2776+
},
2777+
});
2778+
const conditionalPrincipalB = new iam.PrincipalWithConditions(new iam.ServicePrincipal(service), {
2779+
ArnLike: {
2780+
'aws:SourceArn': sourceArnB,
2781+
},
2782+
StringEquals: {
2783+
'aws:SourceAccount': stack.account,
2784+
},
2785+
});
2786+
2787+
// WHEN
2788+
fn.grantInvoke(conditionalPrincipalA);
2789+
fn.grantInvoke(conditionalPrincipalB);
2790+
2791+
// THEN
2792+
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Permission', 2);
2793+
Template.fromStack(stack).hasResource('AWS::Lambda::Permission', {
2794+
Properties: {
2795+
Action: 'lambda:InvokeFunction',
2796+
FunctionName: {
2797+
'Fn::GetAtt': [
2798+
'Function76856677',
2799+
'Arn',
2800+
],
2801+
},
2802+
Principal: service,
2803+
SourceAccount: {
2804+
Ref: 'AWS::AccountId',
2805+
},
2806+
SourceArn: sourceArnA,
2807+
},
2808+
});
2809+
2810+
Template.fromStack(stack).hasResource('AWS::Lambda::Permission', {
2811+
Properties: {
2812+
Action: 'lambda:InvokeFunction',
2813+
FunctionName: {
2814+
'Fn::GetAtt': [
2815+
'Function76856677',
2816+
'Arn',
2817+
],
2818+
},
2819+
Principal: service,
2820+
SourceAccount: {
2821+
Ref: 'AWS::AccountId',
2822+
},
2823+
SourceArn: sourceArnB,
2824+
},
2825+
});
2826+
});
27582827
});
27592828

27602829
test('throws if ephemeral storage size is out of bound', () => {

packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Template } from '@aws-cdk/assertions';
2+
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
23
import * as cdk from '@aws-cdk/core';
34
import * as lambda from '../lib';
4-
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
55

66
describe('lambda version', () => {
77
test('can import a Lambda version by ARN', () => {

packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Template } from '@aws-cdk/assertions';
22
import * as ec2 from '@aws-cdk/aws-ec2';
33
import * as iam from '@aws-cdk/aws-iam';
44
import * as s3 from '@aws-cdk/aws-s3';
5+
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
56
import * as cdk from '@aws-cdk/core';
67
import * as lambda from '../lib';
7-
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
88

99
describe('singleton lambda', () => {
1010
test('can add same singleton Lambda multiple times, only instantiated once in template', () => {

packages/@aws-cdk/aws-secretsmanager/test/lambda-rotation.integ.snapshot/cdk-integ-secret-lambda-rotation.template.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@
266266
"LambdaServiceRoleA8ED4D3B"
267267
]
268268
},
269-
"LambdaInvokeServicePrincipalsecretsmanageramazonawscomB927629E": {
269+
"LambdaInvokeN0a2GKfZP0JmDqDEVhhu6A0TUv3NyNbk4YMFKNc69846677": {
270270
"Type": "AWS::Lambda::Permission",
271271
"Properties": {
272272
"Action": "lambda:InvokeFunction",

0 commit comments

Comments
 (0)