AWS S3 Bucket Hardening Cheat Sheet
A practical checklist for locking down S3 buckets — access, encryption, logging, and the CIS controls each item maps to. Baseline as of September 2026.
S3 misconfiguration remains one of the most common sources of cloud exposure — not because the controls are exotic, but because defaults drift and new buckets get spun up faster than audits catch up. This is a working checklist, not a compliance document: pull from it, don't treat it as complete for your environment.
What changed recently
April 2026: AWS began disabling SSE-C (server-side encryption with customer-provided keys) by default for all new general-purpose buckets and for existing buckets in accounts with no prior SSE-C usage. If your account has never used SSE-C, this needs no action. If you do rely on it, new buckets will reject SSE-C requests with a 403 until you explicitly re-enable it via PutBucketEncryption. AWS's own guidance is to leave it disabled unless you have a specific reason — SSE-S3 or SSE-KMS covers most use cases with far less operational friction, since SSE-C requires the caller to supply the key on every single request.
Access control
- [ ] S3 Block Public Access enabled at both the bucket level and the account level — CIS AWS Foundations Benchmark v5.0.0 control 2.1.4 (Security Hub
S3.1/S3.8) - [ ] Object Ownership set to "Bucket owner enforced" (ACLs disabled) — the default for new buckets, and worth confirming on anything older, since it leaves IAM/bucket policy as the only access layer instead of a second, easy-to-miss one
- [ ] No bucket policy grants
"Principal": "*"or a wildcard"Action": "*"without a tightly scoped condition alongside it - [ ] Least-privilege IAM — grant the specific actions a role needs, not
s3:* - [ ] Applications and services use IAM roles for temporary credentials, not long-lived access keys hardcoded into an application or stored on an EC2 instance
Encryption
- [ ] Server-side encryption confirmed on — SSE-S3 is the default for every bucket; move to SSE-KMS where you need customer-managed key control and a CloudTrail audit trail on key usage
- [ ] SSE-C left disabled unless there's a specific, documented need (see above)
- [ ] HTTPS enforced via an
aws:SecureTransportcondition in the bucket policy — CIS 2.1.1 (S3.5)
Versioning & recovery
- [ ] S3 Versioning enabled — the baseline protection against accidental overwrite or delete
- [ ] MFA Delete enabled on any bucket storing something sensitive or irreplaceable — CIS 2.1.2 (
S3.20) - [ ] S3 Object Lock (WORM) on logs and anything compliance-critical — a common example is locking down your own CloudTrail log bucket so an attacker with write access can't cover their tracks
- [ ] Cross-Region Replication for buckets that need redundancy beyond S3's default multi-AZ storage (requires versioning enabled on both source and destination)
Logging & monitoring
- [ ] S3 server access logging enabled
- [ ] CloudTrail data events enabled for object-level Get/Put/Delete — this is what actually tells you who touched a specific object, not just that the bucket exists (Security Hub
S3.22write events /S3.23read events) - [ ] AWS Config managed rules in place:
s3-bucket-public-read-prohibited,s3-bucket-public-write-prohibited,s3-bucket-versioning-enabled,s3-bucket-logging-enabled,s3-bucket-ssl-requests-only - [ ] IAM Access Analyzer for S3 turned on — it flags any bucket reachable from outside the account, including exposure paths a manual policy review can miss
Detection
- [ ] GuardDuty S3 Protection enabled — anomaly detection over CloudTrail management and data events specific to S3
- [ ] Macie turned on for any bucket that might hold PII or financial data — automated sensitive-data discovery instead of hoping someone remembers what's in there
- [ ] Security Hub CSPM running the CIS AWS Foundations Benchmark v5.0.0 standard for continuous drift detection across everything above
A note on the control numbers
The CIS mappings above are for v5.0.0, the version AWS Security Hub currently recommends. If your org's compliance tooling still references an older version (v1.2.0, v1.4.0, or v3.0.0), the same underlying checks exist but under different section numbers — for example, "Block Public Access" is 2.1.4 in v5.0.0/v3.0.0 but 2.1.5 in v1.4.0. Worth confirming which version a given audit report is actually citing before assuming a control number lines up.
Automating this instead of auditing it by hand
Most of the access-control items above are exactly the kind of thing worth codifying instead of checking manually every quarter. This issue's OSS Spotlight covers Cloud Custodian, an open-source policy engine whose own example policy is, fittingly, a five-line YAML file that finds S3 buckets with cross-account access and removes it.
Sources: AWS — Security best practices for Amazon S3 · AWS — Default SSE-C setting for new buckets · AWS Security Hub — CIS AWS Foundations Benchmark control mapping