AWS Error AccessDenied: S3 Access Denied
The caller's IAM policy, the bucket policy, a KMS key policy or Block Public Access denied the S3 action. Grant the action on the right ARN (bucket vs bucket/*) and check explicit Deny statements.
Identify: does your log match?
An error occurred (AccessDenied) when calling the GetObject operation: User: arn:aws:sts::123456789012:assumed-role/app-task-role/9f1c2e7a is not authorized to perform: s3:GetObject on resource: "arn:aws:s3:::acme-uploads/avatars/42.png" because no identity-based policy allows the s3:GetObject action
- High
Policy resource ARN mismatch
Object actions (s3:GetObject, s3:PutObject) need arn:aws:s3:::bucket/*; bucket actions (s3:ListBucket) need arn:aws:s3:::bucket. Swapping them denies every call.
- Medium
Missing kms:Decrypt for SSE-KMS
Objects encrypted with a customer-managed KMS key also require kms:Decrypt (and kms:GenerateDataKey for uploads) on that key.
- Medium
Missing key looks like 403
Without s3:ListBucket, S3 returns AccessDenied instead of NoSuchKey for objects that do not exist.
Fix
Grant object and bucket actions on the correct ARNs
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": "arn:aws:s3:::acme-uploads"
}{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::acme-uploads" },
{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::acme-uploads/*" }
]
}Object-level actions only match object ARNs. Adding ListBucket also turns misleading 403s for missing keys into 404 NoSuchKey.
Verify: reproduce it on purpose
$ aws s3api get-object --bucket acme-uploads --key avatars/42.png /tmp/out.png --profile no-s3-accessRun it against a dev environment to trigger AccessDenied on purpose and test your error handler.
Prevent
- Check bucket policy and SCPs for explicit Deny.
- Use IAM Access Analyzer to validate policies.
- Enable CloudTrail data events to see denied calls.
FAQ
Why do I get AccessDenied on an object that does not exist?
S3 returns 403 instead of 404 when you lack s3:ListBucket, to avoid revealing which keys exist.
My IAM policy allows it — why still denied?
An explicit Deny anywhere (bucket policy, SCP, permission boundary, VPC endpoint policy) wins over Allow. KMS key policies can also block.
Does Block Public Access cause AccessDenied?
Yes, for anonymous requests and when putting public ACLs or policies. Use CloudFront with OAC instead of public buckets.
Related errors
Last verified 2026-10-21 · Source: botocore service models (errors per operation) · Official docs ↗ · ~22,200 searches/mo