IAM Principal Examples in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Wed Apr 28 20215 min read

A complete set of examples of how to specify different Principal types in AWS CDK.

Table of Contents #

  1. Service Principal Example in AWS CDK
  2. Account Principal Example in AWS CDK
  3. Root Account Principal Example in AWS CDK
  4. ARN Principal Example in AWS CDK
  5. Any Principal Example in AWS CDK
  6. Principal With Conditions Example in AWS CDK
  7. Web Identity Principal Example in AWS CDK
  8. Federated Principal Example in AWS CDK
  9. Organization Principal Example in AWS CDK

IAM Principal Examples in AWS CDK #

A principal is an IAM entity, that can assume a role and take on its associated permissions.

Principals can be:

  • an AWS service
  • an IAM role
  • an IAM user
  • an AWS account
  • federated users (i.e. cognito, google, facebook, etc)

Let's look at concrete examples, starting with service principals.

Service Principal Example in AWS CDK #

A service principal is an IAM principal that represents an AWS service.

The code for this article is available on GitHub

In order to create a service principal in AWS CDK, we have to instantiate the ServicePrincipal 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);

    // ๐Ÿ‘‡ Create a role with a Service Principal
    const role1 = new iam.Role(this, 'role-1', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
    });

    const policy1 = new iam.PolicyStatement({
      resources: ['arn:aws:logs:*:*:log-group:/aws/lambda/*'],
      actions: ['logs:FilterLogEvents'],
    });
    // ๐Ÿ‘‡ add a service principal to the policy
    policy1.addServicePrincipal('ec2.amazonaws.com');
  }
}

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

  1. we created a role and set the lambda service as the principal, which can assume the role
  2. we created a policy statement and added the ec2 service as the principal, which can assume the role

Let's execute a deployment:

shell
npx cdk deploy

After a successful deployment we can look at the trust relationship of the IAM role and see that the lambda service is the only trusted entity:

service principal

Account Principal Example in AWS CDK #

In order to specify an account principal in AWS CDK, we have to instantiate the AccountPrincipal class and pass it an account id.

The code for this article is available on GitHub
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 role with an AWS Account principal
    const role2 = new iam.Role(this, 'role-2', {
      assumedBy: new iam.AccountPrincipal(cdk.Stack.of(this).account),
    });
  }
}

In the code snippet we instantiated the AccountPrincipal class and passed it an account id. In this case we specified the account id that was used to deploy the CDK stack, however you can simply pass in any account id you desire, i.e. 123456789.

After executing the deploy command, we can see that the account number is set as the trusted entity.

account principal

Root Account Principal Example in AWS CDK #

The root account principal specifies the account, into which a stack is deployed as the principal entity.

In order to create a root account principal in AWS CDK, we have to instantiate the AccountRootPrincipal class.

The code for this article is available on GitHub
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 role with an Account Root Principal
    const role3 = new iam.Role(this, 'role-3', {
      assumedBy: new iam.AccountRootPrincipal(),
    });
  }
}

In the code snippet we instantiated the AccountRootPrincipal class to set the account into which the stack is deployed as the principal entity.

ARN Principal Example in AWS CDK #

In order to specify a principal by the Amazon Resource Name (ARN), we have to instantiate the ArnPrincipal class.

ARN principals can be:

  • AWS accounts
  • IAM users
  • IAM roles
  • federated SAML users

Let's look at an example where we set a user principal by the ARN:

lib/cdk-starter-stack.ts
// ๐Ÿ‘‡ create a role with an ARN Principal
const role4 = new iam.Role(this, 'role-4', {
  assumedBy: new iam.ArnPrincipal(
    `arn:aws:iam::${cdk.Stack.of(this).account}:user/YOUR_USER_NAME`,
  ),
});

In the code snippet we've created a role that sets an IAM user, by the ARN, as the trusted entity.

Any Principal Example in AWS CDK #

The any principal represents all identities in all accounts.

The code for this article is available on GitHub

