AWS Error: 'is not authorized to perform: sts:AssumeRole' — Cause, Fix, and Troubleshooting Guide
Fix the STS AccessDenied 'is not authorized to perform: sts:AssumeRole' error: trust policy principals, missing identity permissions, external IDs, and MFA.
- #aws
- #cloud
- #troubleshooting
- #errors
- #iam
Stuck on this AWS with AI error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Assuming an IAM role requires two independent allows: the role’s trust policy must permit your principal to assume it, and your identity policy must grant sts:AssumeRole on that role. If either side is missing (or a condition like ExternalId/MFA isn’t satisfied), STS returns AccessDenied on AssumeRole. The error names the calling principal and the target role, which pins down which side to fix.
You will see it surface from the CLI, an SDK, or cross-account tooling:
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::111122223333:user/dev is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::444455556666:role/CrossAccountDeploy
It occurs whenever role chaining, cross-account access, CI role assumption, or aws sts assume-role runs without both allows and any required conditions in place.
Symptoms
aws sts assume-role(or an SDK/Terraformassume_roleblock) fails withis not authorized to perform: sts:AssumeRole.- Cross-account access works for one principal but not another.
- It started after tightening a trust policy, rotating to a new CI role, or adding an
ExternalId/MFA condition. aws sts get-caller-identitysucceeds (base creds are fine) but the assume fails.
aws sts assume-role \
--role-arn arn:aws:iam::444455556666:role/CrossAccountDeploy \
--role-session-name deploy
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::111122223333:user/dev is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::444455556666:role/CrossAccountDeploy
Common Root Causes
1. The role’s trust policy doesn’t allow your principal
The target role’s AssumeRolePolicyDocument doesn’t list your account/user/role as a trusted Principal.
2. Your identity policy lacks sts:AssumeRole
Your side has no Allow for sts:AssumeRole on that role ARN.
3. A missing or mismatched ExternalId
The trust policy requires sts:ExternalId and you didn’t pass --external-id (or passed the wrong value).
4. An unmet MFA condition
The trust policy requires aws:MultiFactorAuthPresent, but the session has no MFA.
5. A permission boundary or SCP blocks the assume
An SCP or a permission boundary on your principal denies sts:AssumeRole regardless of the identity policy.
6. Wrong role ARN or path
A typo, wrong account ID, or an IAM path mismatch means the target isn’t what you think.
How to diagnose
Step 1: Confirm who you actually are
aws sts get-caller-identity --query Arn --output text
This is the exact principal that must appear (directly or via account root) in the trust policy.
Step 2: Read the target role’s trust policy
aws iam get-role --role-name CrossAccountDeploy \
--query 'Role.AssumeRolePolicyDocument' --output json
Check the Principal matches your Step 1 ARN and note any Condition (sts:ExternalId, MFA).
Step 3: Simulate your identity-side permission
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111122223333:user/dev \
--action-names sts:AssumeRole \
--resource-arns arn:aws:iam::444455556666:role/CrossAccountDeploy \
--query 'EvaluationResults[].[EvalDecision]' --output text
implicitDeny means you’re missing the identity-side allow; explicitDeny points at an SCP/boundary.
Fixes
Add your principal to the role’s trust policy
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/ci-deployer" },
"Action": "sts:AssumeRole"
}
Grant sts:AssumeRole on your identity side
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::444455556666:role/CrossAccountDeploy"
}
Pass the required ExternalId / MFA
aws sts assume-role --role-arn arn:aws:iam::444455556666:role/CrossAccountDeploy \
--role-session-name deploy --external-id REDACTED-EXTID \
--serial-number arn:aws:iam::111122223333:mfa/dev --token-code 123456
What to watch out for
- Both sides must allow the assume — fixing only the trust policy or only the identity policy leaves it broken.
- Trusting an account root (
arn:aws:iam::111122223333:root) in the trust policy also requires each principal in that account to havests:AssumeRoleon their identity side. ExternalIdis case-sensitive and must match exactly; it’s the standard defense for third-party cross-account roles.- An
explicitDenyfrom the simulator means an SCP or permission boundary — no amount of identity/trust editing overrides it until that’s changed.
Related
- AWS Error: ‘AccessDenied … not authorized to perform’ — the general IAM authorization failure pattern.
- AWS Error: SCP explicit deny — Organizations SCPs that block the assume regardless of IAM.
- AWS Error: EKS ‘You must be logged in to the server (Unauthorized)’ — a common downstream effect of a failed role assumption.
Fixed it? Get 500 AWS with AI & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.