S3 Public Access Block is a surprisingly blunt instrument that often prevents legitimate, controlled public access as much as it stops accidental exposure.

Let’s see it in action. Imagine you have a perfectly valid use case: a static website hosted in S3. You’ve configured your bucket policy to allow s3:GetObject for everyone (Principal: "*").

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-static-website-bucket/*"
    }
  ]
}

You’ve also set up a public access point. You upload your index.html and error.html files. You expect to see your website at http://my-static-website-bucket.s3-website-us-east-1.amazonaws.com.

But you get an Access Denied error. Why? Because S3 Public Access Block is enabled by default on all new buckets.

The Public Access Block settings are a set of four controls that can be applied at the bucket level or the account level. When enabled, they override any bucket policies or ACLs that would grant public access.

Here’s the breakdown of the four settings:

  1. Block public access to buckets and objects through new access control lists (ACLs): This prevents new ACLs from granting public access. If you try to grant public read access via an ACL on a new object or bucket, this setting will reject it.
  2. Block public access to buckets and objects through any access control lists (ACLs): This is a more aggressive version of the first setting. It blocks all ACLs, new or existing, from granting public access. This is the one that often trips up people who have relied on ACLs for public access in the past.
  3. Block public access to buckets and objects through new public bucket or access point policies: This prevents new bucket policies or access point policies from granting public access. If you try to add a policy that allows Principal: "*" or Principal: {"AWS": "*"} for s3:GetObject, this setting will block it.
  4. Block public and cross-account access to buckets and objects through any public or access point policies: This is the most restrictive. It blocks all bucket policies and access point policies, new or existing, from granting public or cross-account access.

To allow your static website, you need to selectively disable these blocks.

To allow public GetObject for your static website, you must disable:

  • Block public access to buckets and objects through new public bucket or access point policies
  • Block public and cross-account access to buckets and objects through any public or access point policies

Crucially, you do NOT need to disable the ACL-related blocks if you are using bucket policies for access control. This is where the blunt instrument analogy comes in. Many people disable all four, thinking they need to.

Here’s how you’d do it via the AWS CLI:

First, check the current settings for your bucket:

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

You’ll likely see something like this, indicating all are true:

{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": true,
        "RestrictPublicBuckets": true
    }
}

Now, to allow your static website policy, you’ll update the configuration. You want to keep the ACL blocks enabled to prevent accidental exposure via ACLs, but disable the policy blocks.

aws s3api put-public-access-block \
    --bucket my-static-website-bucket \
    --public-access-block-configuration '{
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": false,
        "RestrictPublicBuckets": false
    }'

Notice that BlockPublicPolicy and RestrictPublicBuckets are set to false. This allows your bucket policy with Principal: "*" to take effect for s3:GetObject.

Why this works: The BlockPublicPolicy setting, when true, prevents any policy from granting public access. By setting it to false, you’re telling S3 to evaluate the bucket policy as written, allowing your GetObject statement to be honored. RestrictPublicBuckets is a more advanced setting that blocks access from any principal not explicitly listed in the bucket policy, even if the policy itself allows public access. For a simple static website, you don’t need this restriction.

After running this command, your static website should become accessible.

The most surprising thing about S3 Public Access Block is that its most restrictive settings (BlockPublicPolicy and RestrictPublicBuckets) are often the only ones that need to be disabled for legitimate public access use cases like static website hosting. Many users mistakenly disable all four, opening themselves up to potential accidental exposure when only the policy-related blocks needed to be loosened.

Once you’ve addressed public access, your next immediate concern will be ensuring that objects themselves are not publicly readable if they are not intended to be, which often involves re-evaluating object-level ACLs or ensuring default encryption is in place.

Want structured learning?

Take the full S3 course →