skip to content

A compliance team requires that audit logs in S3 cannot be deleted by anyone — including an administrator whose credentials are stolen — for seven years. How would you build that on S3, and what are the tradeoffs of the mode you choose?

level: seniorimportance: should knowfreq 45%

answer

  1. versioning makes deletes recoverable, not impossible
  2. WORM enforced below IAM
  3. two modes: one has an escape hatch, one does not
  4. the escape hatch is a permission plus a header
  5. an on/off flag with no end date

basics

~20 s

Enable S3 Object Lock on the versioned bucket with a seven-year default retention in compliance mode, so no principal — including the account root user — can shorten it or delete a protected version. Governance mode is the reversible, testable alternative.

solid answer

~50 s

Versioning alone is not enough: a principal holding `s3:DeleteObjectVersion` can walk the version list and destroy everything. The write-once control is **S3 Object Lock**, which requires versioning and applies retention to individual object *versions*. In **governance mode**, a retained version can still be deleted or its retention shortened by a principal holding `s3:BypassGovernanceRetention` who sends `x-amz-bypass-governance-retention: true` — useful for testing and for mistakes. In **compliance mode**, nobody can, root included, until the retain-until date passes; that is the mode a regulator wants and the one that will bite you, because a wrong retain-until date means paying to store that data for seven years with no escape. **Legal hold** is the orthogonal control: an on/off flag with no expiry, toggled with `s3:PutObjectLegalHold`, for objects frozen by litigation. I would set a bucket default retention, pilot in governance mode, then switch to compliance once the pipeline is proven.

code

bash · 14 lines
bash
# Bucket-wide default: every new version gets 7 years of COMPLIANCE retention
aws s3api put-object-lock-configuration --bucket audit-logs \
  --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Years":7}}}'

# Per-object override, plus an open-ended legal hold
aws s3api put-object --bucket audit-logs --key 2026/08/audit.json.gz \
  --body audit.json.gz \
  --object-lock-mode GOVERNANCE \
  --object-lock-retain-until-date 2033-08-21T00:00:00Z \
  --object-lock-legal-hold-status ON

# Break-glass delete: valid only in GOVERNANCE mode, and only with the permission
aws s3api delete-object --bucket audit-logs --key 2026/08/audit.json.gz \
  --version-id "$VERSION" --bypass-governance-retention

go deeper

for a junior

Know that S3 Object Lock is the write-once feature, that it requires versioning, and that it comes in two retention modes plus a separate legal hold.

for a middle

Explain the mechanics: retention applies per object version, governance mode is escapable with s3:BypassGovernanceRetention and the bypass header, compliance mode is not, and legal hold has no expiry.

for a senior

Show production judgment — pilot in governance mode, isolate locked data in its own bucket and account, pair retention with archival transitions for cost, and recognise that delete markers still hide keys without breaking the lock.

for a principal

Own the commitment: compliance mode is a multi-year financial and operational obligation, so decide the retention taxonomy, who may set it, how mis-ingest is prevented upstream, and how the estate is audited against the regulator's actual requirement.

