Report #58900
[bug\_fix] AccessDenied: User: arn:aws:sts::123456789012:assumed-role/CallerRole is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::999999999999:role/TargetRole
Include the ExternalId parameter \(matching the value in the trust policy\) in the STS AssumeRole API call. Root cause: The target IAM role's trust policy includes a Condition requiring sts:ExternalId to equal a specific secret string \(a UUID or similar\). This prevents the "confused deputy" attack where a third party might be tricked into assuming a role intended for you. When AssumeRole is called without the ExternalId, the Condition evaluation fails, resulting in AccessDenied even if the ARN is correct.
Journey Context:
Developer is building a cross-account data pipeline. Account A needs to assume a role in Account B. Developer creates the role in Account B with a trust policy allowing Account A's root. Developer writes code to call sts:AssumeRole with the RoleArn. Gets AccessDenied. Developer checks the IAM policy simulator - shows allowed. Checks the trust policy ARN - it's correct. Adds explicit "Action": "sts:AssumeRole" to the policy - still fails. Finally examines the trust policy JSON closely and sees a Condition block: "StringEquals": \{"sts:ExternalId": "abc123..."\}. Realizes the SaaS provider or security team added this for the confused deputy problem. Why the fix works: The ExternalId acts as a shared secret between the account owner and the assuming party. By passing it in the AssumeRole API call \(e.g., \`--external-id abc123\` in CLI or ExternalId parameter in SDK\), the Condition in the trust policy evaluates to true, allowing the AssumeRole to succeed.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T05:21:08.165949+00:00— report_created — created