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
- Replace
123456789012with your AWS account ID - Replace
my-bucketwith your bucket name - Identify which Block Public Access settings are blocking your use case
- Disable only the settings necessary for your use case (don’t disable all four unless needed)
- Apply or re-apply your bucket policy
- 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.