CLOUD COMPUTING / TECHNICAL EXPLAINER

AWS SCS-C03: Cross-Account Access Without Static Keys

Cross-account access should normally rely on temporary AWS Security Token Service credentials rather than long-lived access keys copied between accounts. The standard pattern is to […]

In this article

Cross-account access should normally rely on temporary AWS Security Token Service credentials rather than long-lived access keys copied between accounts. The standard pattern is to create an IAM role in the trusting account, define which external principal may assume it through the role trust policy, attach least-privilege permissions to the role, and let the caller use `sts:AssumeRole` to obtain short-lived credentials. This separates identity in the source account from permission in the target account and removes the need to distribute target-account static keys.

The topic maps directly to AWS Certified Security – Specialty (SCS-C03), with SAA-C03 and DOP-C02 providing architecture and automation context.

Create the role in the account that owns the resources

The target, or trusting, account creates an IAM role with permissions to the resources it wants to expose. That role is the permission boundary for cross-account work.

Keep the role focused on one purpose such as reading a data bucket, deploying one application, or querying one service.

Do not make the target role administrator simply because the caller comes from another trusted AWS account.

Use the trust policy to name allowed principals

The role trust policy is a resource-based policy that controls who may call `sts:AssumeRole`. Trust a specific role ARN or well-defined account relationship where possible.

Trusting an entire account delegates the ability to that account’s administrators to decide which identities can assume the role. That may be intentional, but it should be understood.

Use conditions to narrow the trust relationship further when appropriate.

Grant AssumeRole permission in the source account

The source principal also needs identity-based permission to call `sts:AssumeRole` on the target role. Cross-account role assumption therefore depends on both sides of the relationship.

A target trust policy does not automatically give every source user the right to use the role; source-account permissions still matter.

The access-control model is useful: trust and permission are distinct decisions.

Use temporary credentials from STS

When AssumeRole succeeds, STS returns temporary access key ID, secret access key, and session token with an expiration. SDKs and CLI tooling can manage these sessions without storing long-lived target-account credentials.

Short-lived credentials reduce the window of exposure if they leak and simplify revocation because the role trust or permission can be changed centrally.

Applications should refresh sessions through supported credential-provider chains rather than writing tokens to files manually.

Use external IDs for third-party multi-tenant access

When granting a third party access to customer accounts, an external ID helps mitigate the confused-deputy problem by tying role assumption to a value associated with the customer relationship.

The third party supplies the external ID when calling AssumeRole, and the target role trust policy requires the expected value.

AWS explicitly notes that the external ID is not a secret. It is a contextual control, not a replacement for strong principal trust and least privilege.

Use MFA or source conditions for sensitive access

Trust policies can require MFA or other request context for selected human cross-account roles. The approved MFA context helps explain why the second factor strengthens user-driven privileged access.

Other conditions can restrict organization ID, source account, tags, session properties, or network-related context according to supported keys.

Test conditions using the real access path because console, CLI, federated, and third-party clients can supply different context.

Session tags and source identity improve traceability. Session tags can carry attributes such as project, department, environment, or tenant into the assumed session for authorization and audit. Source identity can help preserve who initiated the role session across role chaining where supported.

These values become useful only when they are governed. Do not let callers self-assert privileged tags without controls.

CloudTrail should capture enough session context that investigators can trace target-account API calls back to the source identity.

Prefer workload federation over access keys

CI/CD systems, Kubernetes workloads, GitHub-style OIDC integrations, IAM Identity Center, and cloud workloads can often obtain source-account identity without storing static keys either.

The result is a full temporary-credential chain: external identity or workload federation obtains source credentials, then AssumeRole obtains target-account credentials.

The approved secrets-management context is useful, but the safest static access key is often the one the workload never needs to store.

Use resource policies directly only when they fit

Some AWS services such as S3, SNS, SQS, KMS, and others support resource-based cross-account access. Direct resource policies can be simpler for one narrow resource use case.

Role assumption is usually better when the caller needs a set of permissions across several resources or services and when you want one clear target-account session identity.

Choose the mechanism that creates the clearest least-privilege boundary rather than mixing both patterns unnecessarily.

Audit, expire, and remove trust relationships

Review roles that trust external accounts, unused AssumeRole permissions, stale external IDs, broad principals, and sessions that exceed necessary duration. Cross-account trust should have an owner and business purpose.

The AWS security model works best when account boundaries remain strong but temporary delegation is routine. Roles and STS let teams share capability without copying permanent credentials into every account that needs access.

Account boundaries should be intentional. Separate production, security, shared services, networking, data, and development according to organizational needs, then use role assumption to cross those boundaries rather than sharing one credential everywhere.

A central identity account or IAM Identity Center can provide workforce authentication, while users assume roles into workload accounts. This keeps human identity lifecycle centralized and target permissions local to each account.

Workloads can use the same pattern from an originating role. An application in Account A receives temporary credentials for its local role, then calls STS to assume a narrowly scoped role in Account B.

Role chaining has session-duration limitations and should be designed consciously. If a workload repeatedly chains roles across several accounts, consider whether a more direct trust relationship is simpler and more reliable.

The target role trust policy should name the expected source principal rather than broad root account trust where practical. Specific trust reduces the set of source identities that can ever become eligible.

When account-level trust is necessary for delegation, source-account administrators become part of the target account’s security boundary. Document that governance relationship explicitly.

Organization ID conditions can restrict trust to accounts inside the expected AWS Organization, reducing risk if a referenced account changes ownership or a broad principal is accidentally introduced.

Principal-tag conditions can support ABAC across accounts when tag governance is strong. The source identity and target permissions should agree on which tags are trusted and who may set them.

External IDs are designed for third-party access and confused-deputy mitigation, not as passwords. Generate unique customer-specific values and verify them in the target trust policy while protecting the actual principal relationship separately.

