Guides / Immutable backups with Object Lock

Immutable backups with S3 Object Lock

An attacker who gets into a cloud account often deletes the backups before touching the database, so there is nothing to restore from. A cleanup script with the wrong prefix does the same by accident. If the credentials that reach your database can also delete its backups, one stolen key loses both. With S3 Object Lock, the storage provider refuses to delete or overwrite a locked object before its retention date, whoever asks.

How Object Lock works

Object Lock is a bucket setting that needs versioning on. Each object version can carry a retention date. Until that date, no request can delete that version or shorten its date. It can only be extended. A bucket can also have a default retention, which locks every new object for a fixed number of days without the writer asking.

There are two modes:

ModeWho can remove the lock earlyUse it for
ComplianceNobody, including the account's root user.Backups that have to survive stolen administrator credentials.
GovernanceAnyone with the s3:BypassGovernanceRetention permission.Guarding against accidents while keeping an escape hatch.

A legal hold is a separate flag with no date. It blocks deletion until someone with permission removes it, and is meant for litigation rather than routine backups.

Set up a locked bucket on AWS

# Object Lock on from creation; this also turns on versioning
aws s3api create-bucket --bucket acme-db-backups \
  --object-lock-enabled-for-bucket \
  --create-bucket-configuration LocationConstraint=eu-west-1
# lock every new object for 14 days in compliance mode
aws s3api put-object-lock-configuration --bucket acme-db-backups \
  --object-lock-configuration \
  '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":14}}}'

In us-east-1, leave out --create-bucket-configuration. Try a short retention on a test bucket first. A compliance lock set by mistake cannot be undone, and you pay for the storage until it expires.

Then take away the delete permission from every key that writes backups. The lock stops early deletion, and a key without s3:DeleteObject cannot even add a delete marker that hides a backup from normal listings.

What retention costs

Every locked copy is stored until its date, so the lock length multiplies with backup frequency. Hourly backups locked for 30 days means about 720 copies stored at any time. The usual answer is tiers: lock every backup for a short time, and keep the first backup of each day, week and month for longer.

ScheduleCopies kept at once
Hourly, every copy locked 30 daysAbout 720
Hourly locked 2 days, plus 14 daily, 4 weekly and 12 monthlyAbout 78

A lifecycle rule cannot tell a daily copy from an hourly one, so the tier has to be decided when each backup is written, by setting its retention date on upload.

Which providers support it

ProviderObject Lock
AWS S3Yes, compliance and governance modes.
Backblaze B2Yes, through its S3-compatible API. Turn it on when you create the bucket.
WasabiYes, when turned on for the bucket.
MinIOYes, on a bucket created with mc mb --with-lock.
DigitalOcean SpacesNo.
Cloudflare R2Check R2's current documentation for your bucket before relying on it.

Whatever the provider, test it: write an object with a retention date, try to delete that version, and confirm the request is refused.

What a lock does not protect

How SafeGrd does it

SafeGrd writes every backup under compliance-mode Object Lock, in your bucket or in its hosted storage, and sets each backup's retention date on upload so daily, weekly and monthly copies can be kept longer (tiers). The console's setup wizard writes a host key policy that cannot delete, and safegrd doctor checks that the bucket really has Object Lock on. For a provider without it, you have to set worm_mode: "NONE" on purpose, and SafeGrd then shows those backups as deletable. Threat Shield flags a backup that lost most of its rows, and Fire Drills restore the newest one on a schedule.