Skip to main content
runbooks/aws-iam-cross-account-trust-policy-security/aws-cross-account-assume-role-denied-mismatched-trust-policy.md
HIGH SEVERITYAWS IAM Cross-Account Trust Policy SecurityAWS IAM

AWS Cross-Account AssumeRole Is Denied by a Mismatched Trust Policy

Severity
HIGH
Target Time
45m
DomainAWS IAM Cross-Account Trust Policy Security
Verified
Overview

Trace an AWS STS cross-account AssumeRole denial across both accounts and repair a mismatched role trust policy with a controlled rollback.

Share

Destructive Operation

This intervention contains destructive operations. Proceed with extreme caution and ensure database backups exist before execution.

01 // Diagnose

Symptom

Incident signalWhat responders observe

A workload or operator in one AWS account receives AccessDenied when calling STS AssumeRole for a role in another account, although the role name and account IDs appear correct.

Detection Signature

Detection evidenceMetrics, logs, and confirmation commands
  1. From the calling identity, run aws sts get-caller-identity and record the exact account and principal ARN.

  2. Reproduce once with aws sts assume-role --role-arn arn:aws:iam::<TARGET_ACCOUNT_ID>:role/<TARGET_ROLE> --role-session-name incident-diagnostic and retain the request ID and error.

  3. In the target account, run aws iam get-role --role-name <TARGET_ROLE> --query 'Role.AssumeRolePolicyDocument' and decode/review the trust policy Principal, Action, and Condition elements.

  4. Review CloudTrail events for AssumeRole at the incident timestamp.

  5. Check applicable identity policies, permissions boundaries, session policies, service control policies, and resource control policies for an explicit or implicit deny.

Root Cause Analysis

Causal chainWhy the incident occurred
  1. Cross-account AssumeRole requires permission on both sides: the calling principal needs an identity-based allow for sts:AssumeRole, and the target role trust policy must trust the correct principal under its conditions.

  2. A stale principal ARN, incorrect account ID, unmet ExternalId condition, or applicable explicit deny causes the request to fail.

02 // Contain & Prevent

Blast Radius

  • Automations that depend on the target role cannot obtain temporary credentials.

  • Deployments, backups, or incident tooling may stop if they use the affected cross-account path.

  • An overly broad emergency trust-policy change could expose the target role to unintended principals.

Prevention Measures

Prevent recurrenceControls and architectural guardrails
  • Manage role trust policies through reviewed infrastructure as code and test them with a dedicated non-production principal.

  • Use stable role ARNs and explicit conditions rather than broad principals.

  • Alert on repeated AssumeRole AccessDenied events and unexpected trust-policy changes through CloudTrail.

  • Include both trusted-account and trusting-account policy evaluation in access reviews.

03 // Fix & Intervention

Pre-Flight Checks

Change gateChecks required before intervention
  1. Confirm the current AWS CLI profile, region-independent account context, and exact caller ARN with aws sts get-caller-identity; do not infer identity from a role name.

  2. Export the current target role with aws iam get-role --role-name <TARGET_ROLE> > target-role-before-response.json, then extract its AssumeRolePolicyDocument into target-trust-policy-before.json and validate that rollback file before changing anything.

  3. IAM provides no native dry-run for update-assume-role-policy.

  4. Use jq empty validated-trust-policy.json and aws accessanalyzer validate-policy --policy-type RESOURCE_POLICY --validate-policy-resource-type AWS::IAM::AssumeRolePolicyDocument --policy-document file://validated-trust-policy.json as the equivalent policy preview; abort on any error-severity finding.

  5. Peer-review the validated policy and a diff against target-trust-policy-before.json;

  6. confirm it changes only the intended Principal or Condition.

  7. Confirm the caller's identity policy permits sts:AssumeRole on the exact target role ARN, then use aws iam simulate-principal-policy where supported to preview the caller-side identity-policy decision.

  8. Check Organizations policies, permissions boundaries, and session policies for denies that remain independently authoritative even if the target trust policy is repaired.

  9. Confirm the operator is authorized to update the exact target role in the target account.

  10. Obtain the target-account owner's approval and define a five-minute abort window.

Execution CommandsCOMMANDS

jq -r '.Role.AssumeRolePolicyDocument' target-role-before-response.json | python3 -c 'import json,sys,urllib.parse; value=urllib.parse.unquote(sys.stdin.read().strip()); print(json.dumps(json.loads(value),indent=2))' > target-trust-policy-before.json
jq empty target-trust-policy-before.json validated-trust-policy.json
aws accessanalyzer validate-policy --policy-type RESOURCE_POLICY --validate-policy-resource-type AWS::IAM::AssumeRolePolicyDocument --policy-document file://validated-trust-policy.json
aws iam update-assume-role-policy --role-name <TARGET_ROLE> --policy-document file://validated-trust-policy.json
aws iam get-role --role-name <TARGET_ROLE> --query 'Role.AssumeRolePolicyDocument'

04 // Verify & Recover

Verification Steps

Recovery proofEvidence required before closure
  1. Retry aws sts assume-role from the intended caller and confirm temporary credentials are returned.

  2. Use the temporary credentials for one read-only target operation that the role is expected to allow.

  3. Confirm CloudTrail records the successful AssumeRole event with the intended principal and conditions.

  4. Verify an unrelated test principal still receives AccessDenied.

  5. Monitor AssumeRole activity for at least 15 minutes for unexpected principals.

Rollback Protocol

Safe reversal path
  1. If the new trust policy admits an unintended principal or does not resolve the incident, restore the already extracted and validated target-trust-policy-before.json with aws iam update-assume-role-policy --role-name <TARGET_ROLE> --policy-document file://target-trust-policy-before.json, retrieve and compare the restored policy, and revoke any temporary sessions created during testing where supported by the incident response plan.

Escalation

Conditions requiring additional ownership
  • An Organizations SCP/RCP or permissions boundary is responsible for the denial.

  • The original trusted principal was deleted and recreated, changing its principal identity.

  • The repair would require trusting an entire external account without approved restrictive conditions.

  • CloudTrail shows unexpected successful sessions or evidence of credential misuse.

Authoritative Sources

AWS Cross-Account AssumeRole Is Denied by a Mismatched Trust Policy - Incident Runbook | KBY Technologies