IAM Policy Examples in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Mon Apr 26 20214 min read

banner

Photo by Mhmd Sedky

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/aws-iam'; import * as cdk from '@aws-cdk/core'; 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've 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've created an IAM role, to which we've attached the policy document.

Let's execute a deployment:

shell
npx 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

In our example we are going to use the fromAwsManagedPolicyName method to import a policy that AWS manages:

lib/cdk-starter-stack.ts
import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; 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've 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/aws-iam'; import * as cdk from '@aws-cdk/core'; 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); } }

In the code snippet we've 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 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 execute the destroy command:

shell
npx cdk destroy

Further Reading #

Add me on LinkedIn

I'm a Web Developer with TypeScript, React.js, Node.js and AWS experience.

Let's connect on LinkedIn

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee