Your S3 Website Returns 403. Make the Bucket Public?
Scenario
A site that serves its content from S3 has started returning 403 AccessDenied — the same setup worked fine in another environment. In this account, Block Public Access is enabled at both the account and the bucket level, the application in front of the bucket has its own IAM role, and the bucket holds more than just the public pages: some objects in it were never meant to be shared. A deadline is looming and the site is down.
The Quick Fix on the Table
A teammate proposes the sledgehammer: switch off Block Public Access and attach a bucket policy granting public read on everything. The 403s vanish immediately, the demo works, everyone moves on.
The quick fix is on the table and the room is waiting for your call. Would you sign off on it? Take a position and justify it — out loud or on paper — before revealing the analysis.
Why the Quick Fix Fails
- It publishes everything, not the website. A public-read bucket policy exposes every object — including the sensitive files that share the bucket. The 403 becomes a data exposure with a better error code.
- Public buckets are found within hours. Open S3 buckets are continuously enumerated by scanners, and "temporarily public" buckets are behind a long line of well-known breach headlines. There is no such thing as an unlisted public bucket.
- It dismantles a deliberate guardrail. Block Public Access is on at the account level because someone decided no bucket here should ever be public. Disabling it to fix a 403 overrides a security decision to solve a configuration bug.
- It doesn't answer why access broke. The setup works elsewhere, so something differs — the IAM role's policy, the bucket policy, encryption keys, ownership. Making the bucket public routes around the misconfiguration instead of finding it, and it will bite again at the next environment.
- It creates cost and abuse exposure. A public bucket serving directly means anyone can generate unlimited GETs against your storage bill, with no caching layer, throttling or WAF in front.
The interviewer nods: “Fine, the quick fix is off the table. So what exactly would you do — step by step?” Sketch your plan before revealing the approach.
The Right Approach
- Diagnose the 403 precisely. Reproduce the failing call with the app's actual identity:
aws s3api get-object --bucket site-bucket --key index.html /tmp/outunder the role's credentials. The error detail plus a look at CloudTrail'sAccessDeniedevents usually names the failing condition directly. - Compare against the working environment. Diff the IAM role policy, bucket policy, KMS key policy (SSE-KMS denials look exactly like this), and object ownership settings between the two environments — one of them differs.
- Grant the application scoped access. The app's IAM role needs
s3:GetObjectonarn:aws:s3:::site-bucket/*(and the KMS decrypt permission if encrypted) — a policy naming one principal and one bucket, not the internet. - Serve the public site through CloudFront with Origin Access Control. Keep the bucket private, let CloudFront sign its origin requests via OAC, and add a bucket policy allowing
s3:GetObjectonly to the CloudFront service principal scoped to your distribution ARN. Visitors get the site; the bucket stays sealed. - Separate public assets from private data. Mixed-sensitivity buckets are what make "just make it public" catastrophic. Move website assets into their own bucket so access policy matches content classification.
- Keep Block Public Access on and alarmed. Leave the account-level setting enabled and add an AWS Config rule or CloudTrail alert on any attempt to change it — the guardrail plus a tripwire.
Final pushback: “Your plan costs more time and money than the quick fix. Convince me.” How do you defend your position under pressure?
How to Defend It
- "Public read on this bucket doesn't publish the website — it publishes everything in the bucket, including the files we explicitly never wanted shared."
- "Open buckets get found by scanners in hours, not months. 'Public until after the deadline' is a breach schedule, not a workaround."
- "The same setup works in the other environment, so this is a diff, not a mystery — role policy, bucket policy or KMS key. Finding it takes less time than the incident review for a data exposure."
- "CloudFront with Origin Access Control gives the public exactly the site and nothing else, with caching and TLS included — strictly better than a naked public bucket even ignoring security."
- "Block Public Access is on at the account level because someone made that call deliberately. If we think the call is wrong, we escalate it — we don't switch it off under deadline pressure."