IAM Principal Examples in AWS CDK - Complete Guide

avatar
Borislav Hadzhiev

Last updated: Jan 26, 2024
5 min

banner

# 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-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 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 sample:

  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 deploy our app:

shell
npx aws-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-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 role with an AWS Account principal const role2 = new iam.Role(this, 'role-2', { assumedBy: new iam.AccountPrincipal(cdk.Stack.of(this).account), }); } }

We instantiated the AccountPrincipal class and passed it an account id. We used 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 running 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-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 role with an Account Root Principal const role3 = new iam.Role(this, 'role-3', { assumedBy: new iam.AccountRootPrincipal(), }); } }

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`, ), });

We 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-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 with Any Principal const policy2 = new iam.PolicyStatement({ resources: ['*'], actions: ['s3:*'], effect: iam.Effect.DENY, principals: [new iam.AnyPrincipal()], }); } }

We 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-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 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, }, }, ), }); } }

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 aws-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-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 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, run the destroy command.

shell
npx aws-cdk destroy

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev