Skip to content

WORM (write once, read many) means objects can’t be deleted or overwritten until their retention date, not even by you, not even by an attacker holding your keys. It’s the property that makes a backup survive the bad day it exists for.

Before writing anything, gitdr probes the destination’s lock configuration. Then:

  • Lock confirmed. It proceeds and records the observed immutability in the signed manifest, so “was this backup on WORM storage” has a tamper-evident answer later.
  • No lock. It warns loudly and proceeds. Configuring WORM is your job, but you’ll never be quietly unprotected.
  • --require-worm (or worm.require: true). No confirmed lock means the run fails closed. Use this once your bucket is set up.

Independent of all that, gitdr’s storage layer has no delete or overwrite method, uploads are create-only. WORM protects you from stolen credentials; create-only protects you from gitdr itself.

AWS S3, Object Lock. Only settable at bucket creation:

Terminal window
aws s3api create-bucket --bucket my-worm-bucket --region us-east-1 \
--object-lock-enabled-for-bucket
aws s3api put-object-lock-configuration --bucket my-worm-bucket \
--object-lock-configuration \
'{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":30}}}'

COMPLIANCE mode is real WORM, nobody can shorten it. GOVERNANCE can be lifted with a special permission, which an attacker with admin can also hold. Pick COMPLIANCE.

Google Cloud Storage, locked retention policy. The lock is irreversible:

Terminal window
gcloud storage buckets create gs://my-worm-bucket --location=US \
--uniform-bucket-level-access --public-access-prevention --retention-period=30d
gcloud storage buckets update gs://my-worm-bucket --lock-retention-period

Azure Blob. Storage account with version-level immutability plus blob versioning, then a container with a time-based immutability policy (Azure docs).

“S3-compatible” is a spectrum, and Object Lock is one of the least universally implemented parts. Set destination.s3.endpoint and usually usePathStyle: true.

Provider Object Lock Notes
Wasabi yes compliance mode, Cohasset-assessed
Backblaze B2 yes enable at bucket creation, versioning required
MinIO / IDrive e2 yes create the bucket with object lock
Cloudflare R2 no bucket locks instead; gitdr cannot read them

A provider that doesn’t implement the Object Lock API can’t be confirmed immutable, so gitdr warns and proceeds, or fails closed under --require-worm.

Object Lock in this table means the provider offers it, not that the guarantee is the same everywhere. On a store you run yourself the lock stops the S3 API, not root on the host. MinIO and Ceph protect you from a stolen key, not from your own operators.

R2 is the near case. Its bucket locks do stop deletes and overwrites. An account administrator can remove the rule, so the guarantee is not the one compliance mode gives. R2 does not implement GetObjectLockConfiguration either, so gitdr reports unknown rather than immutable.

The destination credential needs create/put and read. It never needs delete, so don’t grant it. A compromised runner then can’t purge history even on a non-WORM bucket.