If you’ve tried to assume a role across AWS accounts and received an “Access Denied” error, you’re not alone. I’ve spent hours debugging cross-account role assumptions in complex multi-account environments, and the issue almost always comes down to one of five specific misconfiguration points. In this post, I’ll walk through exactly what causes AssumeRole failures and how to fix each one systematically.
The Problem
You’re trying to assume a role in another account:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/DeployRole \
--role-session-name deploy-session
And you get this error:
| Error Type | Error Message |
|---|---|
| AccessDenied | User: arn:aws:iam::111111111111:user/deployer is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::222222222222:role/DeployRole |
The error message tells you exactly what’s failing: your user or role doesn’t have permission to assume the target role. But why?
Why Does This Happen?
- Trust policy in target account is wrong: The role’s trust relationship (assume role policy) doesn’t include your source principal. You’re trying to assume a role that doesn’t trust your account or user
- Source principal lacks
sts:AssumeRolepermission: Your user or role in the source account doesn’t have an IAM policy withsts:AssumeRoleon the target role ARN - External ID mismatch: The target role requires an external ID for security, but you didn’t provide one or provided the wrong one
- MFA required but not presented: The trust policy requires MFA authentication, but you didn’t include an MFA device serial number in your assume-role call
- Role session duration exceeds maximum: You requested a session duration longer than the role allows (default max is 1 hour for roles)
The Fix
Step 1: Verify Your Source Principal
First, confirm who you are in the source account:
aws sts get-caller-identity \
--query '[Account,Arn,UserId]' \
--output text
This outputs your account ID and your exact ARN. You’ll need this ARN for the next step.
Step 2: Check the Target Role’s Trust Policy
Get the trust policy (assume role policy document) from the target account:
aws iam get-role \
--role-name DeployRole \
--query 'Role.AssumeRolePolicyDocument' \
--output text
Look for a Principal that matches your source. It should look like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/deployer"
},
"Action": "sts:AssumeRole"
}
]
}
If your principal ARN is not in the Principal block, that’s your first problem. You can use * for the AWS account to allow anyone in that account:
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
}
Step 3: Check Source IAM Policy
In your source account, verify your user or role has permission to assume the target role:
aws iam get-user-policy \
--user-name deployer \
--policy-name AssumeRolePolicy \
--query 'UserPolicy.PolicyDocument' \
--output text
The policy should include:
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/DeployRole"
}
If this is missing, add it.
Step 4: Handle External IDs (if configured)
If the target role requires an external ID (common for cross-account access security), you must provide it:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/DeployRole \
--role-session-name deploy-session \
--external-id MyExternalIdValue123 \
--duration-seconds 3600
The external ID is a shared secret between accounts. If you don’t know it, ask the target account administrator.
Step 5: Handle MFA (if required)
If the trust policy requires MFA, you must include your MFA device:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/DeployRole \
--role-session-name deploy-session \
--serial-number arn:aws:iam::111111111111:mfa/deployer \
--token-code 123456 \
--duration-seconds 3600
The token-code is your current 6-digit MFA code. You can only assume roles with MFA interactively (not in automated deployments unless you use a virtual MFA device).
Diagnostic Checklist
Use this checklist to systematically verify each layer:
- Does the target role’s trust policy include your source principal? → Check
arn:aws:iam::111111111111:user/deployerorarn:aws:iam::111111111111:root - Does your source IAM policy have
sts:AssumeRoleon the target role ARN? → Runget-user-policyorget-role-policy - If external ID is required, did you provide it? → Check the trust policy for
ExternalIdcondition and pass--external-id - If MFA is required, did you provide it? → Check for
aws:MultiFactorAuthPresentcondition and pass--serial-numberand--token-code - Is the requested session duration within the role’s maximum? → Default max is 1 hour unless the role is configured differently
Is This Safe?
Yes. Testing assume-role calls is completely safe — if they fail, no credentials are issued. You’re just verifying your permissions. Assume-role failures don’t lock you out of anything.
Key Takeaway
AssumeRole failures almost always come down to a trust policy mismatch or a missing source IAM permission. Always verify both the target role’s trust policy and your source IAM policy. In my experience, the trust policy is the culprit 70% of the time — it’s the first place I check in a cross-account setup.
Have questions or ran into a different IAM issue? Connect with me on LinkedIn or X.