In order to specify any principal in AWS CDK, we have to instantiate the AnyPrincipal 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 with Any Principal
    const policy2 = new iam.PolicyStatement({
      resources: ['*'],
      actions: ['s3:*'],
      effect: iam.Effect.DENY,
      principals: [new iam.AnyPrincipal()],
    });
  }
}

In the code snippet we've created a policy with any principal. This policy applies to all identities in all accounts.

Principal With Conditions Example in AWS CDK #

A principal with conditions is an IAM principal, where conditions we've set specify when the policy is in effect.

The code for this article is available on GitHub

In order to create a principal with conditions in AWS CDK, we have to instantiate the PrincipalWithConditions 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 role with PrincipalWithConditions
    const role4 = new iam.Role(this, 'role-4', {
      assumedBy: new iam.PrincipalWithConditions(
        new iam.AccountRootPrincipal(),
        {
          Bool: {
            'aws:MultiFactorAuthPresent': true,
            'aws:SecureTransport': true,
          },
          NumericLessThan: {
            'aws:MultiFactorAuthAge': 300,
          },
        },
      ),
    });
  }
}

In the code snippet we instantiated the PrincipalWithConditions class. The constructor takes 2 parameters:

  1. principal - the principal
  • conditions - a map of conditions, under which the policy takes effect. In our case the conditions verify that the user authenticated via MFA within the past 300 seconds.

Let's execute a deployment:

shell
npx cdk deploy

After a successful deployment, we can see that the conditions have been applied in the trust policy of the role:

principal conditions

Web Identity Principal Example in AWS CDK #

A web identity principal represents a federated identity provider as Web Identity, i.e. Cognito, Facebook, Google, etc.

In order to create a web identity principal in CDK, we have to instantiate the WebIdentityPrincipal class.

lib/cdk-starter-stack.ts
// ๐Ÿ‘‡ create a role with WebIdentityPrincipal
const role5 = new iam.Role(this, 'role-5', {
  assumedBy: new iam.WebIdentityPrincipal(
    'cognito-identity.amazonaws.com',
    {
      StringEquals: {
        'cognito-identity.amazonaws.com:aud': identityPool.ref,
      },
      'ForAnyValue:StringLike': {
        'cognito-identity.amazonaws.com:amr': 'authenticated',
      },
    },
  ),
});

The WebIdentityPrincipal constructor takes the following parameters:

  1. identityProvider - the name of the identity provider - in our case cognito
  2. conditions - conditions, under which the policy takes effect

Federated Principal Example in AWS CDK #

A federated principal represents a federated identity provider, i.e. cognito, that can be used to provide temporary security credentials to authenticated users.

In order to create a federated principal in CDK, we have to instantiate the FederatedPrincipal class.

lib/cdk-starter-stack.ts
// ๐Ÿ‘‡ create a role with FederatedPrincipal
const role6 = new iam.Role(this, 'role-6', {
  assumedBy: new iam.FederatedPrincipal(
    'cognito-identity.amazonaws.com',
    {
      StringEquals: {
        'cognito-identity.amazonaws.com:aud': identityPool.ref,
      },
      'ForAnyValue:StringLike': {
        'cognito-identity.amazonaws.com:amr': 'authenticated',
      },
    },
    'sts:AssumeRoleWithWebIdentity',
  ),
});

The FederatedPrincipal constructor takes the following parameters:

  1. federatedIdentityProvider - the federated identity provider
  2. conditions - conditions, under which the policy takes effect
  3. assumeRoleAction - the action to use when the principal is used in an AssumeRole policy

Organization Principal Example in AWS CDK #

An organization principal represents an AWS organization.

In order to specify an organization as a principal, we have to instantiate the OrganizationPrincipal class.

The code for this article is available on GitHub
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 role with an OrganizationPrincipal
    const role7 = new iam.Role(this, 'role-7', {
      assumedBy: new iam.OrganizationPrincipal('o-123asdf'),
    });
  }
}

The only parameter the OrganizationPrincipal constructor takes is the unique identifier of the organization.

Clean up #

To delete the resources we've provisioned, 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