DevOpsil
AWS
85%
Needs Review

Fix AWS S3 'Access Denied' Errors

Sarah ChenSarah Chen3 min read

The Error: "Access Denied" on S3

You try to access an S3 object and get:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>ABC123DEF456</RequestId>
</Error>

Or from the CLI:

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

This is one of the most common and most frustrating AWS errors because there are at least six different places where access can be blocked.

Root Cause

S3 access is evaluated across multiple policy layers. A denial in any layer blocks access:

  1. IAM user/role policy -- caller doesn't have s3:GetObject
  2. Bucket policy -- explicit deny or missing allow for the caller
  3. S3 Block Public Access -- account or bucket level blocks
  4. Object ACL -- object owned by a different account
  5. VPC Endpoint policy -- restricts which buckets can be accessed
  6. KMS key policy -- caller can't decrypt the encryption key

Step-by-Step Fix

1. Identify Who You Are

First, confirm which identity is making the request:

aws sts get-caller-identity
{
  "UserId": "AROA3XFRBF23ABCDEFGH:session-name",
  "Account": "123456789012",
  "Arn": "arn:aws:sts::123456789012:assumed-role/my-role/session-name"
}

2. Check IAM Policy

Verify the IAM role or user has S3 permissions:

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/my-role \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::my-bucket/my-key

If result is implicitDeny, the IAM policy doesn't grant access. Add it:

{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject",
    "s3:ListBucket"
  ],
  "Resource": [
    "arn:aws:s3:::my-bucket",
    "arn:aws:s3:::my-bucket/*"
  ]
}

Common mistake: missing the /* suffix. s3:GetObject needs bucket/*, while s3:ListBucket needs just bucket.

3. Check Bucket Policy

aws s3api get-bucket-policy --bucket my-bucket --output text | jq .

Look for explicit Deny statements. A common gotcha is a policy that denies all access except from a specific VPC:

{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:*",
  "Resource": "arn:aws:s3:::my-bucket/*",
  "Condition": {
    "StringNotEquals": {
      "aws:sourceVpc": "vpc-abc123"
    }
  }
}

If you're calling from outside that VPC, you'll get Access Denied.

4. Check Block Public Access

aws s3api get-public-access-block --bucket my-bucket

If RestrictPublicBuckets is true, even bucket policies granting public access are ignored.

5. Check Object Ownership (Cross-Account)

If objects were uploaded by a different AWS account:

aws s3api get-object-acl --bucket my-bucket --key my-key

Fix with bucket-owner-full-control:

# Re-upload with proper ownership
aws s3 cp s3://my-bucket/my-key s3://my-bucket/my-key \
  --acl bucket-owner-full-control

Or enforce ownership at the bucket level:

aws s3api put-bucket-ownership-controls --bucket my-bucket \
  --ownership-controls '{"Rules":[{"ObjectOwnership":"BucketOwnerEnforced"}]}'

6. Check KMS Encryption

If the bucket uses KMS encryption, the caller needs kms:Decrypt permission on the key:

aws s3api head-object --bucket my-bucket --key my-key
# Check the ServerSideEncryption and SSEKMSKeyId fields

Add KMS permissions to the IAM policy:

{
  "Effect": "Allow",
  "Action": ["kms:Decrypt", "kms:GenerateDataKey"],
  "Resource": "arn:aws:kms:us-east-1:123456789012:key/key-id"
}

Prevention Tips

  • Use IAM Access Analyzer to verify that policies grant the intended access: aws accessanalyzer validate-policy.
  • Enable S3 server access logging or CloudTrail data events to see exactly which requests are denied and why.
  • Use BucketOwnerEnforced ownership on all new buckets to eliminate ACL headaches.
  • Standardize on a single encryption key per environment to reduce KMS policy complexity.
  • Test access with --dryrun where supported, or use aws iam simulate-principal-policy before deploying.
Share:

Was this article helpful?

Sarah Chen
Sarah Chen

CI/CD Engineering Lead

Automation evangelist who believes no deployment should require a human. I write pipelines, break pipelines, and write about both. Code-first, always.

Related Articles

AWSQuick RefBeginnerNeeds Review

AWS CLI: Cheat Sheet

AWS CLI cheat sheet with copy-paste commands for EC2, S3, IAM, Lambda, ECS, CloudFormation, SSM, and Secrets Manager operations.

Dev Patel·
3 min read

More in AWS

View all →
AWSTutorialBeginnerNeeds Review

AWS EKS: Production Kubernetes Cluster Setup from Scratch

Step-by-step guide to launching a production-ready EKS cluster on AWS — node groups, IAM roles, VPC configuration, managed add-ons, kubeconfig setup, and cost optimization. Both eksctl and Terraform approaches covered.

Aareez Asif·
6 min read

Discussion