Skip to content
ohsudo, Home
Cloud

AWS "is not authorized to perform … because no identity-based policy allows": read the error, find the missing permission

Fix AWS AccessDenied "is not authorized to perform": read who, which action and which resource, check the policy, explicit denies, bucket and KMS key policies.

Intermediate4 min readApplies to AWS IAM · AWS CLI v2 · S3 · KMS · any AWS service

by OhSudo ··

A command or an app fails with an AWS permission error:

An error occurred (AccessDenied) when calling the GetObject operation: User: arn:aws:iam::123456789012:user/ci-deploy is not authorized to perform: s3:GetObject on resource: "arn:aws:s3:::acme-reports/2026/11/summary.csv" because no identity-based policy allows the s3:GetObject action

Long, but it answers the three questions you need:

  • Who — arn:aws:iam::123456789012:user/ci-deploy (an IAM user here; often an assumed role like assumed-role/app-prod/i-0abc…).
  • What — the action s3:GetObject.
  • On what — the resource arn:aws:s3:::acme-reports/2026/11/summary.csv.

And, in most services today, why: the part after because. That last part tells you where to look.

  1. Whouser/ci-deploy, or an assumed role
  2. What, on whats3:GetObject on a resource
  3. Not allowedno policy allows it, or one denies it(breaks here)
AWS knows who you are. The action is refused because no policy allows it for that identity on that resource (or one denies it); the message says who, what, on what, and usually why.

TL;DR

Terminal window
aws sts get-caller-identity # who am I really?
The error says… Look at
because no identity-based policy allows The policies of the user / role — section 2
with an explicit deny in an identity-based policy A Deny in one of its policies — section 3
with an explicit deny in a service control policy An organization SCP — section 3
because no resource-based policy allows The bucket / key / queue policy — section 4
with an explicit deny in a permissions boundary / session policy The boundary on the role, or the policy passed when assuming it

1. Who is really calling?

Terminal window
aws sts get-caller-identity

Credentials come from many places — environment variables, ~/.aws/credentials profiles, an instance role, an SSO session — and they’re often not the ones you think. If the ARN isn’t what you expected, fix that first: AWS_PROFILE, a forgotten AWS_ACCESS_KEY_ID, the wrong role in the CI job.

2. No policy allows the action

Find the policies attached to the user or role (IAM console, or aws iam list-attached-role-policies --role-name app-prod and list-role-policies for inline ones) and look for a statement that allows exactly this action on exactly this resource. The common mistakes:

  • The resource doesn’t match. For S3, objects are arn:aws:s3:::bucket/* and the bucket itself is arn:aws:s3:::bucket. s3:GetObject needs the first, s3:ListBucket the second:
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::acme-reports" },
{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"], "Resource": "arn:aws:s3:::acme-reports/*" }
]
}
  • The action isn’t the one you think. One CLI command can call several API actions (aws s3 sync lists, reads and writes). The error names the action that failed — that’s the one to add.
  • A condition doesn’t match — a required tag, a source VPC, MFA, a region.

The IAM Policy Simulator (in the IAM console) or aws iam simulate-principal-policy shows whether a given action on a given resource is allowed, and which statement decides.

3. An explicit Deny wins

A Deny anywhere beats every Allow. If the message mentions an explicit deny, adding more Allow statements changes nothing. Find the Deny:

  • in the user’s / role’s own policies (often a “guardrail” policy);
  • in a service control policy of your AWS Organization — only the organization’s admins can see and change those;
  • in a permissions boundary attached to the role.

4. The resource has its own policy

Some resources have their own policy: S3 buckets, KMS keys, SQS queues, SNS topics, Secrets Manager secrets. Two classic cases:

  • Another account. Cross-account access needs both sides: the caller’s policy and the resource’s policy must allow it.
  • Encrypted with KMS. Reading an S3 object encrypted with a customer-managed KMS key also needs kms:Decrypt on that key — in the caller’s policy and allowed by the key policy. The error may still name s3:GetObject; look for KMS in CloudTrail.

5. When the message gives no reason

Some services still answer only AccessDenied or AccessDeniedException. Then CloudTrail has the details: search the event history for that event name and errorCode: AccessDenied — it shows the exact identity, action and resource, and sometimes more about the policy that denied it.

Warning

Don’t fix it with "Action": "*" / "Resource": "*" or AdministratorAccess. It works, and it stays — and the next leaked key can do anything in the account. Add the one action on the one resource that the error names.

Shell, we have a problem!

Similar, but different: ExpiredToken / The security token included in the request is expired — the credentials are temporary and ran out; log in again (aws sso login) or let the role refresh. InvalidAccessKeyId / SignatureDoesNotMatch — wrong or deleted keys, or a wrong secret. NoSuchBucket / 404 — the resource doesn’t exist (or, for S3, sometimes you lack s3:ListBucket and get 403 instead of 404). For the layers specific to S3, see S3 403 Access Denied. On Azure, sign-in failures come as AADSTS codes, and a service that isn’t enabled for a subscription is not registered to use namespace. Unable to locate credentials means the CLI found no credentials at all. SignatureDoesNotMatch is a wrong secret key, before IAM is even asked. On Google Cloud, the same kind of error is The caller does not have permission.

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Articles

Related articles