IAMOrganizationsSecurity

AWS Cross-Account Access: IAM Roles and Trust Policies at Scale

Vigilare Engineering

Platform Team · January 4, 2026 · 9 min read

Cross-account access through IAM role assumption enables the multi-account architectures that serious AWS deployments require: a security team account that can read configuration from all member accounts, a CI/CD account that deploys infrastructure to production accounts, an MSP management account that manages customer accounts. Each of these scenarios requires one AWS principal (in one account) to assume a role (in another account) to take actions there.

The security model of cross-account access is trust — the target account explicitly trusts the source account to assume specific roles. This trust must be carefully scoped to limit what the assuming principal can do, and monitored to detect unexpected assumption patterns.

Trust Policy Design

A trust policy on an IAM role defines who can assume it. For cross-account access, the trust policy specifies the source account and (optionally) the specific IAM principal within that account that can assume the role.

Least-privilege trust policy — trusting a specific role rather than the entire account:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::123456789012:role/SecurityAuditAutomation"
    },
    "Action": "sts:AssumeRole",
    "Condition": {
      "Bool": {"aws:MultiFactorAuthPresent": "true"},
      "StringEquals": {"sts:ExternalId": "unique-external-id-here"}
    }
  }]
}

This trust policy grants assumption only to the SecurityAuditAutomation role in account 123456789012, and only when MFA was used and the external ID matches. Each condition narrows the scope of who can assume the role.

External ID: When you provision cross-account access for a third party (MSP, vendor, SaaS tool), use an external ID to prevent the confused deputy problem. The external ID is a secret value that the assuming principal must provide when calling AssumeRole. If the assuming party's credentials are compromised and used to assume roles in other customers, the attacker would need to know your specific external ID — the third party's credentials alone aren't sufficient.

MFA requirement: For sensitive cross-account roles (administrator access, break-glass roles), require MFA in the trust policy. This prevents automation from assuming high-privilege roles — automation that needs cross-account access should use a less sensitive role that doesn't require MFA.

Permission Scoping for Cross-Account Roles

The role's permission policy (distinct from the trust policy) defines what the assuming principal can do once they've assumed the role. Apply the same least-privilege principles as for any IAM role:

Read-only for monitoring: Cross-account monitoring roles should have read-only permissions. The AWS managed policy SecurityAudit provides comprehensive read permissions across most services for security assessment purposes. ReadOnlyAccess is broader than needed for most security monitoring — use SecurityAudit for security-focused roles.

Scoped for specific services: Cross-account deployment roles should have permissions scoped to the specific services being deployed. An infrastructure deployment role for a specific application doesn't need permissions to modify other applications' resources in the same account.

Permission boundaries: Apply permission boundaries to cross-account roles to limit the maximum permissions even if the role's own policies are misconfigured. A permission boundary that caps the role at read-only prevents an overly broad policy from accidentally granting write permissions.

Session Tags and Attribute-Based Access

When assuming a cross-account role, the STS AssumeRole call can include session tags that propagate into the assumed session. These session tags can be used in condition keys to enable attribute-based access control — the assumed session has attributes that the target account's resource policies can evaluate.

For MSP scenarios, tagging assumed sessions with the client identifier allows a single cross-account role in the MSP account to access client-specific resources in a shared services account, with resource policies that restrict access based on the client tag. This reduces the number of roles needed while maintaining client isolation.

Monitoring Cross-Account Assumptions

CloudTrail in the target account records all AssumeRole calls, including the identity of the assuming principal and the source account. Monitor for:

  • Role assumptions from unexpected source accounts
  • Role assumptions outside business hours for human-access roles
  • Role assumption volume anomalies (many more assumptions than usual)
  • Assumptions of high-privilege roles by automation principals (which shouldn't be assuming admin roles)

Create CloudTrail-based EventBridge rules for sensitive roles. A rule that fires when the break-glass administrator role is assumed — and immediately pages the security team — ensures that emergency access is always noticed. See the assume-role monitoring guide for specific CloudTrail queries and EventBridge rule configurations.

Organization-Level Cross-Account Controls

For AWS Organizations members, Service Control Policies can restrict cross-account role assumptions at the organization level. An SCP condition that limits AssumeRole calls to principals within the organization prevents external parties from assuming roles even if a trust policy is misconfigured to allow it:

{
  "Effect": "Deny",
  "Action": "sts:AssumeRole",
  "Resource": "*",
  "Condition": {
    "StringNotEquals": {"aws:PrincipalOrgID": "o-xxxxxxxxxxxx"}
  }
}

Apply this SCP with an exception for roles specifically designed for external access (vendor access roles, MSP monitoring roles). This provides a backstop against accidental external access from misconfigured trust policies.

Related Reading

FAQ

What's the difference between cross-account access via role assumption and cross-account access via resource policies?

Role assumption involves the assuming principal switching to a different identity with different permissions. The actions appear in CloudTrail under the assumed role's identity. Resource policies (S3 bucket policies, KMS key policies, SQS queue policies) grant access to an external principal directly without identity switching — the original principal's identity is maintained. Role assumption is appropriate for access to multiple resources in the target account; resource policies are appropriate for granting access to specific individual resources from external principals.

Can I prevent specific source accounts from assuming roles in my account?

Trust policies can only allow (not deny) — you can't add a trust policy deny for a specific source account while allowing others. If you need to prevent a specific account from assuming any role, use an SCP that denies AssumeRole from that specific principal ARN. This is unusual — normally you control access by only trusting accounts you explicitly want to grant access to.

How do I audit which roles in my account trust external accounts?

Use IAM Access Analyzer, which specifically identifies IAM policies that grant access to external principals. Access Analyzer's findings include cross-account role trust policies, resource-based policies with external principals, and S3 bucket policies granting external access. Enable Access Analyzer in every region and review findings regularly as part of your security governance process.

Protect your AWS accounts before it's too late

Vigilare monitors your AWS accounts for suspension risks — billing anomalies, IAM issues, GuardDuty findings, and more — and alerts you before AWS takes action.

Written by Vigilare Engineering

Platform Team