Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lambda): unlock use case for cross-account functions w/ preconfigured permissions #18979

Merged
merged 5 commits into from Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 27 additions & 3 deletions packages/@aws-cdk/aws-lambda/lib/function-base.ts
Expand Up @@ -180,6 +180,20 @@ export interface FunctionAttributes {
*/
readonly sameEnvironment?: boolean;

/**
* Setting this property informs the CDK that the imported function ALREADY HAS the necessary permissions
* for what you are trying to do. When not configured, the CDK attempts to auto-determine whether or not
* additional permissions are necessary on the function when grant APIs are used. If the CDK tried to add
* permissions on an imported lambda, it will fail.
*
* Set this property *ONLY IF* you are committing to manage the imported function's permissions outside of
* CDK. You are acknowledging that your CDK code alone will have insufficient permissions to access the
* imported function.
*
* @default false
*/
readonly skipPermissions?: boolean;

/**
* The architecture of this Lambda Function (this is an optional attribute and defaults to X86_64).
* @default - Architecture.X86_64
Expand Down Expand Up @@ -228,6 +242,15 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC
*/
protected abstract readonly canCreatePermissions: boolean;

/**
* Whether the user decides to skip adding permissions.
* The only use case is for cross-account, imported lambdas
* where the user commits to modifying the permisssions
* on the imported lambda outside CDK.
* @internal
*/
protected readonly _skipPermissions?: boolean;

/**
* Actual connections object for this Lambda
*
Expand Down Expand Up @@ -342,9 +365,10 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC
});

const permissionNode = this._functionNode().tryFindChild(identifier);
if (!permissionNode) {
throw new Error('Cannot modify permission to lambda function. Function is either imported or $LATEST version. '
+ 'If the function is imported from the same account use `fromFunctionAttributes()` API with the `sameEnvironment` flag.');
if (!permissionNode && !this._skipPermissions) {
throw new Error('Cannot modify permission to lambda function. Function is either imported or $LATEST version.\n'
+ 'If the function is imported from the same account use `fromFunctionAttributes()` API with the `sameEnvironment` flag.\n'
+ 'If the function is imported from a different account and already has the correct permissions use `fromFunctionAttributes()` API with the `skipPermissions` flag.');
}
return { statementAdded: true, policyDependable: permissionNode };
},
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-lambda/lib/function.ts
Expand Up @@ -453,6 +453,7 @@ export class Function extends FunctionBase {
public readonly architecture = attrs.architecture ?? Architecture.X86_64;

protected readonly canCreatePermissions = attrs.sameEnvironment ?? this._isStackAccount();
protected readonly _skipPermissions = attrs.skipPermissions ?? false;

constructor(s: Construct, i: string) {
super(s, i, {
Expand Down
16 changes: 15 additions & 1 deletion packages/@aws-cdk/aws-lambda/test/function.test.ts
Expand Up @@ -845,7 +845,6 @@ describe('function', () => {
});

describe('grantInvoke', () => {

test('adds iam:InvokeFunction', () => {
// GIVEN
const stack = new cdk.Stack();
Expand Down Expand Up @@ -1094,6 +1093,21 @@ describe('function', () => {
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();
kaizencc marked this conversation as resolved.
Show resolved Hide resolved
});
});

test('Can use metricErrors on a lambda Function', () => {
Expand Down