## Why versioning is not the answer on its own Versioning makes deletion *recoverable*, not *impossible*. A `DELETE` without a version ID only inserts a delete marker — but a principal with `s3:DeleteObjectVersion` can enumerate versions and remove each one permanently. In a credential-compromise or malicious-insider scenario, that is exactly what happens. IAM can narrow who holds that action, and MFA delete can gate it further, but both are still *policy*, and policy is editable by whoever can edit policy. Object Lock is different in kind: it is enforced by the storage service below IAM, so no policy edit unlocks it. ## The building blocks **Prerequisite: versioning enabled.** Object Lock protects specific object *versions*; without version IDs there is nothing to protect. Object Lock was historically only settable at bucket creation; AWS now also supports enabling it on an existing bucket that has versioning on. **Retention modes.** Each protected version carries a mode and a retain-until date: - **GOVERNANCE** — the version cannot be deleted or its retention shortened by ordinary principals, but a principal holding `s3:BypassGovernanceRetention` can override it by sending the `x-amz-bypass-governance-retention: true` header. This is the mode for internal protection against accident, and the mode you pilot with. - **COMPLIANCE** — no principal can delete the version or shorten the retain-until date before it expires. Not an administrator, not the account root user, not AWS Support. Retention can only be *extended*. **Legal hold.** A separate boolean on a version, with no date attached. While it is on, the version cannot be deleted, regardless of any retention period; it is removed by a principal with `s3:PutObjectLegalHold`. Use it for the litigation case where the end date is unknown. **Default retention.** A bucket-level rule that stamps a mode and a duration (`Days` or `Years`) onto every new object version, so applications do not have to remember per-request headers. ```bash aws s3api put-object-lock-configuration --bucket audit-logs \ --object-lock-configuration '{"ObjectLockEnabled":"Enabled", "Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Years":7}}}' ``` Per-object overrides use `--object-lock-mode`, `--object-lock-retain-until-date` and `--object-lock-legal-hold-status` on `PutObject`, gated by `s3:PutObjectRetention` and `s3:PutObjectLegalHold`. ## What Object Lock does *not* stop This is where candidates go wrong. Object Lock prevents deletion of a *version*; it does not freeze the *key*. - New versions can still be PUT to the same key. The protected version stays, immutable, underneath. - A version-less `DELETE` still succeeds and inserts a delete marker. The key reads as 404 while every locked version remains intact and recoverable. That is intentional and does not violate the lock. - The **bucket cannot be deleted** while it holds locked versions, since bucket deletion requires an empty bucket. In compliance mode that means the bucket is pinned for the full retention. - Lock does not encrypt, does not authenticate readers, and does not stop copying data out. ## The tradeoff to say out loud Compliance mode converts a storage decision into a **financial and operational commitment**. Seven years of retention on a mis-sized ingest — a debug log accidentally routed into the bucket, a retain-until date computed with the wrong unit, a runaway producer — is seven years of storage you must pay for and cannot delete. There is no support ticket that undoes it. The mitigations are all upstream of the lock: 1. Pilot the whole pipeline in **governance mode**, with the bypass permission held by exactly one break-glass role, and switch the default to compliance only once volumes and dates are proven. 2. Put the locked data in its **own bucket, and preferably its own account**, so a mistake in one workload cannot pin unrelated data, and so a compromised administrator in the producing account cannot reach the bucket's configuration. 3. Combine with a **lifecycle transition** to a cheap archival storage class so seven years of immutable data is not seven years at Standard prices; transitions change storage class, not content, so they coexist with retention. 4. Replicate the locked bucket to a **second account or region** — S3 Replication supports objects protected by Object Lock — so durability does not depend on one account staying healthy. ## Where MFA delete fits MFA delete is the older, weaker sibling: configured on the same `PutBucketVersioning` call, it requires the bucket owner's **root** user credentials plus an MFA token to permanently delete a version or change the bucket's versioning state. It is genuinely strong against stolen IAM credentials, but it forces root usage into a routine operation, it can only be configured via the CLI, SDKs or REST API rather than the console, and S3 does not support lifecycle configuration on a bucket with MFA delete enabled — so noncurrent versions cannot be expired automatically. For a modern seven-year retention requirement, Object Lock in compliance mode is the answer, and MFA delete is at most a supplementary control on a small, sensitive bucket.

  • With Object Lock in compliance mode, can a user still make the object disappear from a normal listing?
    Yes, and that is expected. A version-less DELETE inserts a delete marker, so the key returns 404 and vanishes from ListObjectsV2, while every locked version stays intact and readable by version ID. Object Lock protects versions from destruction, not keys from being shadowed; removing the marker restores normal reads.
  • Where does MFA delete still make sense compared with Object Lock?
    Rarely, and only on small, high-value buckets. MFA delete requires the root user's MFA token to permanently delete a version or change the versioning state, which is strong against stolen IAM credentials but forces routine root usage, cannot be configured from the console, and blocks lifecycle configuration on the bucket. Object Lock scales; MFA delete does not.
  • What is the failure mode of choosing compliance mode too early?
    An unrecoverable cost and capacity commitment. A wrong retain-until date, a mis-routed producer, or a duplicated ingest pins that data for the entire period with no override — not by an administrator, not by root, not by AWS Support. Pilot in governance mode with a single break-glass role, and isolate the workload in its own bucket and account first.
  • How would you keep seven years of immutable logs from costing seven years of Standard storage?
    Layer a lifecycle transition onto the same objects. Transitions change storage class rather than content, so they are compatible with Object Lock: move the versions to an archival class after the access window closes while retention keeps them undeletable. Cost control and immutability are independent levers on the same object.

saying these in an interview costs you the question

  • Says versioning alone makes a bucket ransomware-proof
  • Thinks a bucket policy can override compliance-mode retention
  • Believes root or AWS Support can remove a compliance lock
  • Confuses legal hold with a retention period that expires
  • Assumes Object Lock prevents writing new versions of the key

context