Managed Policy Examples in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Tue Apr 27 20215 min read

In order to create a managed policy in CDK we have to instantiate the `ManagedPolicy` class and pass it at least 1 policy statement.

Table of Contents #

  1. Creating a Managed Policy in AWS CDK
  2. Attaching Managed Policies on IAM Entities in AWS CDK
  3. Adding Policy Statements to a Managed Policy in AWS CDK
  4. Importing Managed Policies in AWS CDK

Managed Policies in AWS CDK #

Policies in AWS define the permissions, that allow or deny access to resources.

Managed policies can be reused on multiple IAM entities, as opposed to inline Policies, which are only applied to a single entity.

In this article we are going to go over examples of AWS managed and Customer managed policies.

Creating a Managed Policy in AWS CDK #

In order to create a managed policy in CDK, we have to instantiate the ManagedPolicy class and pass it one or more policy statements.

The code for this article is available on GitHub

Let's look at a simple example where we create a managed policy and attach it to an IAM role:

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 Role
    const role = new iam.Role(this, 'iam-role-id', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
      description: 'An example IAM role in AWS CDK',
    });

    // ๐Ÿ‘‡ Create a Managed Policy and associate it with the role
    const managedPolicy = new iam.ManagedPolicy(this, 'managed-policy-id', {
      description: 'Allows ec2 describe action',
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ['ec2:Describe'],
          resources: ['*'],
        }),
      ],
      roles: [role],
    });
  }
}

Let's go over what we did in the code snippet.

  1. we created an IAM role by instantiating the Role construct. We've set the lambda service as the principal of the role.

  2. we created a managed policy by instantiating the ManagedPolicy class. The props we've passed are:

  • description - a short description of the managed policy
  • statements - a list of PolicyStatement instances. Note that the effect for policy statements is set to ALLOW by default, so in our case we could have omitted the property.
  • roles - a list of roles to attach the managed policy to

Let's execute a deployment:

shell
npx cdk deploy

After a successful deployment, we can see that the managed policy has been attached to the role:

managed policy attached role

Attaching Managed Policies on IAM Entities in AWS CDK #

The code for this article is available on GitHub

In order to attach a managed policy to an IAM entity, after the entity has been created, we have to use the addManagedPolicy method. This method is available on instances of the Role, User and Group classes.

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 group and pass it an AWS Managed Policy
    const group = new iam.Group(this, 'group-id', {
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonS3ReadOnlyAccess'),
      ],
    });

    // ๐Ÿ‘‡ add a managed policy to a group after creation
    group.addManagedPolicy(managedPolicy);
  }
}

Let's go over what we did in the code snippet.

  1. we created a group, by instantiating the Group construct. We also imported an AWS managed policy and set it on the group.
  2. we used the addManagedPolicy method on the group instance to attach the managed policy to the group.

Let's execute a deployment:

shell
npx cdk deploy

If we take a look at the group we created, we can see that both of our managed policies are attached:

managed policy attached group

An alternative way to attach a managed policy to an IAM entity is to use the attachTo* methods on instances of the ManagedPolicy 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 User
    const user = new iam.User(this, 'example-user', {
      userName: 'example-user',
    });

    // ๐Ÿ‘‡ attach the managed policy to a User
    managedPolicy.attachToUser(user)
  }
}

In the code snippet we created an IAM user and attached a managed policy to it, using the attachToUser method.

Adding Policy Statements to a Managed Policy in AWS CDK #

The code for this article is available on GitHub

In order to add policy statements to a managed policy in CDK, we have to use the addStatements method on a managed policy instance.

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

    // ๐Ÿ‘‡ add policy statements to a managed policy
    managedPolicy.addStatements(
      new iam.PolicyStatement({
        actions: ['sqs:GetQueueUrl'],
        resources: ['*'],
      }),
    );
  }
}

In the code snippet we've used the addStatements method on a managed policy instance. The method takes PolicyStatement instances.

Let's execute a deployment:

shell
npx cdk deploy

If we look at the managed policy we provisioned, we can see that the sqs:GetQueueUrl action is also permitted on all resources:

added managed policy statements

Importing Managed Policies in AWS CDK #

In order to import managed policies in AWS CDK, we have to use the from* static methods on the ManagedPolicy construct:

The code for this article is available on GitHub

Let's start with an example where we import an AWS managed policy:

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

    // ๐Ÿ‘‡ Import an AWS Managed policy
    const lambdaManagedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName(
      'service-role/AWSLambdaBasicExecutionRole',
    );

    console.log('managed policy arn ๐Ÿ‘‰', lambdaManagedPolicy.managedPolicyArn);
  }
}

In the code snippet we've used the fromAwsManagedPolicyName static method on the ManagedPolicy class.

Note that we prefixed the policy name with service-role/. Some managed policy names have to be prefixed with service-role/, others with job-function/ and others don't have a prefix. The prefix should always be included for the managed policies that have one, otherwise we'd get an error.

The easiest way to see if a managed policy has a prefix is to look at the ARN of the policy, for example:

lambda managed policy arn

In the screenshot we can see that the managed policy ARN includes a service-role/ prefix, which we should specify in the parameter passed to fromAwsManagedPolicyName.

In order to import external customer managed policies we have to use the fromManagedPolicyName or fromManagedPolicyArn static methods:

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

    // ๐Ÿ‘‡ Import a Customer Managed Policy by Name
    const customerManagedPolicyByName = iam.ManagedPolicy.fromManagedPolicyName(
      this,
      'external-policy-by-name',
      'YOUR_MANAGED_POLICY_NAME',
    );

    // ๐Ÿ‘‡ Import a Customer Managed Policy by ARN
    const customerManagedPolicyByArn = iam.ManagedPolicy.fromManagedPolicyArn(
      this,
      'external-policy-by-arn',
      'YOUR_MANAGED_POLICY_ARN',
    );
  }
}

The third parameter we pass to the fromManagedPolicyName static method is the name of the external managed policy we want to import.

The third parameter of the fromManagedPolicyArn static method is the ARN of the external managed policy we want to import.

Clean up #

To delete the provisioned resources, execute the destroy command:

shell
npx cdk destroy

Further Reading #

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