Every AWS engineer ends up writing the same handful of S3 bucket policies over and over — enforce HTTPS, let CloudFront in, let another account in, keep everyone else out. This page is the cheatsheet we wish existed the first time: ten ready-to-use policies covering the scenarios that come up in real projects (and in SAA-C03 exam questions), each with a copy-paste JSON block and a short note on the gotcha that usually bites people. Bookmark it, grab what you need, swap in your bucket name, and move on.
Info: Placeholders Used Below
Replace your-bucket-name with your bucket, 111122223333 / 444455556666 with real AWS account IDs, and the example VPC endpoint, distribution, and role names with your own. Every policy here uses Version 2012-10-17 — always keep that line exactly as written; it is the policy language version, not a date to update.
Bucket Policy Anatomy in 60 Seconds
A bucket policy is a resource-based IAM policy attached directly to the bucket. Each statement answers four questions: who (Principal), can or cannot (Effect), do what (Action), on what (Resource) — optionally narrowed by a Condition. Before copying anything below, four rules will save you hours of debugging:
- ●Object actions like s3:GetObject need the /* resource (arn:aws:s3:::your-bucket-name/*); bucket actions like s3:ListBucket need the bare bucket ARN. Most "Access Denied" surprises are one of these two missing
- ●An explicit Deny always wins — over the bucket policy itself, over IAM policies, over everything. Test Deny statements carefully; you can lock yourself out
- ●S3 Block Public Access sits above the bucket policy. A public-read policy does nothing until the relevant block settings are turned off for that bucket
- ●Bucket policies max out at 20 KB — if you are hitting the limit, move principal-specific grants into IAM policies and keep the bucket policy for guardrails
Quick Reference — Which Policy Do You Need?
1. Enforce HTTPS-Only Access
The single most common bucket policy in existence, and a baseline requirement in most compliance frameworks. It denies every S3 action made over plain HTTP. Safe to apply to almost any bucket — the SDKs, CLI, and console all use HTTPS by default.
2. Public Read for Static Website Hosting
For buckets serving a static website directly (no CloudFront). Grants everyone read access to objects — and only read: no listing, no writes.
Warning: Block Public Access Must Be Off First
New buckets ship with Block Public Access enabled, which silently overrides this policy. Turn off "Block public access granted through new/any public bucket policies" for this one bucket — never at the account level. If the site can sit behind CloudFront instead, use policy #3 and keep the bucket fully private.
3. CloudFront-Only Access (Origin Access Control)
The modern replacement for public website buckets: the bucket stays completely private, and only your CloudFront distribution can fetch objects. This is the policy CloudFront generates when you attach an Origin Access Control (OAC) — the SourceArn condition pins it to one specific distribution.
4. Cross-Account Read Access
Lets every principal in a second AWS account (that also has matching IAM permissions on their side) list the bucket and read objects. Using the account root ARN delegates the fine-grained "who exactly" decision to that account's own IAM policies — to grant a single role instead, put the role ARN in Principal (see policy #9).
5. Restrict Access to a VPC Endpoint
For buckets that should only ever be touched from inside your VPC — data lakes, internal app storage, anything that must never traverse the public internet. Requests that do not arrive through the named gateway endpoint are denied, no matter whose credentials they carry.
Warning: This Locks Out the Console — Including You
The AWS console does not go through your VPC endpoint, so this Deny blocks console access to the bucket for everyone, admins included. Before applying, add an escape hatch — e.g. an extra condition excluding your admin role via ArnNotEquals on aws:PrincipalArn — or be prepared to manage the bucket purely from inside the VPC.
6. Allow Only Your Office / VPN IP Range
A simple perimeter for buckets holding internal reports or tooling: any request from outside the listed CIDR ranges is denied. Note that aws:SourceIp checks the public IP AWS sees — traffic arriving through a VPC endpoint carries a private IP and needs policy #5 instead.
7. Enforce SSE-KMS Encryption on Every Upload
S3 has encrypted all new objects with SSE-S3 by default since January 2023, so a bare "must be encrypted" policy is now redundant. What teams actually enforce today is the stronger requirement: uploads must use SSE-KMS (customer-managed key, CloudTrail-audited key usage), not just the S3-managed default.
Tip: Simpler Alternative: Set It as the Bucket Default
If you set the bucket's default encryption to your KMS key, uploads without an encryption header get your key automatically — this policy then only catches uploads that explicitly request the wrong method. Belt and suspenders: do both.
8. Restrict Access to Your AWS Organization
For shared buckets in multi-account setups: any principal from any account inside your AWS Organization can be granted access by their own IAM policies, but nothing outside the org gets in — even if credentials leak. One condition replaces maintaining a list of account IDs.
Note: AWS Service Principals Have No Org ID
Services like CloudTrail or ELB logging that write to your bucket as a service principal will be denied by this policy, because service principals carry no aws:PrincipalOrgID. If the bucket receives service-delivered logs, add a second condition — BoolIfExists on aws:PrincipalIsAWSService — to exempt them.
9. Grant One IAM Role Read/Write
The workhorse policy for application buckets: exactly one role — your app server, Lambda execution role, or CI/CD deployer — gets full object CRUD plus listing, and the bucket policy documents that contract explicitly at the bucket itself.
10. Require MFA for Deletes
A guardrail for buckets holding backups or critical documents: object deletions are denied unless the caller authenticated with MFA. BoolIfExists makes the condition also catch requests where the MFA key is absent entirely (e.g. long-term access keys).
Note: Roles Never Have MFA
IAM roles (including service and Lambda roles) can't present MFA, so this policy blocks all role-based deletions too. Use it on human-managed buckets only — and note it is different from S3 Versioning's "MFA Delete" feature, which is a separate root-user-only versioning setting.
How to Apply a Bucket Policy
Console: bucket → Permissions tab → Bucket policy → Edit → paste → Save. From the CLI, save the JSON to a file and run:
Warning: put-bucket-policy Replaces, Never Merges
A bucket has exactly ONE policy document. Applying a new one overwrites whatever was there. To combine scenarios from this cheatsheet (e.g. HTTPS-only + CloudFront-only), put multiple statements inside one Statement array, then apply once. Validate first with the IAM Policy Simulator or IAM Access Analyzer — both flag typos and unintended public access before they bite.
Where This Shows Up in Certification Exams
S3 security is heavily tested: the SAA-C03 exam's Secure Applications domain is 30% of your score, and bucket-policy questions — spot the missing /* resource, pick the right condition key, explain why an Allow isn't working under Block Public Access — appear on nearly every attempt. Test yourself against our free SAA-C03 mock exam (60 original scenario questions with explanations), or start with the CLF-C02 Cloud Practitioner mock if you're earlier in the journey. And if you want to build these policies hands-on with a trainer walking you through the gotchas live, our 45-day AWS batch covers S3 security end-to-end with real labs.
Ready to Start Your Cloud Journey?
Live batches Mon–Sat — Azure 9–10 AM IST (started 24 august 2026 — join in progress) · AWS 10:30–11:45 AM IST (starts 31 august 2026). Hands-on labs, exam prep, and community support.