Study guide
Technical reference and lesson notes
Purpose of This Lesson
Cross-account access allows an identity in one AWS account to access resources owned by another account without sharing long-term credentials between accounts. This lesson demonstrates the standard IAM role pattern for accessing an Amazon S3 bucket across account boundaries.
The example uses:
- Account A: Contains the IAM user
Jack. - Account B: Contains the IAM role and S3 resources.
- AWS STS: Issues temporary credentials when Jack assumes the role in Account B.
The same design applies to IAM roles assumed by users, applications, automation systems, and third-party AWS accounts.
Key Concepts
Cross-account access requires two policy evaluations
A successful cross-account AssumeRole operation requires both sides of the relationship to permit it:
- Identity-based policy in Account A allows Jack to call
sts:AssumeRoleon the specific role in Account B. - Trust policy in Account B allows the designated principal from Account A to assume the role.
- Permissions policy attached to the role in Account B grants access to the target resources, such as an S3 bucket.
A permission granted in only one of these locations is insufficient.
The role trust policy controls who may assume the role
A role in Account B can use a trust policy similar to this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_A_ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "approved-external-id"
}
}
}
]
}
When an AWS account is specified as arn:aws:iam::ACCOUNT_A_ID:root in a trust policy, this refers to principals from that account, not exclusively to the account’s root user. The requesting principal still needs an identity-based policy permitting the role assumption.
For tighter control, the trust policy can identify a specific role or user rather than an entire account, where the design permits it.
The external ID helps prevent the confused deputy problem
The sts:ExternalId condition requires the caller to include a matching value in the AssumeRole request. It is especially useful when granting access to a third-party AWS account that serves multiple customers.
The external ID helps the trusting account distinguish an authorized request for one customer from an unintended request made through the same third party. It should be managed as an integration-specific value and checked in the role trust policy.
It is not a replacement for IAM authentication, authorization, or MFA, and it should not be treated as a general-purpose password.
The role permissions policy grants access to S3
The role in Account B receives the permissions needed to access the bucket. The demonstration attached AmazonS3FullAccess, but production designs should normally use a customer-managed policy restricted to the required bucket and actions.
For example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::example-bucket"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::example-bucket/*"
}
]
}
Bucket-level actions and object-level actions use different ARN formats. s3:ListBucket applies to the bucket ARN, while object operations apply to the object ARN.
AssumeRole returns temporary security credentials
A successful sts:AssumeRole call returns:
- An access key ID
- A secret access key
- A session token
- An expiration time
These credentials represent the assumed role, not the original IAM user. The effective permissions are those granted to the role, subject to applicable permission boundaries, SCPs, resource policies, session policies, and explicit denies.
The AWS CLI can use a named profile for Jack to call sts assume-role, after which the temporary role credentials can be supplied through environment variables or a dedicated CLI profile.
Useful validation commands include:
aws sts get-caller-identity --profile jack
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT_B_ID:role/S3AccessRoleForExternalAccount \
--role-session-name jack-s3-session \
--external-id approved-external-id \
--profile jack
aws sts get-caller-identity is a practical way to confirm whether commands are running as the original user or as the assumed role.
Resource policies may also affect cross-account S3 access
For many S3 designs, the role’s identity policy is the primary permission mechanism. However, S3 bucket policies can also grant or restrict access. A bucket policy is particularly useful when the bucket owner wants explicit resource-level control over external accounts or when enforcing conditions such as TLS, organization membership, VPC endpoints, or required encryption.
Cross-account access must satisfy all applicable policy controls. An explicit deny in an SCP, permissions boundary, identity policy, resource policy, or another policy layer can still block the request.
Exam-Relevant Takeaways
- Cross-account role assumption uses AWS STS
AssumeRoleand temporary credentials. - The trusted account’s identity policy must allow
sts:AssumeRoleon the target role. - The target account’s role trust policy must trust the calling principal or account.
- The role’s permissions policy determines what the caller can do after assumption.
sts:ExternalIdis a key control for third-party access and confused deputy protection.- The account root ARN in a role trust policy represents the account as a principal scope; it does not mean only the root user can assume the role.
- Restrict the caller’s
Resourceto the exact role ARN whenever possible. - Use
aws sts get-caller-identityto verify the active identity and avoid accidentally running commands with an administrator profile. - S3 bucket and object permissions use different resource ARNs.
- Temporary credentials include a session token; omitting it causes authentication failures.
- AWS Organizations SCPs apply to member accounts and can limit the maximum permissions even when IAM policies allow the operation.
Architecture Decision Guide
| Requirement | Recommended design | Important considerations |
|---|---|---|
| A user in Account A needs access to resources in Account B | Create a role in Account B and allow the user to assume it | Configure both the caller policy and role trust policy |
| A third-party SaaS provider needs customer-specific access | Cross-account role with sts:ExternalId condition | Use a unique integration value and least-privilege role permissions |
| An application in Account A needs recurring access | Attach an instance, task, or workload role in Account A that assumes the role in Account B | Avoid embedded access keys; monitor role sessions |
| Only one target role should be assumable | Restrict the caller policy Resource to that role ARN | Avoid Resource: "*" for sts:AssumeRole |
| The bucket owner needs explicit control over an external principal | Add an S3 bucket policy | Check both IAM and bucket policy effects |
| The caller only needs read access to selected objects | Use a custom role policy with limited S3 actions and prefixes | Separate bucket-level and object-level ARNs |
| Strong human-user authentication is required | Add MFA conditions to the trust policy where appropriate | External ID and MFA solve different problems |
Common Exam Traps
- Assuming only the role trust policy is required: The caller also needs an identity policy permitting
sts:AssumeRole. - Treating
arn:aws:iam::ACCOUNT_ID:rootas only the root user: In a trust policy, it establishes trust in the account’s principals, subject to their own permissions. - Using the external ID as a substitute for credentials: The caller must still authenticate to AWS and be authorized to assume the role.
- Forgetting the session token: STS temporary credentials consist of three values, including
AWS_SESSION_TOKEN. - Granting S3 actions against the wrong ARN:
s3:ListBucketrequires the bucket ARN;GetObjectandPutObjectrequire object ARNs. - Granting
AmazonS3FullAccessin production without analysis: It may work for a lab but violates least privilege in many real designs. - Assuming the role automatically bypasses organization controls: SCPs, permission boundaries, and explicit denies still apply.
- Not specifying the CLI profile: Commands may run under the default administrator or CloudShell identity instead of the intended test user.
- Confusing role assumption with direct cross-account user access: The preferred pattern is normally to use a role and temporary credentials rather than create or share credentials across accounts.
Real-World Engineer Notes
- Prefer IAM roles for workloads and federated human access. Long-term access keys for IAM users should be avoided where possible.
- Use AWS IAM Identity Center for workforce access and permission sets when the organization centrally manages users across multiple accounts.
- For third-party integrations, generate and manage external IDs per customer or integration relationship. Do not use one broadly reusable value for unrelated tenants.
- Scope role permissions to exact S3 buckets, prefixes, actions, and encryption requirements. Consider conditions such as
aws:SecureTransport, required server-side encryption, or organization identifiers. - Record role assumption and S3 activity in AWS CloudTrail. Review the role session name and source identity to improve attribution.
- Test both positive and negative cases: valid external ID, invalid external ID, unauthorized role ARN, missing session token, and access outside the permitted S3 prefix.
- Clean up lab IAM users, access keys, policies, roles, and test buckets after practice. Unused access keys are a security risk even when the lab resources themselves are inexpensive.
Quick Reference Summary
- Put the resource-owning role in Account B.
- Configure its trust policy to allow the required principal from Account A.
- Add an
sts:ExternalIdcondition for third-party access when appropriate. - Attach a least-privilege S3 permissions policy to the role.
- In Account A, allow the caller to perform
sts:AssumeRoleon the exact role ARN. - Call
AssumeRoleand include the external ID if required. - Use the returned access key, secret key, and session token.
- Confirm the active identity with
sts get-caller-identity. - Check S3 bucket policies, SCPs, permissions boundaries, and explicit denies if access fails.
Flashcards
1. What AWS API is used to obtain credentials for a cross-account IAM role?
sts:AssumeRole.
2. Which policy determines who can assume an IAM role?
The role’s trust policy, also called its resource-based trust policy.
3. Which policy allows the caller to request role assumption?
An identity-based policy attached to the caller, group, or calling role.
4. What does the assumed role’s permissions policy control?
The AWS actions and resources available after the caller assumes the role.
5. What is the purpose of sts:ExternalId?
It helps protect third-party integrations against the confused deputy problem by requiring a customer- or integration-specific request value.
6. What credentials does AssumeRole return?
A temporary access key ID, secret access key, session token, and expiration time.
7. Does arn:aws:iam::123456789012:root in a trust policy mean only the root user?
No. It represents principals in that AWS account, subject to the caller’s own authorization.
8. Which ARN is used for s3:ListBucket?
The bucket ARN, such as arn:aws:s3:::example-bucket.
9. Which ARN is used for s3:GetObject?
An object ARN, such as arn:aws:s3:::example-bucket/path/file.txt or arn:aws:s3:::example-bucket/*.
10. How can you verify the identity used by the AWS CLI?
Run aws sts get-caller-identity, optionally with a named profile.
Practice Questions
Question 1
An IAM user in Account A must access an S3 bucket in Account B. An administrator creates a role in Account B with the correct S3 permissions and a trust policy allowing Account A. The user still receives AccessDenied when running AssumeRole. What is the most likely missing configuration?
A. An S3 bucket ACL granting the user access
B. An identity policy in Account A allowing sts:AssumeRole on the role ARN
C. An SCP in Account B allowing s3:*
D. An access key created for the role
Correct answer: B
The caller needs an identity-based policy allowing sts:AssumeRole, while the role trust policy provides the reciprocal trust. Role credentials are generated by STS and do not require creating access keys for the role.
Question 2
A company grants a SaaS provider access to a different S3 bucket for each customer. The provider uses one AWS account and serves many customers. Which control best helps prevent the provider from unintentionally accessing the wrong customer’s bucket through its delegated role?
A. Store the provider’s root access key in Secrets Manager
B. Add a unique sts:ExternalId condition to each customer role trust policy
C. Make every bucket public but require HTTPS
D. Use an S3 ACL with the provider’s canonical user ID
Correct answer: B
An external ID in the trust policy helps address the confused deputy problem in third-party delegation. The role should also have least-privilege permissions limited to the intended customer resources.
Question 3
A role has permission to call s3:GetObject on arn:aws:s3:::finance-data/*, but an assumed-role session cannot list the bucket contents. Which change is required if listing is also needed?
A. Add s3:ListBucket against arn:aws:s3:::finance-data
B. Add s3:ListBucket against arn:aws:s3:::finance-data/*
C. Add iam:ListRoles to the S3 role
D. Add sts:GetSessionToken to the bucket policy
Correct answer: A
s3:ListBucket is a bucket-level action and requires the bucket ARN without /*. Object access actions use object ARNs.
Question 4
An operator successfully assumes a cross-account role and receives an access key ID, secret access key, and session token. They configure only the first two values in a shell and receive an authentication error when accessing S3. What is the likely cause?
A. The role trust policy must include the operator’s email address
B. Temporary STS credentials require the session token as well
C. S3 does not support assumed roles
D. The external ID must be used as the secret access key
Correct answer: B
STS temporary credentials require all three credential values. The session token must be supplied through AWS_SESSION_TOKEN or the equivalent CLI configuration.
Question 5
A security team wants a test user in Account A to assume only one role in Account B. Which identity policy design best meets least privilege?
A. Allow sts:AssumeRole on *
B. Allow iam:* on *
C. Allow sts:AssumeRole with the specific role ARN in Account B as the resource
D. Allow s3:* on the bucket in Account B directly
Correct answer: C
The caller should be granted only the sts:AssumeRole action and only on the intended role ARN. The role in Account B should separately define the required S3 permissions.