Identity and Access Management (IAM)
Relevant source files
The following files were used as context for generating this wiki page:- packages/@aws-cdk/aws-iam/README.md
- packages/@aws-cdk/aws-iam/lib/role.ts
- packages/@aws-cdk/aws-iam/lib/policy.ts
- packages/@aws-cdk/aws-iam/lib/grant.ts
- packages/@aws-cdk/aws-iam/lib/principals.ts
- packages/@aws-cdk/aws-iam/package.json
- packages/@aws-cdk/aws-appsync/README.md
- packages/@aws-cdk/aws-config/lib/rule.ts
The @aws-cdk/aws-iam module provides constructs for defining and managing AWS Identity and Access Management (IAM) resources. Its primary purpose is to simplify the process of assigning correct and minimal IAM permissions for resources within a CDK application. The library offers high-level abstractions for creating roles, policies, users, and groups, and includes powerful mechanisms for granting permissions automatically.
A core feature of the AWS CDK's approach to IAM is the grant* method pattern. Many high-level CDK constructs include these methods (e.g., table.grantReadData(role)), which automatically generate and attach the necessary IAM policy statements. This allows developers to focus on the interactions between resources, while the CDK handles the underlying permission management, adhering to the principle of least privilege.
Principals and Identities
In the context of the @aws-cdk/aws-iam library, it's important to distinguish between a Principal and an Identity.
- Principal: An entity that can be granted permissions. This can be an AWS Service, a user, a role, or a more abstract concept like all users in an account. Principals are represented by classes derived from
iam.PolicyPrincipal. - Identity: A specific IAM entity that can have a policy attached to it. This includes
Role,User, andGroupconstructs, which all implement theIIdentityinterface.
Sources: packages/@aws-cdk/aws-iam/README.md
Principal Types
The library provides various classes to represent different types of principals, which are used in resource policies and role trust policies (assumedBy).
| Principal Class | Description | Example Usage |
|---|---|---|
ServicePrincipal | Represents an AWS service. | new iam.ServicePrincipal('ec2.amazonaws.com') |
AccountPrincipal | Represents a specific AWS account. | new iam.AccountPrincipal('123456789012') |
ArnPrincipal | Represents any principal specified by an ARN. | new iam.ArnPrincipal('arn:aws:iam::123456789012:role/MyRole') |
AccountRootPrincipal | Represents the root user of the current account. | new iam.AccountRootPrincipal() |
CompositePrincipal | A principal that is composed of multiple other principals. | new iam.CompositePrincipal(p1, p2) |
WebIdentityPrincipal | A principal for web identities (e.g., Cognito, Google). | new iam.WebIdentityPrincipal('cognito-identity.amazonaws.com') |
SamlPrincipal | A principal for a SAML provider. | new iam.SamlPrincipal(provider, conditions) |
AnyPrincipal | Represents all principals ("AWS": "*"). | new iam.AnyPrincipal() |
Sources: packages/@aws-cdk/aws-iam/README.md, packages/@aws-cdk/aws-iam/lib/principals.ts
The following diagram illustrates the relationship between key IAM interfaces and classes.
This diagram shows that IIdentity extends IPrincipal and IGrantable. Concrete classes like Role, User, and Group implement IIdentity, making them both principals and grantable entities. Other principal types like ServicePrincipal implement IPrincipal directly.
Sources: packages/@aws-cdk/aws-iam/lib/role.ts, packages/@aws-cdk/aws-iam/lib/grant.ts, packages/@aws-cdk/aws-iam/lib/principals.ts
Roles
Roles are a central part of IAM, defining a set of permissions that can be assumed by trusted principals. The CDK automates much of the role creation and management process.
Creating and Using Roles
A new role can be created by instantiating the iam.Role class. The assumedBy property is mandatory and specifies the principal that is allowed to assume the role.
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'),
description: 'This is a custom role...',
});
Sources: packages/@aws-cdk/aws-iam/README.md
Many CDK constructs that require a role will create one automatically if not provided. Permissions are then added to this role as you grant access to other resources.
Importing Existing Roles
You can import a pre-existing IAM role into your CDK application using its ARN with the Role.fromRoleArn method. By default, imported roles are mutable, meaning the CDK can attach new policies to them. To prevent modifications, set the mutable option to false.
const role = iam.Role.fromRoleArn(this, 'Role', 'arn:aws:iam::123456789012:role/MyExistingRole', {
mutable: false,
});
Sources: packages/@aws-cdk/aws-iam/README.md
Opting Out of Automatic Permissions
In some cases, you may want to manage a role's policies manually and prevent the CDK from automatically adding permissions. This can be achieved by passing an immutable view of the role to constructs using the role.withoutPolicyUpdates() method.
const role = new iam.Role(this, 'Role', {
assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'),
});
new codepipeline.Pipeline(this, 'Pipeline', {
// Give the Pipeline an immutable view of the Role
role: role.withoutPolicyUpdates(),
});
// You are now responsible for managing the Role's policies
role.addToPolicy(new iam.PolicyStatement({
actions: ['s3:GetObject'],
resources: ['arn:aws:s3:::my-bucket/*'],
}));
Sources: packages/@aws-cdk/aws-iam/README.md
Policies and Permissions
Permissions are defined using PolicyStatement objects, which are then collected into Policy or ManagedPolicy constructs and attached to IAM identities.
Policy Statements
A PolicyStatement is the fundamental building block of an IAM policy. It defines an effect (Allow or Deny), a set of actions, and the resources to which they apply.
const statement = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:ListBucket'],
resources: [myBucket.bucketArn],
});
Sources: packages/@aws-cdk/aws-iam/lib/policy.ts
Managed and Inline Policies
Policies can be attached to roles, users, or groups.
- Inline Policies: Created using
role.addToPolicy(statement). These policies are embedded directly within the identity. - Managed Policies: Standalone policies that can be attached to multiple identities. They can be created from AWS-managed policies or as custom
ManagedPolicyconstructs.
// Attach an inline policy
role.addToPolicy(new iam.PolicyStatement({
actions: ['dynamodb:GetItem'],
resources: [myTable.tableArn],
}));
// Attach an AWS-managed policy
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'));
Sources: packages/@aws-cdk/aws-iam/README.md, packages/@aws-cdk/aws-config/lib/rule.ts:320-322
Permissions Boundaries
A Permissions Boundary is an advanced feature that sets the maximum permissions an identity can have. It is a managed policy attached to a role or user. The effective permissions are the intersection of the identity's policies and its permissions boundary. This is used to prevent privilege escalation.
You can apply a permissions boundary to a specific construct or to all constructs within a scope (like a stack).
// Import an existing boundary policy
const boundary = iam.ManagedPolicy.fromManagedPolicyArn(this, 'Boundary', 'arn:aws:iam::123456789012:policy/boundary');
// Apply the boundary to all Roles in a stack
iam.PermissionsBoundary.of(stack).apply(boundary);
// Apply the boundary directly to a Role
iam.PermissionsBoundary.of(role).apply(boundary);
Sources: packages/@aws-cdk/aws-iam/README.md
Granting Permissions
The CDK provides a high-level, intent-based mechanism for granting permissions via grant() methods. These methods are available on many resource constructs and simplify the process of connecting resources.
The grant() Pattern
The grant() methods accept an IGrantable object (which Role, User, and Group implement) and automatically create and attach the necessary PolicyStatement.
The following diagram shows the flow of a grant() call.
This flow demonstrates how a single high-level call translates into a correctly configured IAM policy, abstracting the details from the developer.
Sources: packages/@aws-cdk/aws-iam/README.md, packages/@aws-cdk/aws-iam/lib/grant.ts
Specific vs. Generic Grants
There are two main types of grant methods:
- Specific
grant*methods: e.g.,table.grantReadData(principal). These grant a predefined set of permissions for a common use case. - Generic
grant()method: e.g.,table.grant(principal, 'dynamodb:PutItem', 'dynamodb:UpdateItem'). This allows granting a specific, custom set of actions.
// Specific grant for write access
table.grantWriteData(fn);
// Generic grant for a specific action
table.grant(fn, 'dynamodb:PutItem');
Sources: packages/@aws-cdk/aws-iam/README.md
Granting Permissions for AppSync
The grant() pattern is powerful for services with complex authorization, like AWS AppSync. You can grant access to specific parts of your GraphQL API, such as a particular mutation field.
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
const api = new appsync.GraphqlApi(stack, 'API', {
// ...
});
// Grant permission to invoke a specific mutation
api.grant(role, appsync.IamResource.custom('types/Mutation/fields/updateExample'), 'appsync:GraphQL');
// Or use a helper method
api.grantMutation(role, 'addTest');
Sources: packages/@aws-cdk/aws-appsync/README.md, packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.ts:100-102
Identity Providers
The IAM module supports configuration for external identity providers using OpenID Connect (OIDC) and SAML 2.0, enabling federated access to AWS resources.
OpenID Connect (OIDC) Providers
OIDC providers describe an external IdP service (like Google or a Cognito Identity Pool) that supports the OIDC standard. This allows you to establish trust between the IdP and your AWS account.
const provider = new iam.OpenIdConnectProvider(this, 'MyProvider', {
url: 'https://openid/connect',
clientIds: [ 'myclient1', 'myclient2' ],
});
// Use the provider to create a principal for a role's trust policy
const principal = new iam.WebIdentityPrincipal(provider, {
StringEquals: { 'cognito-identity.amazonaws.com:aud': 'cognito-pool-id' }
});
Sources: packages/@aws-cdk/aws-iam/README.md
SAML Providers
SAML 2.0 identity providers describe an external IdP (like Active Directory Federation Services) that supports the SAML 2.0 standard. You can create a SamlProvider by supplying the provider's metadata document.
const provider = new iam.SamlProvider(this, 'Provider', {
metadataDocument: iam.SamlMetadataDocument.fromFile('/path/to/saml-metadata-document.xml'),
});
// Use the SAML principal in a role's trust policy
new iam.Role(this, 'Role', {
assumedBy: new iam.SamlConsolePrincipal(provider),
});
Sources: packages/@aws-cdk/aws-iam/README.md
Conclusion
The @aws-cdk/aws-iam construct library provides a comprehensive and developer-friendly toolkit for managing permissions in an AWS CDK application. It successfully abstracts the complexity of IAM through high-level constructs and the grant() pattern, which promotes the principle of least privilege by default. While providing powerful automation, it retains the flexibility for developers to import existing resources, manage policies manually, and configure advanced features like permissions boundaries and federation when necessary. This makes it a cornerstone of secure and scalable infrastructure definition with the AWS CDK.