This is the AWS CDK v2 Developer Guide. The older CDK v1 entered maintenance on June 1, 2022 and ended support on June 1, 2023.
Define AWS Identity and Access Management (IAM) roles and policies for L2 constructs when using the AWS Cloud Development Kit (AWS CDK).
Use grant methods to define permissions
When you define your infrastructure using L2 constructs from the AWS Construct Library, you can use the provided grant methods to specify the permissions your resources will require. The AWS CDK will automatically create the IAM roles needed for all AWS resources that require them.
The following is an example that defines permissions between an AWS Lambda function and Amazon Simple Storage Service (Amazon S3) bucket.
Here, the grantRead
method of the Bucket L2 construct is used to define these permissions:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as kms from 'aws-cdk-lib/aws-kms';
export class CdkDemoStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const key = new kms.Key(this, 'BucketKey');
const bucket = new s3.Bucket(this, 'Bucket', {
encryptionKey: key,
});
const handler = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
});
// Define permissions between function and S3 bucket using grantRead method
bucket.grantRead(handler);
}
}
When you use grant methods of L2 constructs to define permissions between resources, the AWS CDK will create roles
with least privilege policies based on the method you specify. As a security best practice, we recommend that you use
the method that applies only the permissions that you require. For example, if you only need to grant permissions for a
Lambda function to read from an Amazon S3 bucket, use the grantRead
method instead of
grantReadWrite
.
For each method that you use, the CDK creates a unique IAM role for the specified resources. If necessary, you can also directly modify the policy that will be attached to the role. The following is an example:
import { aws_iam as iam } from 'aws-cdk-lib';
handler.addToRolePolicy(new iam.PolicyStatement({
actions: ['s3:GetObject', 's3:List*'],
resources: [
bucket.bucketArn,
bucket.arnForObjects('*'),
]
}));
However, we recommend that you use the grant
methods when available.
Manually create and use IAM roles
If you prefer not to use the CDK grant
methods to create and manage permissions, you must
manually create and configure them. You can create IAM roles using the AWS Management Console, AWS CLI, or AWS SDKs. Then, you can
pass them into your CDK application manually or use the role customization feature.
Reference and manage all roles manually
Constructs that require a role have an optional role
property that you can use to pass in a role
object.
To reference a role manually
-
Use
Role.fromRoleName()
to reference your pre-existing role. The following is an example:const existingRole = Role.fromRoleName(stack, 'Role', 'my-pre-existing-role', { mutable: false // Prevent CDK from attempting to add policies to this role }
-
Pass the pre-existing role when defining your resource. The following is an example:
const handler = new lambda.Function(stack, 'Handler', { runtime: lambda.Runtime.NODEJS_20_XZ, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), // Pass in pre-existing role role: existingRole, });
Use the role customization feature
The AWS CDK role customization feature generates a report of roles and policies in your CDK app. You can use this feature to generate a report. Then you can substitute pre-created roles for them.
To use the role customization feature
-
Add
Role.customizeRoles()
somewhere towards the top of your CDK application. The following is an example:const stack = new Stack(app, 'LambdaStack'); // Add this to use the role customization feature iam.Role.customizeRoles(stack); // Define your resources using L2 constructs const key = new kms.Key(stack, 'BucketKey'); const bucket = new s3.Bucket(stack, 'Bucket', { encryptionKey: key, }); const handler = new lambda.Function(stack, 'Handler', { runtime: lambda.Runtime.NODEJS_16_X, handler: 'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); // The grantRead() is still important. Even though it actually doesn't mutate // any policies, it indicates the need for them. bucket.grantRead(handler);
-
When you synthesize your application, the CDK will throw an error, indicating that you need to provide the pre-created role name to
Role.customizeRoles()
. The following is an example of the generated report:<missing role> (LambdaStack/Handler/ServiceRole) AssumeRole Policy: [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" } } ] Managed Policy ARNs: [ "arn:(PARTITION):iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ] Managed Policies Statements: NONE Identity Policy Statements: [ { "Action": [ "s3:GetObject*", "s3:GetBucket*", "s3:List*" ], "Effect": "Allow", "Resource": [ "(LambdaStack/Bucket/Resource.Arn)", "(LambdaStack/Bucket/Resource.Arn)/*" ] } ]
-
Once the role is created, you can pass it into your application for the resource that it applies to. For example, if the name of the role created for
LambdaStack/Handler/ServiceRole
islambda-service-role
, you would update your CDK app as follows:const stack = new Stack(app, 'LambdaStack'); // Add this to pass in the role iam.Role.customizeRoles(stack, { usePrecreatedRoles: { 'LambdaStack/Handler/ServiceRole': 'lambda-service-role', }, });
The CDK will now use the pre-created role name anywhere that the role is referenced in the CDK application. It will also continue to generate the report so that any future policy changes can be referenced.
You will notice that the reference to the Amazon S3 bucket ARN in the report is rendered as (
LambdaStack/Bucket/Resource.Arn
) instead of the actual ARN of the bucket. This is because the bucket ARN is a deploy time value that is not known at synthesis (the bucket hasn’t been created yet). This is another example of why we recommend allowing CDK to manage IAM roles and permissions by using the providedgrant
methods. In order to create the role with the initial policy, the admin will have to create the policy with broader permissions (for example,arn:aws:s3:::*
).