In this blog post, we’ll outline how to create a custom IAM role, an AWS Lambda function, and then assign the custom role to the Lambda function in AWS CDK.
Additionally, we’ll also provide another option to add add permissions to our Lambda function using the .addToRolePolicy method.
Table of Contents
1. Prerequisites
Before we start building the AWS Lambda and IAM Role construct, you’re required to have done the following prerequisites before you can run AWS CDK code in TypeScript.
- Install AWS CDK and TypeScript NPM packages
- Install the AWS CLI and configure an AWS profile
- Create an AWS CDK TypeScript project
If you’ve already done this, you can proceed to step 2.
1.1 Install AWS CDK
Use the NPM package manager in your terminal to install AWS CDK and TypeScript globally on your system:
➜ npm install -g aws-cdk typescript
added 180 packages, and audited 181 packages in 7s
found 0 vulnerabilities
~ took 7s
Once you’ve installed AWS CDK you can validate that you’re running on the latest version by running the following command in the terminal:
➜ cdk version
2.23.0 (build 50444aa)
1.2 Install AWS CLI and configure an AWS profile
The AWS CLI is a command line tool that allows you to interact with AWS services in your terminal. Depending on if you’re running Linux, macOS, or Windows the installation goes like this:
# macOS install method:
brew install awscli
# Windows install method:
wget https://awscli.amazonaws.com/AWSCLIV2.msi
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
# Linux (Ubuntu) install method:
sudo apt install awscli
In order to access your AWS account with the AWS CLI, you first need to configure an AWS Profile. There are 2 ways of configuring a profile:
- Access and secret key credentials from an IAM user
- AWS Single Sign-on (SSO) user
In this article, I’ll briefly explain how to configure the first method so that you can proceed more quickly to set up the Amazon S3 Bucket in AWS CDK.
If you wish to set up the AWS profile more securely, then I’d suggest you read and apply the steps described in setting up AWS CLI with AWS Single Sign-On (SSO).
In order to configure the AWS CLI with your IAM user’s access and secret key credentials, you need to login to the AWS Console. Go to IAM > Users, select your IAM user and click on the Security credentials tab to create an access and secret key.
Then configure the AWS profile on the AWS CLI as follows:
➜ aws configure
AWS Access Key ID [None]: <insert_access_key>
AWS Secret Access Key [None]: <insert_secret_key>
Default region name [None]: <insert_aws_region>
Default output format [json]: json
Your was credentials are stored in ~/.aws/credentials and you can validate that your AWS profile is working by running the command:
➜ aws sts get-caller-identity
{
"UserId": "AIDA5BRFSNF24CDMD7FNY",
"Account": "012345678901",
"Arn": "arn:aws:iam::012345678901:user/test-user"
}
1.3 Create a new AWS CDK TypeScript Project
Now that we’ve configured our profile and installed the packages, it’s time to create an AWS CDK TypeScript project where you’re going to build the Amazon S3 Bucket construct.
You can generate a new AWS CDK TypeScript project by running the following command in an empty directory:
➜ cdk init sample-app --language=typescript
Applying project template sample-app for typescript
# Welcome to your CDK TypeScript project!
You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`CdkProjectStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
## Useful commands
* `npm run build` compile typescript to js
* `npm run watch` watch for changes and compile
* `npm run test` perform the jest unit tests
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk synth` emits the synthesized CloudFormation template
Initializing a new git repository...
Executing npm install...
✅ All done!
2. How to assign a custom role to a lambda function
Now that we’ve configured our workspace and cdk app, we can proceed with the creation of the constructs.
2.1 Creating a Custom IAM Role
The first step is to create a custom IAM role. This role will dictate what resources our Lambda function can interact with in our AWS environment.
Here’s an example of how to do this:
const role = new iam.Role(this, 'MyCustomRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
In this example, we’ve created a role that can be assumed by Lambda services called ‘MyCustomRole’.
2.2 Creating an AWS Lambda Function
Now that we have our custom role created, we can go ahead and create our AWS Lambda function. We will be using the aws-cdk-lib/aws-lambda
module for this.
Here’s how you do it:
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
code: lambda.Code.fromInline(`
exports.handler = async (event) => {
console.log('event: ', event)
};
`),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_14_X,
role,
});
2.3 Assigning the Custom Role to the Lambda Function
We’ve created our IAM Role and Lambda function. Now, we need to assign our custom role to the function.
We do this by adding the role to the properties of our Lambda function as follows:
import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
export class CustomRoleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const role = new iam.Role(this, 'MyCustomRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
code: lambda.Code.fromInline(`
exports.handler = async (event) => {
console.log('event: ', event)
};
`),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_14_X,
role,
});
}
}
With this code, we’ve now assigned our custom IAM role ‘MyCustomRole’ to the Lambda function ‘MyLambdaFunction’ in our ‘CustomRoleStack’.
3. Extend custom role with additional policies
In some cases, you may want to add additional permissions to your Lambda function.
You can do this by using the .addToRolePolicy()
method on the Lambda function.
Let’s assume we want to give our function the ability to write logs to Amazon CloudWatch Logs:
myFunction.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
resources: ['arn:aws:logs:*:*:*'],
}));
In the above example, we’ve given our Lambda function the ability to create a log group, create a log stream, and put log events.
Conclusion
In this post, we’ve shown how you can create a custom IAM role, create a Lambda function, and assign the custom role to the Lambda function using AWS CDK.
We also discussed how to use the .addToRolePolicy()
method to add permissions to your Lambda function. This process provides flexibility and security in managing your AWS resources, enabling you to tailor permissions to suit your project’s specific needs.
Everything that you’ve just built by following this article can also be found as a fully working example on my GitHub repository.
Remember, assigning the least amount of privileges necessary for a function to perform its job is a best practice in AWS to reduce the potential blast radius in case of any security breaches.