This chapter covers IAM cross-account role assumptions, a critical mechanism for granting temporary access to resources in one AWS account to users or services in another. For the SAA-C03 exam, understanding cross-account roles is essential for designing secure, multi-account architectures, and approximately 10-15% of exam questions touch on this topic, often in the context of centralized access control, data sharing, or automated cross-account operations. You will learn how roles work across accounts, how to configure trust policies and permissions, and common pitfalls that appear in exam scenarios.
Jump to a section
Imagine a large hotel where each floor is a separate AWS account. A guest staying on the 5th floor (Account A) needs to access the business center on the 10th floor (Account B). However, the 5th floor key card only opens doors on the 5th floor. To access the 10th floor, the guest must first go to the front desk (the IAM role in Account B) and request a temporary key card. The front desk checks the guest's ID (the trust policy) and, if approved, issues a 10th-floor key card that is valid for a limited time (the temporary security credentials). The guest then uses this new key card to open the 10th-floor doors. Importantly, the front desk records that the 5th-floor guest is now authorized on the 10th floor, but the guest never receives a permanent key to the 10th floor. Also, the 5th-floor guest cannot give their 10th-floor key card to someone else because it's tied to their identity and expires. This mirrors AWS cross-account role assumption: a user in Account A assumes a role in Account B, receiving temporary credentials that grant specific permissions, and the trust policy in Account B determines who from Account A is allowed to assume the role.
What is IAM Cross-Account Role Assumption?
IAM cross-account role assumption is a security mechanism that allows a principal (user, group, or service) in one AWS account to obtain temporary credentials to access resources in another AWS account. This is achieved by assuming an IAM role that exists in the target account. The role defines what actions the assuming principal can perform on which resources. This model eliminates the need to create IAM users across multiple accounts or share long-term access keys, enhancing security and auditability.
Why It Exists
In multi-account AWS environments, organizations often isolate workloads for security, billing, or organizational boundaries. However, there are legitimate needs for cross-account access, such as:
Centralized security auditing (e.g., a security account reads CloudTrail logs from all accounts)
Data analytics (e.g., a data lake account reads data from production accounts)
DevOps automation (e.g., a CI/CD pipeline in one account deploys to another)
Backup and disaster recovery
Cross-account roles are the recommended AWS best practice for these scenarios because they provide temporary, scoped credentials that can be revoked at any time by modifying the role's trust policy.
How It Works Internally
The process of assuming a cross-account role uses the AWS Security Token Service (STS). Here is the step-by-step mechanism:
Request Initiation: The principal in Account A calls the AWS STS AssumeRole API, specifying the ARN of the target role in Account B (e.g., arn:aws:iam::123456789012:role/CrossAccountAccessRole). The request includes a session name and optional duration.
Authentication and Authorization: STS verifies that the requesting principal is authenticated (has valid credentials) and authorized to call AssumeRole. This authorization is governed by the IAM policy attached to the principal in Account A. That policy must explicitly allow the sts:AssumeRole action on the target role ARN.
Trust Policy Evaluation: STS then checks the trust policy of the target role in Account B. The trust policy specifies which principals (by account ID, user ARN, or condition) are allowed to assume the role. For cross-account access, the trust policy typically includes "AWS": "arn:aws:iam::AccountA:user/username" or "AWS": "arn:aws:iam::AccountA:root". If the requesting principal matches and any conditions (e.g., MFA, source IP) are satisfied, the trust policy grants permission to assume the role.
Temporary Credential Issuance: Once both policies are satisfied, STS generates a set of temporary security credentials: an access key ID, a secret access key, and a session token. The credentials have a lifetime between 15 minutes and the role's maximum session duration (default 1 hour, maximum 12 hours). The credentials are scoped to the permissions defined by the role's permission policy (plus any session policies passed during the call).
Credential Delivery: STS returns these credentials to the calling principal. The principal can then use them to make API calls to AWS services. The credentials are valid only for the duration specified and cannot be revoked individually (but the role's trust policy can be updated to deny future assumptions).
Key Components
Trust Policy: Attached to the role in the target account. Defines who can assume the role (the principal) and under what conditions. Example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}Permission Policy: Attached to the role in the target account. Defines what actions the assumed role can perform (e.g., read S3 buckets, write to DynamoDB). This is a standard IAM policy.
IAM Policy on the Calling Principal: Must allow sts:AssumeRole on the target role ARN. Example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/CrossAccountRole"
}
]
}Session Name: A required parameter when calling AssumeRole. It appears in CloudTrail logs for auditing. The session name must be unique within the role session and can be used for monitoring.
Duration: The DurationSeconds parameter can range from 900 seconds (15 minutes) to the role's maximum session duration (default 3600 seconds, max 43200 seconds). The role's MaxSessionDuration setting caps this value.
External ID: An optional, unique identifier that the trusting account (Account B) can require to prevent the confused deputy problem. The calling principal must pass the correct external ID when assuming the role.
Configuration and Verification
To configure cross-account role assumption:
In Account B (target), create an IAM role with a trust policy allowing Account A's root or specific user/role.
Attach a permission policy to the role granting the desired access (e.g., read-only S3 access).
In Account A, attach an IAM policy to the user/group/role that allows sts:AssumeRole on the role ARN.
To verify, the user in Account A can use the AWS CLI:
aws sts assume-role --role-arn "arn:aws:iam::222222222222:role/CrossAccountRole" --role-session-name "TestSession"The output includes temporary credentials. The user can then export them as environment variables and make API calls.
Interaction with Related Technologies
AWS Organizations: Cross-account roles are often used with Organizations to manage access across member accounts. Service Control Policies (SCPs) can restrict sts:AssumeRole actions, effectively overriding role trust policies.
AWS Single Sign-On (SSO): AWS SSO automates cross-account role assumption by creating roles in each account and using an identity provider (IdP) to federate users. The SSO service calls AssumeRole on behalf of the user.
IAM Roles Anywhere: Similar cross-account concept but for workloads outside AWS (e.g., on-premises servers) that need temporary credentials.
Resource-Based Policies: Some services (S3, SNS, SQS, Lambda) support resource-based policies that grant cross-account access directly, without needing a role. These are alternatives to cross-account roles for specific use cases.
Security Considerations
Confused Deputy Problem: If Account A has a role that allows service X to assume it, and service X can be triggered by a user in Account B, that user might trick service X into assuming a role that grants unintended access. Use external ID or aws:SourceArn conditions to prevent this.
Permissions Boundary: Can be applied to the role to limit the maximum permissions the role can have.
CloudTrail Logging: All AssumeRole API calls are logged in CloudTrail in both the calling account and the target account, providing an audit trail.
Principal in Account A calls AssumeRole
A user, role, or service in Account A invokes the AWS STS AssumeRole API. The request must include the target role ARN (e.g., arn:aws:iam::222222222222:role/CrossAccountRole) and a session name. Optionally, the caller can specify duration, external ID, and session policies. The caller must have an IAM policy allowing sts:AssumeRole on that specific role ARN. At the protocol level, the request is an HTTPS POST to sts.amazonaws.com. AWS signs the request using the caller's existing credentials. STS receives the request and begins authentication.
STS verifies caller's permissions
STS checks the IAM policy attached to the caller's identity (user or role) in Account A. The policy must explicitly allow the sts:AssumeRole action on the target role ARN. If the policy is missing or denies, STS returns an AccessDenied error. This evaluation happens before checking the target role's trust policy. STS also verifies that the caller's credentials are valid (e.g., not expired, MFA fulfilled if required by the caller's policy).
STS evaluates target role's trust policy
STS retrieves the target role's trust policy from Account B. The trust policy must contain a statement that allows the sts:AssumeRole action for a principal that matches the caller. Typically, the principal is the root user of Account A (arn:aws:iam::111111111111:root) or a specific user/role ARN. Conditions such as MFA, source IP, or external ID are evaluated. If the trust policy does not authorize the caller, STS returns an AccessDenied error. This step ensures the target account explicitly trusts the source account/principal.
STS generates temporary credentials
If both policies allow, STS generates a new set of temporary security credentials. These consist of an Access Key ID, Secret Access Key, and Session Token. The credentials are valid for the requested duration (subject to the role's MaxSessionDuration, default 1 hour, max 12 hours). The permissions of these credentials are the intersection of the role's permission policy and any session policies passed by the caller (if any). If the role has a permissions boundary, that also limits the permissions. STS creates a unique session identifier that appears in CloudTrail logs.
Caller receives and uses temporary credentials
STS returns the temporary credentials to the caller in the API response. The caller can then use these credentials to make subsequent AWS API calls. The caller must include the session token in all requests. The caller can assume the role multiple times, each time receiving a new set of credentials. The credentials cannot be used after they expire. The caller can switch back to their original credentials by discarding the temporary credentials. CloudTrail logs all actions performed with the temporary credentials, showing the assumed role session name.
Enterprise Scenario 1: Centralized Security Auditing
A large enterprise with 50 AWS accounts for different business units (production, development, marketing) needs a single security team to audit all accounts. The security team has a dedicated 'Security' AWS account. In each member account, an IAM role named 'SecurityAuditRole' is created with a trust policy allowing the Security account's root user to assume it. The role is attached to a managed policy like 'SecurityAuditPolicy' that grants read-only access to CloudTrail, Config, S3 bucket policies, and IAM. The security team uses AWS CLI scripts that loop through all account IDs, assume the role, and collect audit data. To handle scale, they use AWS Organizations and the organizations:ListAccounts API to dynamically discover accounts. Performance considerations: Each AssumeRole call takes ~1-2 seconds, so for 50 accounts, the script completes in under 2 minutes. Misconfiguration: If the trust policy accidentally includes "Principal": "*", any AWS account could assume the role, leading to a data breach. The fix is to restrict the principal to the specific security account ARN.
Scenario 2: Cross-Account Data Lake Ingestion
A company uses a data lake account to aggregate data from multiple production accounts. Each production account has an S3 bucket with raw data. The data lake account has an S3 bucket for staging. The data lake account creates a role named 'DataIngestionRole' with permissions to read from the production buckets and write to the staging bucket. The trust policy allows the production accounts' root users to assume this role. The production accounts have a Lambda function that triggers daily, assumes the DataIngestionRole, and copies new data to the staging bucket. This avoids storing long-term keys in Lambda environment variables. Scale: The role may be assumed hundreds of times per day. The role's permission policy uses resource ARNs to restrict access to specific buckets. Common issue: If the Lambda function's execution role in the production account does not have sts:AssumeRole permission on the DataIngestionRole ARN, the assumption fails. The engineer must attach an inline policy to the Lambda role.
Scenario 3: Cross-Account Backup and Disaster Recovery
An organization uses a backup account to store EBS snapshots and RDS backups from all other accounts. In each source account, an IAM role 'BackupRole' is created with permissions to create snapshots and copy them to the backup account. The trust policy allows the backup account's backup automation role to assume it. The backup account runs a scheduled job that assumes the BackupRole in each source account, creates a snapshot, and copies it to a central AMI or snapshot in the backup account. This design ensures that even if a source account is compromised, the backups remain safe in a separate account. Misconfiguration: If the role's permission policy does not include ec2:CopySnapshot to the backup account, the copy fails. The engineer must ensure the role has permissions to copy to the backup account's resources. Also, the backup account must have a resource-based policy on the destination snapshots to allow the source role to copy.
What SAA-C03 Tests
The SAA-C03 exam specifically tests your ability to design cross-account access using IAM roles as the preferred method over resource-based policies where applicable. Key objective codes: Domain 1 (Secure Architectures) Objective 1.1: "Design secure access to AWS resources." Also Domain 2 (Resilient Architectures) Objective 2.2: "Design scalable and loosely coupled architectures" often involves cross-account roles for automation.
Common Wrong Answers
Creating IAM users in the target account: Candidates often think that to give access to a user from another account, you should create a user in the target account. This is wrong because it violates the principle of least privilege and creates credential management overhead. The correct answer is to use an IAM role.
Using resource-based policies when not supported: Some services (e.g., EC2, Lambda) do not support resource-based policies for cross-account access. Candidates might incorrectly choose to attach a resource-based policy to an EC2 instance. The correct approach is to use an IAM role.
Assuming role without proper trust policy: Candidates may forget that the target account's role must have a trust policy explicitly allowing the source account. They might think the source account's policy alone is sufficient. The exam tests that both sides (source policy and target trust policy) are required.
Confusing 'sts:AssumeRole' with 'sts:AssumeRoleWithWebIdentity': The exam may present a scenario with an external identity provider (like Facebook). Candidates might choose a cross-account role, but the correct answer is AssumeRoleWithWebIdentity for web identity federation.
Specific Numbers and Terms
Default session duration: 1 hour (3600 seconds)
Maximum session duration: 12 hours (43200 seconds)
Minimum session duration: 15 minutes (900 seconds)
External ID: used to prevent confused deputy
aws:MultiFactorAuthPresent: condition key for requiring MFA
aws:SourceArn and aws:SourceAccount: condition keys to prevent confused deputy in services
Edge Cases
Chained role assumption: A role in Account A assumes a role in Account B, which then assumes a role in Account C. The exam may ask about the maximum chain length (not explicitly defined, but each assumption adds latency and complexity). The recommended practice is to limit chaining.
Service Control Policies (SCPs): SCPs can deny sts:AssumeRole even if the trust policy allows it. The exam may present a scenario where a user cannot assume a role despite correct policies, and the reason is an SCP.
Permissions boundaries: If the role has a permissions boundary, the effective permissions are the intersection of the boundary and the permission policy. The exam may test this limit.
How to Eliminate Wrong Answers
If the question involves cross-account access to an S3 bucket, consider both resource-based policies (bucket policies) and IAM roles. The exam often expects the simplest solution: bucket policy if the service supports it, otherwise role.
If the question mentions 'temporary credentials', 'federation', or 'no long-term keys', the answer is likely an IAM role.
If the question involves an external IdP (like Active Directory), the answer is IAM identity federation (SAML or web identity), not cross-account role.
Always check if the service supports resource-based policies. If it does (S3, SNS, SQS, Lambda), that might be the answer. If not (EC2, RDS, DynamoDB), you need a role.
Cross-account role assumption uses AWS STS AssumeRole API to obtain temporary credentials.
Both the source account's IAM policy (allow sts:AssumeRole) and the target account's role trust policy (allow the source principal) are required.
Default session duration is 1 hour; maximum is 12 hours; minimum is 15 minutes.
External ID prevents the confused deputy problem; must match exactly if required by trust policy.
Not all services support resource-based policies; for those that don't (EC2, RDS, DynamoDB), use cross-account roles.
Service Control Policies (SCPs) in AWS Organizations can override trust policies and deny role assumption.
CloudTrail logs all AssumeRole calls and subsequent actions with the session name for auditing.
These come up on the exam all the time. Here's how to tell them apart.
Cross-Account IAM Roles
Works for any AWS service (EC2, RDS, Lambda, etc.)
Requires configuration in both accounts (source policy + target trust policy)
Provides temporary credentials with configurable duration
Supports fine-grained conditions (MFA, source IP, external ID)
Auditable via CloudTrail with session name
Resource-Based Policies (e.g., S3 Bucket Policy)
Only works for services that support it (S3, SNS, SQS, Lambda, KMS, Glue, etc.)
Only requires policy in the target account (resource-based policy)
Does not generate temporary credentials; uses the principal's existing credentials
Supports conditions but limited to what the service supports
Auditable but session information may be less detailed
Mistake
Cross-account roles require creating IAM users in the target account.
Correct
No. Cross-account roles do not create any IAM users in the target account. The principal in the source account assumes the role and receives temporary credentials. No permanent user is created in the target account.
Mistake
The source account's policy alone is sufficient to assume a role in another account.
Correct
Both the source account's IAM policy (allowing sts:AssumeRole) and the target account's role trust policy (allowing the source principal) are required. If either is missing, the assumption fails.
Mistake
Temporary credentials from role assumption never expire.
Correct
Temporary credentials have a configurable expiration (15 minutes to 12 hours). After expiration, they cannot be used. The principal must assume the role again to get new credentials.
Mistake
You can assume a cross-account role without passing an external ID if the trust policy requires it.
Correct
If the trust policy includes a condition for an external ID, the caller must provide the exact external ID in the AssumeRole call. Without it, the assumption is denied.
Mistake
Resource-based policies are always simpler than cross-account roles.
Correct
Resource-based policies are simpler for services that support them (S3, SNS, SQS, Lambda, KMS). However, for services that do not (e.g., EC2, DynamoDB), cross-account roles are the only option. The exam tests knowledge of which services support resource-based policies.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Cross-account IAM roles allow a principal in one account to assume a role in another account, receiving temporary credentials. This works for any AWS service but requires configuration in both accounts. Resource-based policies (e.g., S3 bucket policies, SQS queue policies) grant cross-account access directly to the resource without needing a role. They only require a policy in the target account, but only work for services that support them (S3, SNS, SQS, Lambda, KMS, etc.). The exam expects you to choose the simpler option (resource-based policy) when the service supports it.
Yes, if the trust policy does not require an external ID. However, if the trust policy includes a condition for an external ID (e.g., `"StringEquals": { "sts:ExternalId": "abc123" }`), you must provide that exact external ID in the AssumeRole call. The external ID is used to prevent the confused deputy problem when a third party is involved. For direct cross-account access (e.g., Account A to Account B), an external ID is typically not required.
If the trust policy has `"Principal": "*"`, any AWS account (and any user/role within that account) can attempt to assume the role, provided they have the `sts:AssumeRole` permission. This is extremely dangerous and should be avoided. The role's permission policy would then grant access to anyone who assumes it. Always restrict the trust policy to specific accounts or ARNs.
The trust policy can include a condition like `"Bool": { "aws:MultiFactorAuthPresent": "true" }`. The caller must have authenticated with MFA in their own account before calling AssumeRole. The MFA device is associated with the caller's IAM user or role in the source account. The temporary credentials do not carry the MFA status; the condition is evaluated at assumption time.
Yes, you can use roles within the same account, but it is often unnecessary. Cross-account roles are designed for accessing resources in a different account. For same-account access, you typically use the user's existing permissions or switch to a role within the same account (which also uses STS). The exam focuses on cross-account scenarios.
The maximum session duration is 12 hours (43200 seconds). The role's `MaxSessionDuration` setting can be set between 1 hour (default) and 12 hours. The caller can request a shorter duration via the `DurationSeconds` parameter, but cannot exceed the role's maximum. The minimum is 15 minutes (900 seconds).
CloudTrail logs the `AssumeRole` API call in both the source account (as a `AwsApiCall` event) and the target account (as a `AwsApiCall` event). Subsequent actions performed with the temporary credentials are logged in the target account with the `userIdentity` showing the assumed role session (e.g., `arn:aws:sts::222222222222:assumed-role/CrossAccountRole/TestSession`). This provides a complete audit trail.
You've just covered IAM Cross-Account Role Assumptions — now see how well it sticks with free SAA-C03 practice questions. Full explanations included, no account needed.
Done with this chapter?