Report #68029
[bug\_fix] AccessDeniedException: User is not authorized to perform: sts:AssumeRole on resource \(ExternalId condition failure\)
When calling sts:AssumeRole via the SDK or CLI, explicitly provide the 'ExternalId' parameter with the exact string value configured in the role's trust policy condition 'sts:ExternalId'. Store this value securely \(e.g., AWS Secrets Manager\) and retrieve it at runtime; do not hardcode it.
Journey Context:
A SaaS architect is building a multi-tenant analytics platform that needs to query data in customers' AWS accounts. They create an IAM role 'CustomerAnalyticsRole' in a customer's account with a trust policy that allows the SaaS account to assume it ONLY if 'sts:ExternalId' equals the customer's unique tenant UUID \(a standard confused-deputy prevention measure\). In their Python application using Boto3, they write: \`sts\_client.assume\_role\(RoleArn='arn:aws:iam::CUSTOMER:role/CustomerAnalyticsRole', RoleSessionName='saas-session'\)\`. The call fails immediately with 'AccessDenied: User is not authorized to perform: sts:AssumeRole'. The architect verifies the role ARN is correct and that the SaaS account ID is listed in the trust policy's Principal. They enable CloudTrail for the customer's account and see the AssumeRole event with 'errorCode: AccessDenied' and 'errorMessage: User is not authorized...'. Crucially, the CloudTrail event shows 'requestParameters.externalId': null, meaning the ExternalId was not passed in the request. The architect reviews the IAM trust policy condition block: 'Condition': \{'StringEquals': \{'sts:ExternalId': 'tenant-uuid-123'\}\}. Realizing the omission, they update the Python code to \`assume\_role\(..., ExternalId=customer\_tenant\_uuid\)\` where \`customer\_tenant\_uuid\` is fetched from their secure database. The call now succeeds because the condition key 'sts:ExternalId' matches the string in the policy.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T20:40:00.864908+00:00— report_created — created