Third-party SaaS providers should document their source account IDs, role naming, external ID process, required permissions, and incident-revocation procedure before receiving access.

MFA is especially appropriate for human-admin role assumption. The trust policy can require MFA context so stolen password-only credentials cannot obtain the privileged target session.

Session policies can narrow one AssumeRole session below the role’s baseline permissions. Broker systems can use them to give one user access to a subset of a broader operational role.

Session tags can drive target-account ABAC, but transitive-tag behavior and tag-session permissions need to be understood when roles are chained.

Source identity can help preserve the original actor through assumed-role sessions and should be standardized for important administrative access paths.

Temporary credentials should remain in memory or supported SDK providers where possible. Avoid writing STS credentials into `.env` files, build artifacts, or shared logs.

SDK credential providers can automatically refresh temporary credentials before expiration, reducing the pressure to create long sessions solely for application convenience.

CI/CD systems should prefer OIDC federation or platform-native identity into the source account, then AssumeRole to targets. This removes long-lived AWS access keys from the pipeline entirely.

GitHub-style OIDC trusts should validate repository, branch, environment, or other token claims so any repository in the provider cannot assume the deployment role.

Kubernetes workloads can use pod or service-account identity patterns instead of node-wide keys. Cross-account target roles should trust the workload role, not an entire cluster node identity, where architecture supports it.

Resource-based policies may be better when a consumer needs one specific S3 bucket, KMS key, SNS topic, or SQS queue. They avoid an extra role session but can scatter trust across many resources if overused.

Centralizing broad access in one cross-account role can be easier to audit, while resource policies can express direct sharing cleanly. Choose one pattern deliberately for each capability.

KMS encryption often requires additional cross-account configuration because both key policy and IAM permission influence use. Test encryption/decryption from the assumed role before declaring the sharing pattern complete.

CloudTrail should record AssumeRole in the target account and later target actions under the role session. Capture session names and source identity in a way security teams can interpret.

Access Analyzer can reveal roles or resource policies trusted by external accounts. Review those findings against approved partnerships and internal account architecture.

Cross-account roles should have expiration at the business-relationship level. When a project or vendor contract ends, remove the trust and source permissions rather than merely asking the caller to stop using them.

The secure outcome is temporary, traceable delegation. No target-account access key is copied, every session expires, the target account retains control over what the role can do, and both sides can revoke access centrally.

Cross-account role naming should reveal purpose and environment so CloudTrail entries are understandable. Generic roles named `AccessRole` become difficult to interpret across dozens of accounts.

Permission policies should avoid granting a role more authority than every caller needs. If two partners require different data, create separate roles rather than one broad role plus an informal agreement about what each partner should touch.

Trust-policy conditions can include `sts:ExternalId`, MFA, organization membership, principal ARN, and supported session attributes. Keep conditions simple enough to test and explain.

Role assumption should fail closed when required context is missing. Test from the actual third-party or workload integration rather than only with an administrator manually calling the CLI.

Temporary credential duration should reflect the job. A fifteen-minute automation does not need a twelve-hour session, while a long-running deployment may require a longer supported duration or credential refresh pattern.

Applications should handle credential expiration cleanly. SDK providers typically refresh automatically, but custom code that caches credentials can fail hours later under load.

Cross-account roles should be provisioned and reviewed through infrastructure as code where practical. Manual trust edits are easy to forget and hard to compare across environments.

Organization-wide access patterns can use standardized role names and permission sets, but production accounts may still need narrower permissions than development. Consistency should not become uniform overprivilege.

Security teams should monitor AssumeRole failures as well as successes. Repeated attempts from an unexpected source account or incorrect external ID may indicate misconfiguration or probing.

Revocation should be tested. Remove the source permission or target trust in a test relationship and verify new sessions fail while understanding how already issued temporary sessions behave until expiration.

The best cross-account design makes permanent secrets unnecessary and trust relationships visible. Temporary sessions, short duration, least privilege, traceable identity, and centralized revocation turn account separation into a practical security boundary rather than an operational obstacle.

Cross-account access inventories should list every trusting role, source principal, business owner, external ID where applicable, session duration, and target permission. This makes periodic entitlement review much easier than parsing trust policies one account at a time.

Organizations with many accounts can standardize deployment through StackSets, infrastructure as code, or account vending pipelines so required audit and trust conditions are consistent.

Standardization should preserve least privilege: a security-read role, deployment role, billing role, and data-read role should remain distinct even if every account creates them from the same templates.

Emergency access should be separate from ordinary cross-account automation and strongly monitored. A break-glass role can have broader permission but should require stronger authentication, short duration, and incident justification.

Temporary delegation is operationally superior to static keys because revocation, audit, and expiry are part of the identity system. That benefit is fully realized only when roles themselves remain narrowly trusted and regularly reviewed.

Trust relationships should be reviewed after mergers, account moves, organization changes, and vendor offboarding because account IDs and organizational context can outlive the original business purpose.

Use clear session names for automation so CloudTrail records distinguish deployment systems, data jobs, and human administration rather than showing dozens of indistinguishable role sessions.

Cross-account automation should fail when the target role is missing rather than falling back to a stored static key. Fallback credentials often reintroduce the exact long-lived-secret risk the role design was intended to remove.

Keep the trust model documented in architecture diagrams so teams understand which accounts may assume which roles and which controls narrow that access.

Review role assumption patterns periodically and remove paths that no longer correspond to an active workload, user group, or external partner so trust does not accumulate faster than it is retired.

That ongoing review keeps temporary delegation temporary in practice and prevents old cross-account roles from becoming undocumented permanent backdoors between otherwise separated environments.

Keep trust relationships current and owned.

Review it regularly.

Keep it auditable.