# WORM buckets

Make the destination immutable, so ransomware and stolen credentials can't touch your backups.

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.

## How gitdr treats it

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.

## Set one up

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

```sh
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:

```sh
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](https://learn.microsoft.com/azure/storage/blobs/immutable-version-level-worm-policies)).

## S3-compatible providers

"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 | 90-day minimum retention |
| Backblaze B2 | yes | enable at bucket creation, versioning required |
| MinIO / IDrive e2 | yes | create the bucket with object lock |
| Cloudflare R2 | no | works as a destination, gitdr warns, no WORM |

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`.

## Credential scoping

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.