feat(backup): object-locked off-site buckets with optional server-side expiry #514

Sammanfogat
supernaut sammanfogade 1 incheckning från fix/465-backup-delete-credential in i main 2026-10-02 09:57:41 +00:00
Ägare

What

First slice of #465: off-site backups the host cannot destroy.

The OpenStack credential can delete the local backup volume, but not the off-site copies. The S3 keys in backup.env can: any compromise of the services user could rclone delete every off-site archive. This PR prepares object-locked buckets.

  • bitborg-backup.sh.j2: per-destination server_side_expiry flag. When true, the host skips its rclone delete prune and the bucket's lifecycle rule expires archives, so the host key can be denied s3:DeleteObject. Default false: rendered behaviour is unchanged.
  • Runbook: new "Immutable off-site copies (#465)" section with the operator steps (Glesys probe, locked bucket with COMPLIANCE 14 d, lifecycle rule, vault switch, apply, backup + drill, negative control, optional Hetzner delete-deny policy, retire old bucket after 28 d).

Limits

  • The restic [storage] tier is not protected: old base packs leave the lock window but stay in use.
  • Glesys documents no object lock, versioning or lifecycle. The runbook starts with a probe; if it fails, Glesys stays unlocked.
  • Delete markers can hide current objects; recovery via mc ls --versions.

Not in this PR (plan in #465)

ADR for the target shape, a restic writer without delete rights, separate OpenStack application credentials with access rules, network tiers, one rootless user per service.

Verification

ansible-lint 0/0, --syntax-check OK, prettier and markdownlint clean, shellcheck on the rendered script: only a pre-existing SC2086 info. Merging is inert: an apply is needed only after the vault bucket change.

Refs #465

## What First slice of #465: off-site backups the host cannot destroy. The OpenStack credential can delete the local backup volume, but not the off-site copies. The S3 keys in `backup.env` can: any compromise of the services user could `rclone delete` every off-site archive. This PR prepares object-locked buckets. - `bitborg-backup.sh.j2`: per-destination `server_side_expiry` flag. When true, the host skips its `rclone delete` prune and the bucket's lifecycle rule expires archives, so the host key can be denied `s3:DeleteObject`. Default false: rendered behaviour is unchanged. - Runbook: new "Immutable off-site copies (#465)" section with the operator steps (Glesys probe, locked bucket with COMPLIANCE 14 d, lifecycle rule, vault switch, apply, backup + drill, negative control, optional Hetzner delete-deny policy, retire old bucket after 28 d). ## Limits - The restic `[storage]` tier is not protected: old base packs leave the lock window but stay in use. - Glesys documents no object lock, versioning or lifecycle. The runbook starts with a probe; if it fails, Glesys stays unlocked. - Delete markers can hide current objects; recovery via `mc ls --versions`. ## Not in this PR (plan in #465) ADR for the target shape, a restic writer without delete rights, separate OpenStack application credentials with access rules, network tiers, one rootless user per service. ## Verification ansible-lint 0/0, `--syntax-check` OK, prettier and markdownlint clean, shellcheck on the rendered script: only a pre-existing SC2086 info. Merging is inert: an apply is needed only after the vault bucket change. Refs #465
supernaut lade till 1 incheckning 2026-10-02 08:36:52 +00:00
feat(backup): object-locked off-site buckets with optional server-side expiry
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m50s
e9fc2686a1
A compromised service on the services host can read the off-site keys
and delete every off-site archive. Document moving each destination to a
COMPLIANCE object-locked bucket, so no key can delete an archive inside
its retention window. The host's prunes then only add delete markers.

Add a per-destination `server_side_expiry` flag. When set, the backup
script skips the host-side `rclone delete` and the bucket's lifecycle
rule expires archives instead, so the host key can be denied
s3:DeleteObject (Hetzner per-key bucket policy). Unset by default, so
nothing changes until the operator has locked the bucket.

The restic storage tier is not fully covered by a fixed lock window.
That, and the OpenStack credential split, remain open.

Refs #465
supernaut tvångsskickade fix/465-backup-delete-credential från e9fc2686a1
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m50s
till 7ae584bcab
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m39s
2026-10-02 09:53:44 +00:00
Jämför
supernaut schemalade den här ändringsförfrågan för automatisk sammanfogning när alla kontroller lyckas 2026-10-02 09:53:55 +00:00
supernaut sammanfogade incheckning 4e2ba6c566 till main 2026-10-02 09:57:41 +00:00
supernaut tog bort grenen fix/465-backup-delete-credential 2026-10-02 09:57:41 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra!514
Ingen beskrivning angiven.