Skip to content

Commit

Permalink
feat(custom-resources): supported custom role for provider lambda
Browse files Browse the repository at this point in the history
Added support to pass a custom role to the provider which the lambda will use. Can be used a.o. to pass a permission boundary.

closes aws#12126
  • Loading branch information
Ruben-E committed Dec 17, 2020
1 parent 8f6f9a8 commit 192c256
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
6 changes: 5 additions & 1 deletion packages/@aws-cdk/custom-resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@ the actual handler.
```ts
import { CustomResource } from '@aws-cdk/core';
import * as logs from '@aws-cdk/aws-logs';
import * as iam from '@aws-cdk/aws-iam';
import * as cr from '@aws-cdk/custom-resources';

const onEvent = new lambda.Function(this, 'MyHandler', { /* ... */ });

const myRole = new iam.Role(this, 'MyRole', { /* ... */ });

const myProvider = new cr.Provider(this, 'MyProvider', {
onEventHandler: onEvent,
isCompleteHandler: isComplete, // optional async "waiter"
logRetention: logs.RetentionDays.ONE_DAY // default is INFINITE
logRetention: logs.RetentionDays.ONE_DAY, // default is INFINITE
role: myRole, // must be assumable by the `lambda.amazonaws.com` service principal
});

new CustomResource(this, 'Resource1', { serviceToken: myProvider.serviceToken });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as path from 'path';
import * as cfn from '@aws-cdk/aws-cloudformation';
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import * as logs from '@aws-cdk/aws-logs';
import { Construct as CoreConstruct, Duration } from '@aws-cdk/core';
Expand Down Expand Up @@ -70,6 +71,16 @@ export interface ProviderProps {
* @default logs.RetentionDays.INFINITE
*/
readonly logRetention?: logs.RetentionDays;

/**
* AWS Lambda execution role.
*
* The role that will be assumed by the AWS Lambda.
* Must be assumable by the 'lambda.amazonaws.com' service principal.
*
* @default - A default role will be created.
*/
readonly role?: iam.Role;
}

/**
Expand Down Expand Up @@ -97,6 +108,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid

private readonly entrypoint: lambda.Function;
private readonly logRetention?: logs.RetentionDays;
private readonly role?: iam.Role;

constructor(scope: Construct, id: string, props: ProviderProps) {
super(scope, id);
Expand All @@ -111,6 +123,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid

this.logRetention = props.logRetention;

this.role = props.role;

const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME);

if (this.isCompleteHandler) {
Expand Down Expand Up @@ -153,6 +167,7 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid
handler: `framework.${entrypoint}`,
timeout: FRAMEWORK_HANDLER_TIMEOUT,
logRetention: this.logRetention,
role: this.role,
});

fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as path from 'path';
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import * as logs from '@aws-cdk/aws-logs';
import { Duration, Stack } from '@aws-cdk/core';
Expand Down Expand Up @@ -217,3 +218,57 @@ describe('log retention', () => {
expect(stack).not.toHaveResource('Custom::LogRetention');
});
});

describe('role', () => {
it('uses custom role when present', () => {
// GIVEN
const stack = new Stack();

// WHEN
new cr.Provider(stack, 'MyProvider', {
onEventHandler: new lambda.Function(stack, 'MyHandler', {
code: lambda.Code.fromAsset(path.join(__dirname, './integration-test-fixtures/s3-file-handler')),
handler: 'index.onEvent',
runtime: lambda.Runtime.NODEJS_10_X,
}),
role: new iam.Role(stack, 'MyRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
}),
});

// THEN
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
Role: {
'Fn::GetAtt': [
'MyRoleF48FFE04',
'Arn',
],
},
});
});

it('uses default role otherwise', () => {
// GIVEN
const stack = new Stack();

// WHEN
new cr.Provider(stack, 'MyProvider', {
onEventHandler: new lambda.Function(stack, 'MyHandler', {
code: lambda.Code.fromAsset(path.join(__dirname, './integration-test-fixtures/s3-file-handler')),
handler: 'index.onEvent',
runtime: lambda.Runtime.NODEJS_10_X,
}),
});

// THEN
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
Role: {
'Fn::GetAtt': [
'MyProviderframeworkonEventServiceRole8761E48D',
'Arn',
],
},
});
});
});

0 comments on commit 192c256

Please sign in to comment.