Cross-account roles are fundamental to building secure, scalable multi-account AWS environments. Instead of creating duplicate users or credentials in every account, you leverage IAM roles to grant specific permissions to principals (users, roles, or services) residing in other AWS accounts. The core mechanism here is the sts:AssumeRole API call. Account A, the "assuming account," grants a principal (e.g., an IAM user or role) the permission to call sts:AssumeRole. Account B, the "trusting account," defines an IAM role with a trust policy that explicitly allows principals from Account A to assume it. Once assumed, the principal temporarily inherits the permissions defined in the trusting account's role, enabling delegated access without sharing long-lived credentials. This pattern is crucial for centralized security operations, shared services, and partner integrations.
The trust policy is the critical component defining who can assume a role. It's a resource-based policy attached directly to the role, specifying Principal elements that are permitted to invoke sts:AssumeRole on that role. This Principal can be an entire AWS account, specific IAM users, services, or, crucially, other IAM roles (e.g., arn:aws:iam::111122223333:role/MyAnotherRole). When a role's trust policy specifies another role as its Principal, you enable assume-role chains. An entity (user or role) assumes Role A, then uses Role A's temporary credentials to assume Role B, and potentially Role C, creating a secure, multi-step privilege escalation or access path. This chaining is powerful for advanced security architectures, allowing for "break-glass" scenarios where higher privileges are only accessed through an auditable, multi-step process, or for compartmentalizing access across different functional accounts.
For Cloud Architects, mastering cross-account roles, assume-role chains, and trust policies is non-negotiable for designing robust multi-account strategies. Proper configuration ensures adherence to the principle of least privilege, as permissions are granted only when necessary and often for limited durations (via role session duration). CloudTrail logs provide comprehensive audit trails, tracking not only which role was assumed but also the original caller who initiated the AssumeRole operation, even through a chain. Practical considerations include using ExternalId in trust policies for third-party access to prevent the confused deputy problem and carefully managing MaxSessionDuration to enforce temporary access. These mechanisms are the backbone of secure inter-account communication and delegated administration in AWS.
Key Takeaways
- Cross-account roles facilitate secure, delegated access across AWS accounts using
sts:AssumeRole. - A role's trust policy explicitly defines which principals (accounts, users, roles) are allowed to assume it.
- Assume-role chains enable multi-step privilege escalation or access paths by having one role assume another.
- CloudTrail provides complete auditability, showing the original caller through any assume-role chain.
- Design with least privilege,
ExternalIdfor third parties, and appropriate session durations.
Code Example
# IAM Role for cross-account access or assume-role chain
MyCrossAccountRole:
Type: AWS::IAM::Role
Properties:
RoleName: MyCrossAccountRoleExample
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
- arn:aws:iam::111122223333:root # Allow account 111122223333 to assume this role
- arn:aws:iam::444455556666:role/AnotherAccountRole # Or allow a specific role from account 444455556666
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: "my-secure-external-id" # Recommended for third-party access
Path: "/"
Policies:
- PolicyName: MyCrossAccountPermissions
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: s3:GetObject
Resource: arn:aws:s3:::my-secure-bucket/*How this code works
This code defines an IAM role, MyCrossAccountRole, designed to allow other AWS accounts or specific roles to temporarily gain its permissions. This is fundamental for building secure cross-account access or setting up assume-role chains where one role assumes another. The AssumeRolePolicyDocument is the crucial "trust policy" that dictates who is allowed to assume this role. Within its Principal section, it explicitly lists either an entire AWS account (arn:aws:iam::111122223333:root) or a particular role from another account (arn:aws:iam::444455556666:role/AnotherAccountRole). The Action: sts:AssumeRole is the specific API call permitted. A vital security measure, especially for third-party access, is the Condition block requiring a matching sts:ExternalId, preventing confused deputy attacks by ensuring the caller intended to assume this specific role.
Once a trusted entity successfully assumes MyCrossAccountRole, they then inherit the permissions defined in the Policies section. Here, the MyCrossAccountPermissions policy grants the assumed role the ability to perform s3:GetObject actions on my-secure-bucket/*, allowing it to read objects from that S3 bucket. A subtle but important distinction is understanding that the AssumeRolePolicyDocument only controls who can assume the role, while the separate Policies section defines what the role can do after it's been assumed. Without both, the role would either be unassumable or have no useful permissions.