skip to content

An S3 bucket that should be private is serving objects to anonymous callers. How does S3 decide that a bucket is public, and what does each of the four S3 Block Public Access settings stop?

level: middleimportance: must knowfreq 70%

answer

  1. four booleans, not one flag
  2. block new versus ignore existing
  3. AuthenticatedUsers is not your org
  4. two levels, stricter one wins
  5. wildcard principal without a condition

basics

~20 s

S3 treats a grant to a wildcard principal or to the legacy AllUsers/AuthenticatedUsers groups as public unless conditions pin it to fixed values. Block Public Access has four independent switches that block or ignore public ACLs and public policies, and it applies at both account and bucket level.

solid answer

~40 s

Something granted access to everyone: either a bucket policy with `"Principal": "*"` and no narrowing condition, or a legacy ACL granting the `AllUsers`/`AuthenticatedUsers` groups. S3's evaluation of "public" is deliberately conservative — a wildcard principal counts as public unless the statement is constrained by conditions on a fixed set of values such as `aws:SourceVpce` or `aws:SourceAccount`. Block Public Access then gives you four switches: `BlockPublicAcls` rejects requests that *set* a public ACL, `IgnorePublicAcls` ignores public ACLs that already exist, `BlockPublicPolicy` rejects a `PutBucketPolicy` that would be public, and `RestrictPublicBuckets` neutralises an already-public policy so only account principals and AWS services can use it. They exist at the account level and per bucket, and the more restrictive of the two wins — so investigate both.

code

bash · 4 lines
bash
aws s3api get-public-access-block --bucket my-bucket
aws s3control get-public-access-block --account-id 111122223333
aws s3api get-bucket-policy --bucket my-bucket --output text
aws s3api get-bucket-acl --bucket my-bucket

go deeper

for a junior

Know that a bucket becomes public through a wildcard-principal bucket policy or a public ACL, and that Block Public Access is the switch that stops it. Be able to name where you would look first.

for a middle

Explain all four settings and the split between blocking new grants and ignoring existing ones, plus the fact that account-level and bucket-level settings combine to the most restrictive result.

for a senior

Walk an actual investigation: which API calls you run, how you tell an anonymous caller from an over-permissioned role, and why you would move public delivery behind a CDN rather than opening the bucket.

for a principal

Own the guardrail design — account-level BPA enforced from the organisation so it cannot be disabled locally, Access Analyzer findings as the detective layer, and a documented exception path for the rare bucket that genuinely must be open.

