S3 AccessDenied With a Correct Bucket Policy: 8 Places to Check

2–3 minutes

Updated

Short answer: an S3 AccessDenied is the result of several policies evaluated together. A correct bucket policy is only one of them. An explicit Deny anywhere wins, and an Allow is needed on every layer that applies.

The error

terminal

An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

How S3 decides

For a request to succeed, every layer that applies must allow it and none may deny it: identity policy, bucket policy, SCPs and RCPs from AWS Organizations, permissions boundaries, session policies, VPC endpoint policies and, for encrypted objects, the KMS key policy.

Symptom → likely cause

What you seeCheck first
Works for the bucket owner, fails for another accountBucket policy principal, object ownership, KMS key policy
Works from your laptop, fails from a private subnetVPC endpoint policy, aws:SourceVpce conditions
Fails only for objects encrypted with a customer managed keyKMS key policy and kms:Decrypt on the role
Fails for every principal in an accountSCP or RCP in AWS Organizations
Public access fails even with a public policyS3 Block Public Access (account or bucket)

8 places to check, in order

  1. Who is calling. Run aws sts get-caller-identity. Many “correct” policies allow the wrong role.
  2. Explicit Deny in the bucket policy. Look for Deny statements with conditions such as aws:SecureTransport, aws:SourceVpce or aws:PrincipalOrgID.
  3. Identity policy. The role needs s3:GetObject on arn:aws:s3:::bucket/* (objects), not only on the bucket ARN.
  4. KMS key policy. For SSE-KMS objects, the caller needs kms:Decrypt and the key policy must allow it.
  5. Organizations SCPs and RCPs. A deny at the organization level applies even to administrators in member accounts.
  6. Permissions boundary or session policy. They cap what the role can do, even if its policy allows more.
  7. VPC endpoint policy. A restrictive endpoint policy blocks requests that would otherwise pass.
  8. Block Public Access and object ownership. Public policies are ignored when Block Public Access is on; with ACLs enabled, objects written by another account may not be owned by the bucket owner.

diagnose-s3-403.sh

aws sts get-caller-identity
aws s3api get-bucket-policy --bucket my-bucket --query Policy --output text | jq .
aws s3api get-public-access-block --bucket my-bucket
aws s3api get-bucket-encryption --bucket my-bucket
aws kms get-key-policy --key-id <key-id> --policy-name default --output text | jq .

A bucket policy Deny wins over any IAM Allow. Read the Deny statements before you change roles.

Prevent it

  • Use IAM Access Analyzer policy validation in CI for bucket and key policies.
  • Keep bucket policies, key policies and endpoint policies in the same Terraform module, reviewed together.
  • Log data events for sensitive buckets in CloudTrail, so a denial shows which policy type denied it.

Joniel Gallo · Cloud & AI Engineer

I build these labs in a real AWS account and publish the code. Need a second opinion on your architecture or your AWS bill? Work with me.

One tested AWS & AI lab a week

Real costs, working code and what changed in Bedrock this month. Subscribe and get the free AWS Permission Debugger (PDF).