# ADR-0007 — Secrets: SOPS + age - Status: Accepted - Date: 2026-08-15 - Serves: R-SEC-01, R-GITOPS-01 - Supersedes: — ## Context Secrets (VPN keys, DNS API token, SMTP creds, service passwords, backup-target creds) must live in git for GitOps but MUST NOT be plaintext. The engine is Flux (ADR-0004), which decrypts SOPS natively. ## Decision Encrypt secrets in git with **SOPS** using **age** recipients; **Flux decrypts in-cluster** at reconciliation via an age private key bootstrapped as a Kubernetes Secret. Plaintext secrets never enter git or logs. Secret rotation = re-encrypt + commit; Flux rolls it out (restart triggered by checksum annotation where needed). ## Alternatives considered - **Sealed Secrets (Bitnami)** — solid; one-way encryption to a cluster key. SOPS chosen for native Flux integration, multi-recipient/age simplicity, and readable, reviewable encrypted diffs. - **External Secrets Operator + external vault (Vault/cloud SM)** — stronger for large orgs but adds an external dependency and operational weight not justified for a single-operator home platform. May be revisited via superseding ADR if a real external secret store is introduced. - **Plaintext + private repo** — rejected outright (R-SEC-01). ## Consequences - Secrets are versioned, encrypted, and reconciled with the rest of GitOps state. - The **age private key bootstrap** is a sanctioned out-of-band step (documented; one of the few non-GitOps actions, [07](../docs/07-security-and-secrets.md)). - Key custody/rotation for the age key itself must be documented; losing it blocks decryption. - No secret material may appear in agent output, PRs, or logs ([AGENTS.md §5](../AGENTS.md)).