Let a principal in one account act in another
Choose between assuming a role in the target account and a resource policy that names the caller, then make the changes in both accounts in the right order and test each side separately.
markdownguidev44E07-5KSHstage: buildtrust: officialtrust: fieldservice: iamservice: stsinterface: cliinterface: sdkinterface: iaccross-account accesscross-account roleassume role in another accountsource_profilerole_arnresource policy cross-accountExternalId
Cross-account access needs an allow on both sides, and each side is a different account's change. Below, the caller account is where the identity lives and the target account is where the resources are. Decide which path you need, then make the target-side change first so the caller-side change can be tested immediately.
1. Choose the path
| Path | Use when | What you configure |
|---|---|---|
| A. Assume a role in the target account | The caller needs several resources or services in the target account, or the resource type has no resource policy | Target: a role with a trust policy naming the caller. Caller: permission to sts:AssumeRole on that role |
| B. Resource policy naming the caller | One resource that supports a resource policy (a bucket, queue, secret, key), and the caller should keep its own identity | Target: the resource policy names the caller. Caller: its identity policy allows the action on the target ARN |
Path A is the general answer. After assuming the role, the caller acts as the role inside the target account, so the role's own permissions policies govern access there and no per-resource policy is needed.
2. Path A, target account: create the role
Trust policy naming the caller. Name a specific role in the caller account rather than the whole account where you can:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<caller-account-id>:role/<caller-role>" },
"Action": "sts:AssumeRole"
}]
}
aws iam create-role --role-name <target-role> --assume-role-policy-document file://trust.json
aws iam attach-role-policy --role-name <target-role> --policy-arn <permissions policy ARN>
- Naming the account (
"AWS": "<caller-account-id>"or its:rootARN, which are equivalent) instead lets that account's administrators decide who may assume the role. - For a third party, require
sts:ExternalIdin the trust policy (patterns/iam/trust-policies.md). - Set the role's maximum session duration if callers need sessions longer than one hour (up to 12).
- If saving fails with
Invalid principal in policy, the caller ARN is malformed, uses a partial wildcard, names a deleted principal, or crosses the GovCloud boundary: seereference/iam/errors.md.
3. Path A, caller account: allow the assume
Attach to the calling identity:
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<target-account-id>:role/<target-role>"
}
Then use it. Simplest for the CLI and SDKs is a profile that assumes the role and refreshes it automatically:
[profile target]
role_arn = arn:aws:iam::<target-account-id>:role/<target-role>
source_profile = <profile holding the caller's credentials>
aws sts get-caller-identity --profile target
The returned ARN should be arn:aws:sts::<target-account-id>:assumed-role/<target-role>/<session-name>. The session name is visible in the target account's CloudTrail. Calling AssumeRole directly from code: reference/sts/assume-role.md.
4. Path B: resource policy plus caller permission
Target account, on the resource:
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<caller-account-id>:role/<caller-role>" },
"Action": ["<service>:<Action>"],
"Resource": "<resource ARN>"
}
Caller account, on the identity: an Allow for the same actions on the same resource ARN. Either half alone is not enough. KMS key policies are an exception to the "either side is enough" rule even within one account: they must name the principal explicitly. If the target data is encrypted with a customer managed key, the key policy is a third policy that must allow the caller; check the service's cross-account documentation.
5. Test each side on its own
- From the caller:
aws sts get-caller-identity(confirms who you are), then the assume or the action. - Read the end of any denial (
guides/iam/fix-access-denied.md):
no role trust policy allows→ target side, step 2.no identity-based policy allows the sts:AssumeRole action→ caller side, step 3.no resource-based policy allows→ target side, step 4.- A service control policy named → the caller's organization caps the principal.
- A resource control policy named → the target's organization caps the resource, and RCPs apply to callers from outside the organization too.
- An
ExpiredTokenlater in a long job means the role session ran out; request a longerDurationSecondswithin the role's maximum, or use the profile form, which refreshes. Role chaining caps the session at one hour.