scubbo
scubbo

Reputation: 5818

In CDK, why is a Lambda Function's Role Optional? What is the idiomatic way to grant permissions to it?

I note that the role property of a CDK Lambda Function is of type iam.IRole | undefined. This is surprising to me - how is it possible for a Lambda Function to exist without a Role to act as?

In practice, this is frustrating because it means that, instead of:

const dynamoTable = new Table(...);
const func = new Function(...);
dynamoTable.grantReadWriteData(func.role);

, I have to instead do

[...]
if (typeof func.role !== 'undefined') {
  dynamoTable.grantReadWriteData(func.role);
}

(Though I am at least impressed that TypeScript can determine that the property is defined within that if block if, instead, I extract const funcRole = func.role)

Is there a more idiomatic way to do this?


EDIT: Balu's answer, which points out that the Function itself is IGrantable, addresses how to update the RolePolicy for the auto-created Role - but (I believe?) we still need a concrete Role in order to update Resource Policies (e.g. on Queues) by calling resource.addToRolePolicy(new PolicyStatement({...})) with appropriate principals. Some resources like Dynamo Tables have "helper" methods that can accept the Function itself - but for those that don't, the Role (or, more accurately, a Principal) is required.

Upvotes: 4

Views: 2903

Answers (1)

Balu Vyamajala
Balu Vyamajala

Reputation: 10333

CDK code, if we don't pass a role, it creates a role with default permissions AWSLambdaBasicExecutionRole and AWSLambdaVPCAccessExecutionRole

From documentation:

Lambda functions assume an IAM role during execution. In CDK by default, Lambda functions will use an autogenerated Role if one is not provided.

The autogenerated Role is automatically given permissions to execute the Lambda function.

We can always add additional permissions by calling addToRolePolicy on the function. OR by calling grant permissions on other resources like dynamoDb or loggroup, etc.

Lets say our lambda is created like this

const myFun = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_10_X,
  handler: 'index.handler',
  code: ...})

We can add permissions like this:

 myFun.role.addToRolePolicy(
        new iam.PolicyStatement({
            resources: ['*'],
            actions: [...],
        })
    );

OR Lets say we want to grant access to write to log group, we can do this, which appends additional inline policy to lambda role.

const logGroup = new awsLogs.LogGroup(this, `my-fun`, {
    retention: 30,
    logGroupName: `/aws/lambda/${functionName}`,
    removalPolicy: cdk.RemovalPolicy.DESTROY,
});
logGroup.grantWrite(this.myFun);

Similarly in case of DynamoDB,for dynamoTable.grantReadWriteData method, we need to pass function itself, not the role. so,

Instead of

dynamoTable.grantReadWriteData(myFun.role);

We should do

dynamoTable.grantReadWriteData(myFun);

Upvotes: 3

Related Questions