// Policy for the ops-cron backup job (.forgejo/workflows/ops-cron.yml). // // Exists to DELETE FOUR CI SECRETS. Today S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY and // S3_SECRET_KEY are Forgejo repo secrets, even though ops-cron only ever uses them // INSIDE the script it SSHes onto the host — they are passed through `envs:` and // consumed as RCLONE_CONFIG_ARCHIVE_*. Nothing needs them on the runner. Moving them // here means the host reads them directly and CI holds four fewer credentials. // // It also collapses a genuine duplication: the same values already live in the SOPS // vault as THERMOGRAPH_S3_* in common.yaml, so there are currently two sources of // truth for one credential pair, free to drift. // // The backup recipient belongs here too — see thermograph/data/ops/backup below. // ops-cron.yml:142 and :197 currently HARDCODE the age recipient as a literal, in two // places, and that same public key is duplicated in eleven places across the repo. path "thermograph/data/ops/backup" { capabilities = ["read"] } path "thermograph/metadata/ops/backup" { capabilities = ["read", "list"] } // ============================================================================ // THE AGE KEY IS NOT RETIRED BY THIS MIGRATION. This path is why. // ============================================================================ // ops-cron.yml streams every off-box database dump through // `pg_dump | age -r | rclone rcat`, with 30-day S3 retention, and restore // depends on the private half at /etc/thermograph/age.key. The Forgejo backup path is // the same shape. // // So the age keypair is not merely the SOPS transport — it is the BACKUP ENCRYPTION // KEY. Deleting it alongside the SOPS vault files would silently destroy up to 30 days // of database recoverability, and nothing would notice until a restore was attempted. // // Therefore: the age private key is stored at thermograph/data/legacy/age (operator // access only, deliberately NOT granted by this policy) and kept on disk until either // the newest age-encrypted object in S3 has aged out, or the backup path is re-pointed // at a dedicated backup recipient. Only then may /etc/thermograph/age.key be removed. // // The `deny` is explicit so that widening this policy cannot hand the backup job the // key to read everything else in the estate. path "thermograph/data/legacy/age" { capabilities = ["deny"] } path "auth/token/lookup-self" { capabilities = ["read"] }