How to add permissions to Lambda Functions in AWS CDK

avatar
Borislav Hadzhiev

Last updated: Jan 27, 2024
4 min

banner

# Table of Contents

  1. Adding Permissions to a Lambda Function in AWS CDK
  2. Deploying Additional Permissions for Lambdas in CDK
  3. Lambda Permissions in AWS CDK - Discussion
  4. The provided execution Role does not have Permissions

# Adding Permissions to a Lambda Function in AWS CDK

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_18_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 sample:

  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.

# Table of Contents

  1. Deploying Additional Permissions for Lambdas in CDK
  2. Lambda Permissions in AWS CDK - Discussion
  3. The provided execution Role does not have Permissions

# 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.

# Table of Contents

  1. Lambda Permissions in AWS CDK - Discussion
  2. The provided execution Role does not have Permissions

# 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 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 as follows.

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', ), );

I've also written a guide on how to provision and configure lambda functions in AWS CDK.

# The provided execution Role does not have Permissions

Attach the AWSLambdaVPCAccessExecutionRole managed policy to the function's execution role to solve the lambda error "The provided execution role does not have permissions to call DescribeNetworkInterfaces".

The error occurs because lambda functions in a VPC need to have permission to create and manage elastic network interfaces.

To attach the AWSLambdaVPCAccessExecutionRole policy to the function, you have to:

  1. Open the AWS Lambda console and click on the function's name
  2. Click on the Configuration Tab and then click Permissions

click on role

  1. Click on the function's role and then click Add permissions and Attach policies
  2. Filter for the AWSLambdaVPCAccessExecutionRole managed policy, click the checkbox next to its name and click Attach Policy

attach vpc access policy

The AWSLambdaVPCAccessExecutionRole grants the lambda function permissions to create and manage elastic network interfaces and log to CloudWatch.

AWSLambdaVPCAccessExecutionRole
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "ec2:CreateNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:AssignPrivateIpAddresses", "ec2:UnassignPrivateIpAddresses" ], "Resource": "*" } ] }

After the function has permission to create and manage Elastic network interfaces, the error will be resolved.

If the error persists, make a small change to the Lambda function, e.g. increase its timeout by 1 second or add an extra print statement in the function's code and click on the Deploy button.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

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.

Copyright ยฉ 2024 Borislav Hadzhiev