I created a bucket policy that explicitly allows public access with "Principal": "*", deployed it, and tested the public URL. 403 Forbidden. No errors in the policy itself—it was syntactically correct. I checked the bucket policy in the console, and it was there. But somehow, S3 was silently ignoring it. After digging through AWS documentation, I discovered the culprit: Block Public Access settings were overriding my bucket policy without any warning. In this post, I’ll walk through exactly what causes this and how to fix it.

The Problem

You add a bucket policy with "Principal": "*" to allow public read access, but the bucket still returns 403 Forbidden. The policy appears in the console, it looks correct, but it’s not being applied. The issue isn’t the policy—it’s S3 Block Public Access silently overriding it.

Error Type Description
403 Forbidden Public bucket policy exists, but Block Public Access prevents public access.
Policy Not Effective Policy is correct but ignored due to Block Public Access settings.
Account-Wide Block Account-level Block Public Access overrides bucket-level settings.

Why Does This Happen?

S3 Block Public Access has 4 independent settings at both the account level and the bucket level. Two of them directly conflict with bucket policies:

  • BlockPublicPolicy — Prevents any bucket policy that grants public access from being applied. If enabled, a bucket policy with "Principal": "*" is silently ignored (not even evaluated). The policy is stored but has no effect.
  • RestrictPublicBuckets — Makes any existing public bucket policy treat all non-AWS principal access as blocked. The policy exists and is syntactically valid, but S3 doesn’t allow non-AWS access through it.

The other two settings (BlockPublicAcls and IgnorePublicAcls) control object-level ACLs, not bucket policies.

The Fix

Step 1: Check Block Public Access at Account Level

# View account-level Block Public Access settings
aws s3control get-public-access-block \
  --account-id 123456789012

Output shows four boolean settings. If any are true, they restrict public access.

Step 2: Check Block Public Access at Bucket Level

# View bucket-level Block Public Access settings
aws s3api get-public-access-block --bucket my-bucket

Step 3: Understanding Which Settings Block Which Actions

Setting Blocks What
BlockPublicAcls Object ACLs that grant public access
IgnorePublicAcls Existing public object ACLs (object is treated as private)
BlockPublicPolicy Bucket policies that grant public access (prevents policy from being applied)
RestrictPublicBuckets Public access through bucket policies (policy ignored for non-AWS principals)

Step 4: Disable the Right Settings for Your Use Case

For a public static website: All four settings must be false:

aws s3api put-public-access-block \
  --bucket my-bucket \
  --public-access-block-configuration \
  BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false

For cross-account access with bucket policy only: Only RestrictPublicBuckets may need adjustment:

aws s3api put-public-access-block \
  --bucket my-bucket \
  --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=false,RestrictPublicBuckets=false

For account-level override: If account-level Block Public Access is blocking bucket-level policies, disable it:

aws s3control put-public-access-block \
  --account-id 123456789012 \
  --public-access-block-configuration \
  BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false

Step 5: Verify After Changes

Apply the bucket policy again (it may need re-application if it was blocked):

cat > bucket-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}
EOF

aws s3api put-bucket-policy \
  --bucket my-bucket \
  --policy file://bucket-policy.json

Test public access:

curl https://my-bucket.s3.amazonaws.com/index.html

How to Run This

  1. Replace 123456789012 with your AWS account ID
  2. Replace my-bucket with your bucket name
  3. Identify which Block Public Access settings are blocking your use case
  4. Disable only the settings necessary for your use case (don’t disable all four unless needed)
  5. Apply or re-apply your bucket policy
  6. Test public access immediately

Is This Safe?

Block Public Access is a security best practice. Disable settings only for the specific use case (static website, cross-account access, etc.). For production, consider using CloudFront in front of S3 instead of making the bucket directly public. This allows you to keep Block Public Access enabled while serving content through a CloudFront origin access identity.

Key Takeaway

Block Public Access settings override bucket policies silently. BlockPublicPolicy prevents policies from being applied, and RestrictPublicBuckets restricts them further. Check both account-level and bucket-level settings, disable only what’s necessary, and re-apply your policy afterward.


Have questions or ran into a different S3 issue? Connect with me on LinkedIn or X.