IAM Policy Examples in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Last updated: Apr 14, 2022

banner

Check out my new book

Table of Contents #

  1. Creating IAM Policies in AWS CDK
  2. Using Managed Policies in AWS CDK
  3. Policy Statements Example in AWS CDK

Creating IAM Policies in AWS CDK #

IAM Policies define specific permissions needed to access AWS resources and can be associated with IAM users, roles or groups.

In order to create IAM policies in AWS CDK, we use the Policy constructs, for example:

The code for this article is available on GitHub

Let's start by creating a Policy with the PolicyDocument construct, which takes an array of PolicyStatement instances.

lib/cdk-starter-stack.ts
import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // 👇 Create a Policy Document (Collection of Policy Statements) const filterLogEvents = new iam.PolicyDocument({ statements: [ new iam.PolicyStatement({ resources: ['arn:aws:logs:*:*:log-group:/aws/lambda/*'], actions: ['logs:FilterLogEvents'], // 👇 Default for `effect` is ALLOW effect: iam.Effect.ALLOW, }), ], }); // 👇 Create role, to which we'll attach our Policies const role = new iam.Role(this, 'example-iam-role', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), description: 'An example IAM role in AWS CDK', inlinePolicies: { // 👇 attach the Policy Document as inline policies FilterLogEvents: filterLogEvents, }, }); } }

Let's go over the code snippet:

  1. We used the PolicyDocument class, which takes a statements prop. The statements prop is an array of policy statement instances.

    We passed the following 3 props when instantiating the PolicyStatement class:

    • resources - a list of ARNs of resources to add to the policy statement
    • actions - a list of actions to add to the policy statement
    • effect - whether the actions in the policy statement should be allowed or denied. Note that by default effect is set to ALLOW so we could've skipped passing effect altogether
  2. We created an IAM role, to which we attached the policy document.

Let's run the deploy command:

shell
npx aws-cdk deploy

If we take a look at the permission policy of the role we've created, we can see that the FilterLogEvents policy has been attached to the role:

policy attached to role

Using Managed Policies in AWS CDK #

In order to use managed policies in AWS CDK, we have to use the fromManagedPolicy* methods on the ManagedPolicy construct, for example:

The code for this article is available on GitHub

Let's use the fromAwsManagedPolicyName method to import a policy that AWS manages:

lib/cdk-starter-stack.ts
import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // ... rest // 👇 Use an AWS Managed Policy const managedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName( 'service-role/AWSLambdaBasicExecutionRole', ); // 👇 attach the Managed Policy to the Role role.addManagedPolicy(managedPolicy); } }

Notice that in the call to fromAwsManagedPolicyName method, we prefixed the policy name with service-role/. Some managed policies have a prefix of service-role/, others - job-function/ and others have no prefix at all.

Since we always have to include the prefix along with the policy name, the best way to check if a managed policy has a prefix is to look at its ARN.

managed policy arn

If we take a look at the ARN of the AWSLambdaBasicExecutionRole policy, we can see the service-role/ prefix which we have to include.

Policy Statements Example in AWS CDK #

The code for this article is available on GitHub

In order to create a statement in an IAM Policy, we have to use the PolicyStatement class.

lib/cdk-starter-stack.ts
import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // ... rest // 👇 Create a Policy using the generic Construct const putLogEventsPolicy = new iam.Policy(this, 'cw-logs', { statements: [ new iam.PolicyStatement({ actions: ['logs:PutLogEvents'], resources: ['*'], }), ], }); // 👇 attach the Policy to the role role.attachInlinePolicy(putLogEventsPolicy); // 👇 Create a Policy Statement const createLogStreams = new iam.PolicyStatement({ actions: ['logs:CreateLogGroup', 'logs:CreateLogStream'], resources: ['*'], }); // 👇 Attach policy to Role role.addToPolicy(createLogStreams); } }

We used the Policy and PolicyStatement classes to create IAM Policies. The Policy class takes a statements prop, which is an array of PolicyStatement instances.

Notice how we didn't pass the effect prop when instantiating the PolicyStatement class. The default value for effect is Effect.ALLOW. If you want to override this behavior you should set effect to Effect.DENY.

Let's deploy the updated resources:

shell
npx aws-cdk deploy

If we take a look at the IAM role we've provisioned, we can see that it has 4 permission policies attached to it:

permission policies attached

Clean up #

To delete the resources we've provisioned, run the destroy command:

shell
npx aws-cdk destroy

Further Reading #

Use the search field on my Home Page to filter through my more than 3,000 articles.