LearnDevOpsHands-On Labs
Troubleshooting Matrix/AWS: is not authorized to perform
AWSCritical Severity

AWS: is not authorized to perform

Fix "is not authorized to perform": run aws sts get-caller-identity, then simulate the action in IAM. Covers SCPs, boundaries, resource policies and AssumeRole.

Observed Error Signature / Log Pattern
An error occurred (AccessDenied) when calling the PutObject operation:

Incident Overview

Fix "is not authorized to perform": run aws sts get-caller-identity, then simulate the action in IAM. Covers SCPs, boundaries, resource policies and AssumeRole.

medium fix·7 min read

By Vishvesh Patel·DevOps Engineer·Updated 16 September 2026

BASHDiagnostic / remediation command
An error occurred (AccessDenied) when calling the PutObject operation:
User: arn:aws:sts::123456789012:assumed-role/AppRole/i-0abc123 is not
authorized to perform: s3:PutObject on resource:
arn:aws:s3:::acme-uploads/report.pdf because no identity-based policy
allows the s3:PutObject action

An error occurred (AccessDenied) when calling the AssumeRole operation:
User: arn:aws:iam::123456789012:user/ci is not authorized to perform:
sts:AssumeRole on resource: arn:aws:iam::210987654321:role/Deployer

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

• Confirm which identity is really being used

The Arn here is the principal the policy has to allow, and it is often not the one you assumed. If it is wrong, the credential chain picked something else up. Check env | grep -i AWS and aws configure list.

• Ask IAM why it said no, rather than guessing

implicitDeny means nothing grants the action, so add it. explicitDeny names the policy doing the blocking, and an explicit Deny beats every Allow anywhere.

• If the resource belongs to another account, check its own policy

Resource policies are evaluated alongside identity policies. For cross-account access both sides have to allow it, and a missing bucket policy denies you no matter how permissive your role is.

AWS AccessDenied messages are more informative than they look. Before changing any policy, read the three facts the message gives you.

That last clause is newer and worth looking for. AWS now often states why, and the wording distinguishes the causes below.

BASHDiagnostic / remediation command
aws sts get-caller-identity

First: confirm who you actually are

More AccessDenied investigations are wasted on this than on anything else.

Check the account and the role. A surprising share of these errors are a correct policy in the wrong account, a stale AWS_PROFILE, or an EC2 instance using its instance role when you assumed you were using your own credentials.

Environment variables beat the profile, so an AWS_ACCESS_KEY_ID left over from an earlier session silently overrides --profile.

BASHDiagnostic / remediation command
aws sts get-caller-identity

Then: ask IAM directly

Rather than reasoning about the policies, simulate the call:

implicitDeny means nothing allows it. explicitDeny means something actively forbids it, and MatchedStatements names the policy, which is the fastest route to a deny buried in an SCP or a boundary.

Note the simulator does not evaluate resource policies or SCPs in every case, so a pass here with a real failure points at one of those.

BASHDiagnostic / remediation command
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/AppRole \
  --action-names s3:PutObject \
  --resource-arns arn:aws:s3:::acme-uploads/report.pdf \
  --query 'EvaluationResults[].[EvalActionName,EvalDecision,MatchedStatements[].SourcePolicyId]'

The six causes, in order of likelihood

• 1. No identity-based policy allows it

The default state: IAM denies everything not explicitly allowed. The message says because no identity-based policy allows.

Add the action, scoped to the resource:

