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

Viewed 1035

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?

1 Answers

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);
Related