From fc612e317a10bbd0c3171b276e773dd161d93110 Mon Sep 17 00:00:00 2001 From: Roger Zhang Date: Thu, 18 Apr 2024 00:17:04 +0000 Subject: [PATCH] change to grantinvoke --- .../lambda-permissions.assets.json | 4 +- .../lambda-permissions.template.json | 4 +- .../manifest.json | 10 +- .../integ.permissions.js.snapshot/tree.json | 12 +- .../test/aws-lambda/test/integ.permissions.ts | 4 +- .../lib/experimental/edge-function.ts | 7 +- packages/aws-cdk-lib/aws-lambda/README.md | 5 +- .../aws-lambda/lib/function-base.ts | 63 ++-- .../aws-lambda/test/function.test.ts | 336 +----------------- 9 files changed, 63 insertions(+), 382 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.assets.json index 0fe6f14bc19f9..8ce83217aff9a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.assets.json @@ -1,7 +1,7 @@ { "version": "36.0.0", "files": { - "b2e192de6e64cd300b19c8ae06b46a2c61406cd49caa35f4ce1bf976f679491b": { + "018c275dea5b6c3d59a2559a0749bbb85138bfa549ff989fc5bdea87a681546f": { "source": { "path": "lambda-permissions.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "b2e192de6e64cd300b19c8ae06b46a2c61406cd49caa35f4ce1bf976f679491b.json", + "objectKey": "018c275dea5b6c3d59a2559a0749bbb85138bfa549ff989fc5bdea87a681546f.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-lambda/test/integ.permissions.js.snapshot/lambda-permissions.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.template.json index ca8f785185e12..e3b51a1d026ad 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/lambda-permissions.template.json @@ -78,7 +78,7 @@ "PrincipalOrgID": "o-xxxxxxxxxx" } }, - "MyLambdaInvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ48B59B4A": { + "MyLambdaInvokeiasez2Hq1vE2Fl1I4Yaq8UbNdwu1QsvuMXzIoTAF759EB93": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -92,7 +92,7 @@ "PrincipalOrgID": "o-yyyyyyyyyy2" } }, - "MyLambdaInvokefy1YgRC9j8kJQBgyNsNsleYXOlPp4RTnXEx2NNmcs4CE101ED": { + "MyLambdaInvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c0F884F73": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/manifest.json index 63ca9f40b6f84..b7f336e9615b0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/manifest.json @@ -18,7 +18,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}/b2e192de6e64cd300b19c8ae06b46a2c61406cd49caa35f4ce1bf976f679491b.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/018c275dea5b6c3d59a2559a0749bbb85138bfa549ff989fc5bdea87a681546f.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -58,16 +58,16 @@ "data": "MyLambdaInvoke138AF9IJcZORjZNKCKShZMMuVQwCnUkbFqMoQf5of0C1F7DFD8" } ], - "/lambda-permissions/MyLambda/InvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ=": [ + "/lambda-permissions/MyLambda/Invoke--iasez2Hq1vE2Fl1I4--Yaq8UbNdw--u1QsvuMXzIo+TA=": [ { "type": "aws:cdk:logicalId", - "data": "MyLambdaInvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ48B59B4A" + "data": "MyLambdaInvokeiasez2Hq1vE2Fl1I4Yaq8UbNdwu1QsvuMXzIoTAF759EB93" } ], - "/lambda-permissions/MyLambda/Invokefy1YgRC9j8kJQBgy+NsNsleYXOl--Pp4RTnXEx2NNmcs=": [ + "/lambda-permissions/MyLambda/InvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c=": [ { "type": "aws:cdk:logicalId", - "data": "MyLambdaInvokefy1YgRC9j8kJQBgyNsNsleYXOlPp4RTnXEx2NNmcs4CE101ED" + "data": "MyLambdaInvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c0F884F73" } ], "/lambda-permissions/MyLambda/FunctionUrl/Resource": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/tree.json index 8d760b30501af..f53602a03e6d1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.js.snapshot/tree.json @@ -137,9 +137,9 @@ "version": "0.0.0" } }, - "InvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ=": { - "id": "InvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ=", - "path": "lambda-permissions/MyLambda/InvokeZoBUDhNic8W9iwOX3PUHW4PxLYxcNvgQd0I750ZVGfQ=", + "Invoke--iasez2Hq1vE2Fl1I4--Yaq8UbNdw--u1QsvuMXzIo+TA=": { + "id": "Invoke--iasez2Hq1vE2Fl1I4--Yaq8UbNdw--u1QsvuMXzIo+TA=", + "path": "lambda-permissions/MyLambda/Invoke--iasez2Hq1vE2Fl1I4--Yaq8UbNdw--u1QsvuMXzIo+TA=", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -159,9 +159,9 @@ "version": "0.0.0" } }, - "Invokefy1YgRC9j8kJQBgy+NsNsleYXOl--Pp4RTnXEx2NNmcs=": { - "id": "Invokefy1YgRC9j8kJQBgy+NsNsleYXOl--Pp4RTnXEx2NNmcs=", - "path": "lambda-permissions/MyLambda/Invokefy1YgRC9j8kJQBgy+NsNsleYXOl--Pp4RTnXEx2NNmcs=", + "InvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c=": { + "id": "InvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c=", + "path": "lambda-permissions/MyLambda/InvokeeCd3Xf1YrYI9J9KZWaa7iTC3wv2MejAlHdcglgF5m4c=", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.ts index 55f173d714ba4..9079c0a76efbf 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.permissions.ts @@ -17,9 +17,9 @@ fn.grantInvoke(new iam.AnyPrincipal().inOrganization('o-yyyyyyyyyy')); fn.grantInvoke(new iam.OrganizationPrincipal('o-xxxxxxxxxx')); -fn.grantInvokeV2(new iam.AnyPrincipal().inOrganization('o-yyyyyyyyyy2')); +fn.grantInvoke(new iam.AnyPrincipal().inOrganization('o-yyyyyyyyyy2'), { onlyGrantLatestVersion: true }); -fn.grantInvokeV2(new iam.OrganizationPrincipal('o-xxxxxxxxxx2')); +fn.grantInvoke(new iam.OrganizationPrincipal('o-xxxxxxxxxx2'), { onlyGrantLatestVersion: true }); const fnUrl = fn.addFunctionUrl(); const role = new iam.Role(stack, 'MyRole', { diff --git a/packages/aws-cdk-lib/aws-cloudfront/lib/experimental/edge-function.ts b/packages/aws-cdk-lib/aws-cloudfront/lib/experimental/edge-function.ts index 1e58b82ca5790..93974491855e0 100644 --- a/packages/aws-cdk-lib/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/aws-cdk-lib/aws-cloudfront/lib/experimental/edge-function.ts @@ -116,11 +116,8 @@ export class EdgeFunction extends Resource implements lambda.IVersion { public addToRolePolicy(statement: iam.PolicyStatement): void { return this.lambda.addToRolePolicy(statement); } - public grantInvoke(identity: iam.IGrantable): iam.Grant { - return this.lambda.grantInvoke(identity); - } - public grantInvokeV2(identity: iam.IGrantable, grantVersionAccess?: boolean): iam.Grant { - return this.lambda.grantInvokeV2(identity, grantVersionAccess); + public grantInvoke(identity: iam.IGrantable, props?: lambda.GrantInvokeProps): iam.Grant { + return this.lambda.grantInvoke(identity, props); } public grantInvokeUrl(identity: iam.IGrantable): iam.Grant { return this.lambda.grantInvokeUrl(identity); diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index a8357014b64fe..04311dc47b715 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -201,15 +201,14 @@ You can also restrict permissions given to AWS services by providing a source account or ARN (representing the account and identifier of the resource that accesses the function or layer). -**Important**: Be aware that `fn.grantInvoke()` grants permission to the principal to call any version of the function, including all past ones. If you only want the principal to invoke the latest version, use `fn.grantInvokeV2()` instead. +**Important**: By default `fn.grantInvoke()` grants permission to the principal to invoke any version of the function, including all past ones. If you only want the principal to invoke the latest version, use `grantInvoke(grantee, { onlyGrantLatestVersion:true })`. ```ts // Grant permissions to a service declare const fn: lambda.Function; const principal = new iam.ServicePrincipal('my-service'); -fn.grantInvokeV2(principal, false); -// false is the default and can be omitted +grantInvoke(principal, { onlyGrantLatestVersion = true }); ``` For more information, see diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function-base.ts b/packages/aws-cdk-lib/aws-lambda/lib/function-base.ts index 875dce94f2820..5b5b483f7e0de 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function-base.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function-base.ts @@ -95,13 +95,7 @@ export interface IFunction extends IResource, ec2.IConnectable, iam.IGrantable { /** * Grant the given identity permissions to invoke this Lambda */ - grantInvoke(grantee: iam.IGrantable): iam.Grant; - - /** - * Grant the given identity permissions to invoke to $Latest version when grantVersionAccess is false - * Grant the given identity permissions to invoke All version when grantVersionAccess is true - */ - grantInvokeV2(grantee: iam.IGrantable, grantVersionAccess?: boolean): iam.Grant; + grantInvoke(grantee: iam.IGrantable, props?: GrantInvokeProps): iam.Grant; /** * Grant the given identity permissions to invoke this Lambda Function URL @@ -233,6 +227,19 @@ export interface FunctionAttributes { readonly architecture?: Architecture; } +/** + * Parameters to pass into grantInvoke method + */ +export interface GrantInvokeProps { + /** + * Controls whether to grant invoke access to all function versions. Defaults to `false`. + * - When set to `false`, both the function and functions with specific versions can be invoked. + * - When set to `true`, only the function without a specific version (`$Latest`) can be invoked. + * @default false + */ + readonly onlyGrantLatestVersion?: boolean; +} + export abstract class FunctionBase extends Resource implements IFunction, ec2.IClientVpnConnectionHandler { /** * The principal this Lambda Function is running as @@ -424,51 +431,27 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC /** * Grant the given identity permissions to invoke this Lambda - */ - public grantInvoke(grantee: iam.IGrantable): iam.Grant { - const hash = createHash('sha256') - .update(JSON.stringify({ - principal: grantee.grantPrincipal.toString(), - conditions: grantee.grantPrincipal.policyFragment.conditions, - }), 'utf8') - .digest('base64'); - const identifier = `Invoke${hash}`; - - // Memoize the result so subsequent grantInvoke() calls are idempotent - let grant = this._invocationGrants[identifier]; - if (!grant) { - grant = this.grant(grantee, identifier, 'lambda:InvokeFunction', this.resourceArnsForGrantInvoke); - this._invocationGrants[identifier] = grant; - } - return grant; - } - - /** - * Grants the specified identity permissions to invoke this Lambda function. - * - * **Important:** Avoid using `grantInvokeV2` in conjunction with `grantInvoke`. - * * @param grantee The principal (identity) to grant invocation permission. - * @param grantVersionAccess (Optional) Controls whether to grant access to all function versions. Defaults to `false`. - * - When set to `false`, only the function without a specific version (`$Latest`) can be invoked. - * - When set to `true`, both the function and functions with specific versions can be invoked. + * @param props onlyGrantLatestVersion (Optional) Controls whether to grant access only to latest function versions. Defaults to `false`. + * - When set to `false`, both the function and functions with specific versions can be invoked. + * - When set to `true`, only the function without a specific version (`$Latest`) can be invoked. */ - public grantInvokeV2(grantee: iam.IGrantable, grantVersionAccess?: boolean): iam.Grant { + public grantInvoke(grantee: iam.IGrantable, props: GrantInvokeProps = {}): iam.Grant { const hash = createHash('sha256') .update(JSON.stringify({ principal: grantee.grantPrincipal.toString(), conditions: grantee.grantPrincipal.policyFragment.conditions, - grantVersionAccess: grantVersionAccess, + onlyGrantLatestVersion: props.onlyGrantLatestVersion, }), 'utf8') .digest('base64'); const identifier = `Invoke${hash}`; - // Memoize the result so subsequent grantInvokeV2() calls are idempotent + // Memoize the result so subsequent grantInvoke() calls are idempotent let grant = this._invocationGrants[identifier]; if (!grant) { - let resouceArns = [this.functionArn]; - if (grantVersionAccess) { - resouceArns = this.resourceArnsForGrantInvoke; + let resouceArns = this.resourceArnsForGrantInvoke; + if (props.onlyGrantLatestVersion) { + resouceArns = [this.functionArn]; } grant = this.grant(grantee, identifier, 'lambda:InvokeFunction', resouceArns); this._invocationGrants[identifier] = grant; diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index bfb37d73b4fb3..9038425b57347 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -1282,275 +1282,7 @@ describe('function', () => { }); }); - test('with a service principal', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - const service = new iam.ServicePrincipal('apigateway.amazonaws.com'); - - // WHEN - fn.grantInvoke(service); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'apigateway.amazonaws.com', - }); - }); - - test('with an account principal', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - const account = new iam.AccountPrincipal('123456789012'); - - // WHEN - fn.grantInvoke(account); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: '123456789012', - }); - }); - - test('with an arn principal', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - const account = new iam.ArnPrincipal('arn:aws:iam::123456789012:role/someRole'); - - // WHEN - fn.grantInvoke(account); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'arn:aws:iam::123456789012:role/someRole', - }); - }); - - test('with an organization principal', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - const org = new iam.OrganizationPrincipal('my-org-id'); - - // WHEN - fn.grantInvoke(org); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: '*', - PrincipalOrgID: 'my-org-id', - }); - }); - - test('can be called twice for the same service principal', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - const service = new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com'); - - // WHEN - fn.grantInvoke(service); - fn.grantInvoke(service); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'elasticloadbalancing.amazonaws.com', - }); - }); - - test('with an imported role (in the same account)', () => { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '123456789012' }, - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - - // WHEN - fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: 'lambda:InvokeFunction', - Effect: 'Allow', - Resource: [ - { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, - { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Function76856677', 'Arn'] }, ':*']] }, - ], - }, - ], - }, - Roles: ['someRole'], - }); - }); - - test('with an imported role (from a different account)', () => { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '3333' }, - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - - // WHEN - fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'arn:aws:iam::123456789012:role/someRole', - }); - }); - - test('on an imported function (same account)', () => { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '123456789012' }, - }); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - // WHEN - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - Principal: 'elasticloadbalancing.amazonaws.com', - }); - }); - - test('on an imported function (unresolved account)', () => { - const stack = new cdk.Stack(); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - expect( - () => fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')), - ).toThrow(/Cannot modify permission to lambda function/); - }); - - test('on an imported function (unresolved account & w/ allowPermissions)', () => { - // GIVEN - const stack = new cdk.Stack(); - const fn = lambda.Function.fromFunctionAttributes(stack, 'Function', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - sameEnvironment: true, - }); - - // WHEN - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - Principal: 'elasticloadbalancing.amazonaws.com', - }); - }); - - test('on an imported function (different account)', () => { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '111111111111' }, // Different account - }); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - // THEN - expect(() => { - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - }).toThrow(/Cannot modify permission to lambda function/); - }); - - test('on an imported function (different account & w/ skipPermissions', () => { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '111111111111' }, // Different account - }); - const fn = lambda.Function.fromFunctionAttributes(stack, 'Function', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - skipPermissions: true, - }); - - // THEN - expect(() => { - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - }).not.toThrow(); - }); - }); - - describe('grantInvokeV2', () => { - test('adds iam:InvokeFunction', () => { + test('adds iam:InvokeFunction with onlyGrantLatestVersion', () => { // GIVEN const stack = new cdk.Stack(); const role = new iam.Role(stack, 'Role', { @@ -1563,7 +1295,7 @@ describe('function', () => { }); // WHEN - fn.grantInvokeV2(role); + fn.grantInvoke(role, { onlyGrantLatestVersion:true }); // THEN Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { @@ -1580,39 +1312,6 @@ describe('function', () => { }); }); - test('adds iam:InvokeFunction with version', () => { - // GIVEN - const stack = new cdk.Stack(); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.AccountPrincipal('1234'), - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_LATEST, - }); - - // WHEN - fn.grantInvokeV2(role, true); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: 'lambda:InvokeFunction', - Effect: 'Allow', - Resource: [ - { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, - { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Function76856677', 'Arn'] }, ':*']] }, - ], - }, - ], - }, - }); - }); - test('with a service principal', () => { // GIVEN const stack = new cdk.Stack(); @@ -1624,7 +1323,7 @@ describe('function', () => { const service = new iam.ServicePrincipal('apigateway.amazonaws.com'); // WHEN - fn.grantInvokeV2(service); + fn.grantInvoke(service); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1650,7 +1349,7 @@ describe('function', () => { const account = new iam.AccountPrincipal('123456789012'); // WHEN - fn.grantInvokeV2(account); + fn.grantInvoke(account); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1676,7 +1375,7 @@ describe('function', () => { const account = new iam.ArnPrincipal('arn:aws:iam::123456789012:role/someRole'); // WHEN - fn.grantInvokeV2(account); + fn.grantInvoke(account); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1702,7 +1401,7 @@ describe('function', () => { const org = new iam.OrganizationPrincipal('my-org-id'); // WHEN - fn.grantInvokeV2(org); + fn.grantInvoke(org); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1729,8 +1428,8 @@ describe('function', () => { const service = new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com'); // WHEN - fn.grantInvokeV2(service); - fn.grantInvokeV2(service); + fn.grantInvoke(service); + fn.grantInvoke(service); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1757,7 +1456,7 @@ describe('function', () => { }); // WHEN - fn.grantInvokeV2(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); + fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); // THEN Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { @@ -1766,7 +1465,10 @@ describe('function', () => { { Action: 'lambda:InvokeFunction', Effect: 'Allow', - Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + Resource: [ + { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Function76856677', 'Arn'] }, ':*']] }, + ], }, ], }, @@ -1786,7 +1488,7 @@ describe('function', () => { }); // WHEN - fn.grantInvokeV2(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); + fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1809,7 +1511,7 @@ describe('function', () => { const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); // WHEN - fn.grantInvokeV2(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1824,7 +1526,7 @@ describe('function', () => { const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); expect( - () => fn.grantInvokeV2(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')), + () => fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')), ).toThrow(/Cannot modify permission to lambda function/); }); @@ -1837,7 +1539,7 @@ describe('function', () => { }); // WHEN - fn.grantInvokeV2(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { @@ -1856,7 +1558,7 @@ describe('function', () => { // THEN expect(() => { - fn.grantInvokeV2(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); }).toThrow(/Cannot modify permission to lambda function/); }); @@ -1872,7 +1574,7 @@ describe('function', () => { // THEN expect(() => { - fn.grantInvokeV2(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); }).not.toThrow(); }); });