Watch the ARN shape. Bucket-level and object-level actions take different resources: s3:ListBucket needs arn:aws:s3:::acme-uploads, while s3:PutObject needs arn:aws:s3:::acme-uploads/*. Using one where the other belongs is the single most common S3 policy mistake.

• 2. A resource policy denies or does not allow it

For cross-account access, both sides must permit the call. A bucket policy, KMS key policy, SQS queue policy or Lambda resource policy can allow or deny independently of IAM.

The special case worth knowing: KMS requires both the key policy and IAM, and an IAM policy granting kms:* achieves nothing on a key whose policy does not permit your principal. A PutObject to an SSE-KMS bucket therefore fails with an S3-shaped error caused by KMS.

• 3. An explicit deny

A single Deny anywhere beats every Allow. The message reads because an explicit deny in an identity-based policy.

Common sources: a policy denying actions outside a region, denying access unless MFA is present, or denying anything not carrying a required tag.

• 4. A service control policy

That phrase is the giveaway, and it appears at the end of a long message where it is easy to miss. An SCP caps what is possible in the account regardless of IAM.

You need Organizations access to check, which usually means asking whoever manages the management account. Region-restriction SCPs are a frequent cause, and they break global services unless exempted.

• 5. A permissions boundary

A boundary caps what a role can do even when its policies allow more. The message says because no permissions boundary allows.

• 6. A session policy

When a role is assumed with --policy or --policy-arns, that session is limited further:

The resulting credentials cannot write to S3 no matter what the role permits. Federated sessions from an identity provider frequently carry one of these.

BASHDiagnostic / remediation command
aws iam list-attached-role-policies --role-name AppRole
aws iam list-role-policies --role-name AppRole

Reading which cause applies

The because … clause maps directly:

If your error has no because clause, the API is an older one. Use the simulator.

Cross-account AssumeRole

Two separate permissions, and both are needed:

The caller needs sts:AssumeRole on that role ARN:

The role needs a trust policy accepting the caller:

Missing either gives an identical error. And note the ExternalId condition, if the trust policy requires one, the caller must pass --external-id or the assume fails with the same message.

BASHDiagnostic / remediation command
User: arn:aws:iam::123456789012:user/ci is not authorized to perform:
sts:AssumeRole on resource: arn:aws:iam::210987654321:role/Deployer

Find it in CloudTrail

Every denied call is recorded, with the full request context:

The event includes userIdentity, requestParameters and errorMessage, which together settle arguments about what was actually requested, often revealing the call used a different resource ARN than anyone assumed.

BASHDiagnostic / remediation command
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=PutObject \
  --start-time "$(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ)" \
  --query 'Events[?contains(CloudTrailEvent, `AccessDenied`)].CloudTrailEvent' \
  --output text | python3 -m json.tool | head -40

A checklist

Frequently Asked Questions

How do I read an AWS "is not authorized to perform" error?

It gives you four things: the principal ARN that made the call, the exact API action, the resource ARN including any object key, and increasingly a because … clause naming the cause. Start with the principal. Confirm with aws sts get-caller-identity that you are the identity you think you are, in the account you think you are. A large share of these errors turn out to be a correct policy in the wrong account or a stale environment variable overriding your profile.

Why does my IAM policy allow the action but the call still fails?

Six things can deny a request, and IAM is only one. A resource policy, bucket, KMS key, queue, can refuse independently. An explicit Deny anywhere overrides every Allow. A service control policy caps what is possible in the whole account. A permissions boundary caps what the role can do. And a session policy can restrict credentials further when a role is assumed with --policy. The because … clause in the error tells you which applies.

Why do I get AccessDenied on S3 when my policy looks right?

Most often the resource ARN shape. Bucket-level actions such as s3:ListBucket require arn:aws:s3:::bucket, while object-level actions such as s3:GetObject and s3:PutObject require arn:aws:s3:::bucket/*, and using one form where the other belongs denies the call with a policy that reads as correct. The second cause is an SSE-KMS bucket: writing to it needs kms:GenerateDataKey on the key, permitted by both the key policy and IAM.

What does "with an explicit deny in a service control policy" mean?

An SCP attached to your account or one of its parent organizational units forbids that action, and no IAM policy can override it. SCPs set a ceiling on what is possible. The phrase appears at the end of a long message where it is easy to overlook, and it is the only reliable indicator, since an implicit denial under an allow-list SCP gives no explanation at all. Checking requires Organizations access, so it usually means asking whoever manages the management account.

Why does sts:AssumeRole fail across accounts?

Because it needs permission on both sides. The calling identity requires sts:AssumeRole on the target role's ARN in its own IAM policy, and the target role requires a trust policy naming that caller as a principal. Missing either produces an identical error. If the trust policy includes an sts:ExternalId condition, the caller must also pass --external-id with the matching value, which fails the same way when omitted.

How do I find out exactly why a request was denied?

aws iam simulate-principal-policy with the action and resource ARN returns implicitDeny or explicitDeny, and for an explicit deny names the policy in MatchedStatements, which is much faster than reading policies by hand. It does not evaluate every resource policy or SCP, so a pass there with a real-world failure points at one of those. CloudTrail holds the complete request for any denied call, including the resource ARN actually used, which frequently differs from what everyone assumed.

Reference and practice

Learn the underlying concept

Other AWS errors

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Get notified about new tutorials and features.

• Roadmaps

• Interview Prep

• Certifications

• Company

© 2026 DevOpsLesson. All rights reserved.

Need to practice this scenario?

Simulate this error condition and practice recovery commands safely in our in-browser terminal.

Open AWS Sandbox