## What "public" means to S3 Access to an S3 object can be granted three ways: an IAM identity policy, the bucket policy, and the legacy per-object or per-bucket ACL. Only the last two can grant to *everyone*, and both are what Block Public Access (BPA) polices. A bucket policy is public if a statement allows an action to a wildcard principal — `"Principal": "*"` or `"Principal": {"AWS": "*"}` — without narrowing it. S3 evaluates this statically, before any request arrives, and errs toward calling things public: the statement is treated as non-public only when a condition pins the request to a fixed set of values, using keys such as `aws:SourceVpce`, `aws:SourceVpc`, `aws:SourceAccount` or a non-wildcard `aws:SourceIp` range. If you cannot convince S3 that the audience is bounded, it is public. An ACL is public if it grants to one of the two predefined groups: `AllUsers` (literally anyone, unauthenticated included) or `AuthenticatedUsers` — which sounds safe and is not, because it means *any* AWS account holder on earth, not any account of yours. `AuthenticatedUsers` being mistaken for "my org" is one of the oldest S3 breaches. ## The four switches BPA is not one flag. It is four booleans, split along two axes — ACLs versus policies, and new grants versus existing ones: | Setting | What it does | |---|---| | `BlockPublicAcls` | Rejects `PutBucketAcl`/`PutObjectAcl` calls, and uploads carrying an ACL, that would make something public. Existing public ACLs are untouched. | | `IgnorePublicAcls` | Ignores every public ACL already on the bucket or its objects, so they stop granting anything. | | `BlockPublicPolicy` | Rejects a `PutBucketPolicy` whose document S3 evaluates as public. An existing public policy stays in place. | | `RestrictPublicBuckets` | Where a public policy already exists, restricts its use to principals in the bucket-owning account and to AWS service principals — anonymous and cross-account callers are cut off. | The pairing is the point: the two `Block*` settings are preventive and stop new mistakes, while `IgnorePublicAcls` and `RestrictPublicBuckets` are remedial and neutralise mistakes already made. Turning on only the `Block*` pair on an existing bucket changes nothing about the exposure you already have. ## Two levels, most restrictive wins Every setting exists twice: on the bucket, and account-wide through S3 Control. The account-level setting is evaluated on top of the bucket-level one, and the union of restrictions applies. That means: - A bucket with BPA off is still fully blocked if the account has BPA on. This is the single most common source of "the setting is off but the bucket is still not public" confusion. - Conversely, turning BPA off at the account level does not turn it off per bucket. Since April 2023, newly created buckets have all four BPA settings enabled and ACLs disabled by default, so a bucket that is public today either predates that or was deliberately opened. ## Debugging "why is this public?" Work the sources in order: 1. `aws s3api get-public-access-block --bucket NAME` for the bucket, and the account-level equivalent through S3 Control. If BPA is fully on and callers still get objects, they are not anonymous — look for a broad IAM policy or an assumed role instead. 2. `aws s3api get-bucket-policy --bucket NAME` and look for a wildcard `Principal` with no narrowing condition. 3. `aws s3api get-bucket-acl` and the ACLs of individual objects, for the `AllUsers`/`AuthenticatedUsers` grantees. 4. IAM Access Analyzer for S3, which reports exactly which buckets are reachable from outside a chosen zone of trust and why — the fastest answer for an estate rather than one bucket. ## Serving content publicly without a public bucket The reason to be strict is that "public bucket" is almost never the right way to serve public content. The pattern that replaces it puts CloudFront in front of a private bucket and lets the distribution read the origin as an authorised principal, so the objects have exactly one door, with caching, logging and WAF in front of it. Keep BPA fully on and let the CDN do the exposing. ## The guardrail framing At organisation scale, BPA per bucket is not enough — someone will create a bucket in an account you have not onboarded. Set BPA at the account level for every account, and back it with a preventive control at the organisation layer so the account setting cannot be turned off by an account admin. Detective controls such as Access Analyzer findings then catch what slipped through, rather than being the only line of defence.

  • You enable BlockPublicAcls and BlockPublicPolicy on an existing bucket that is already public. Is it private now?
    No. Those two settings are preventive: they reject *new* public ACLs and *new* public policies, but leave whatever is already there fully in force. You also need `IgnorePublicAcls` to neutralise existing public ACLs and `RestrictPublicBuckets` to stop an existing public policy from serving anonymous or cross-account callers. In practice, turn on all four.
  • How should you serve genuinely public content if the bucket must stay private?
    Put CloudFront in front of it and keep Block Public Access fully enabled. The distribution reads the bucket as an authorised principal and the bucket policy grants only that distribution, so there is exactly one public door — one you can cache, log, rate-limit and put a WAF in front of. Direct public bucket reads give you none of that.
  • Why is a grant to the AuthenticatedUsers ACL group considered public?
    Because "authenticated" means holding *any* AWS credentials anywhere in the world, not being a member of your account or organisation. Anyone can create an AWS account in minutes, so the group is effectively the internet with an extra signup step. S3 classifies it as public for exactly that reason.

saying these in an interview costs you the question

  • Thinks Block Public Access is a single on/off flag
  • Assumes enabling BPA retroactively fixes existing public grants
  • Reads AuthenticatedUsers as "users in my account"
  • Checks only the bucket setting and ignores the account-level one
  • Believes public content requires a public bucket

context