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.
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 actionLong, but it answers the three questions you need:
- Who —
arn:aws:iam::123456789012:user/ci-deploy(an IAM user here; often an assumed role likeassumed-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.
- Whouser/ci-deploy, or an assumed roleasks for
- What, on whats3:GetObject on a resourcechecked against policies(fails)
- Not allowedno policy allows it, or one denies it(breaks here)
TL;DR
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?
aws sts get-caller-identityCredentials 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 isarn:aws:s3:::bucket.s3:GetObjectneeds the first,s3:ListBucketthe 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 synclists, 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:Decrypton that key — in the caller’s policy and allowed by the key policy. The error may still names3: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.