How to add permissions to Lambda Functions in AWS CDK

avatar

Borislav Hadzhiev

Last updated: Apr 12, 2022

banner

Photo from Unsplash

Adding Permissions to a Lambda Function in AWS CDK #

In order to add permissions to a Lambda Function, we have to attach a policy to the function's role.

The code for this article is available on GitHub

Let's take a look at a complete example where we:

  1. Create a Lambda function
  2. Create an IAM Policy statement
  3. Attach an inline policy to the function's role, passing it the policy statement we created
lib/cdk-starter-stack.ts
import * as iam from 'aws-cdk-lib/aws-iam'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // 👇 define the Lambda const myFunction = new NodejsFunction(this, 'my-function', { runtime: lambda.Runtime.NODEJS_16_X, handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.ts`), }); // 👇 create a policy statement const s3ListBucketsPolicy = new iam.PolicyStatement({ actions: ['s3:ListAllMyBuckets'], resources: ['arn:aws:s3:::*'], }); // 👇 add the policy to the Function's role myFunction.role?.attachInlinePolicy( new iam.Policy(this, 'list-buckets-policy', { statements: [s3ListBucketsPolicy], }), ); } }
If you still use CDK version 1, switch to the cdk-v1 branch in the GitHub repository.

Let's go over what we did in the code snippet:

  1. We defined a Lambda function via the NodejsFunction construct
  2. We created an IAM Policy Statement with the PolicyStatement class. The policy grants the Lambda function access to list the S3 buckets in the account.
  3. We attached an inline IAM Policy to the function's role and we passed it the statement we created earlier

Deploying Additional Permissions for Lambdas in CDK #

I'll issue the deploy command:

shell
npx aws-cdk deploy

The CloudFormation console shows that our list-buckets-policy has been provisioned:

cloudformation lambda permissions

The IAM role of the lambda function now has 2 policies:

  1. The default AWSLambdaBasicExecutionRole policy that is managed by AWS
  2. The list-buckets-policy inline policy that is managed by us

lambda iam role

At this point, we've successfully added permissions to a Lambda function's role.

Lambda Permissions in AWS CDK - Discussion #

When we define a Lambda function, it comes with an automatically generated Role (unless we explicitly provide one). This role will then be assumed by the Lambda function during execution.

The automatically generated policy included in the role is called AWSLambdaBasicExecutionRole. It grants permissions related to logging:

default-policy.json
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] }

In most of our lambda functions we will want to be able to log information to Cloud Watch, so extending the default lambda role is a good option.

If we were to provide our own IAM role, we would then have to manually edit the Trust relationship of the role to allow the service lambda.amazonaws.com to assume the role and add the logging permissions ourselves.

The default trust relationship looks like:

default-trust-relationship.json
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

By attaching an inline policy to the function's role, we were able to keep the default Lambda execution role and attach policies to extend it.

If we were to pass in our own role, we could add the AWSLambdaBasicExecutionRole policy to it in the following way:

const myFunction = new NodejsFunction(this, 'my-function', { // ... rest role: someRole, }); myFunction.role?.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName( 'service-role/AWSLambdaBasicExecutionRole', ), ); // only required if your function is in a VPC myFunction.role?.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName( 'service-role/AWSLambdaVPCAccessExecutionRole', ), );

Further Reading #

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.