Files
home-network-k3s-impl/bootstrap/sops

bootstrap/sops — SOPS + age key material & decryption wiring (Phase 1, T-1.4)

Generates the age keypair, declares SOPS creation rules, and documents how the age private key is installed into the cluster so Flux can decrypt SOPS at reconcile. Spec: ADR-0007 (SOPS+age), docs/07 · Requirement: R-SEC-01 (secrets encrypted at rest in git, decrypted only in-cluster).

AUTHOR-ONLY. Nothing here has been executed. No key or secret material exists in this output. No age-keygen, sops, or kubectl was run. The age keypair is generated later by the operator; .sops.yaml carries only a placeholder for the public recipient.

Files

File Purpose
age-keygen.sh Operator-run script: generates the age keypair to a path outside the repo, prints only the public recipient. Refuses to write inside the repo or clobber an existing key.
.sops.yaml SOPS creation rules (encrypt only data/stringData → readable diffs). age: recipient is a clearly-marked REPLACE-ME placeholder filled at bootstrap. Effective home is the repo root (see below).
age-key-secret.md Runbook + kubectl create secret template installing the age private key as the sops-age Secret in flux-system (the sanctioned out-of-band step). Rotation + DR custody included.

How this satisfies R-SEC-01 / ADR-0007

  • Secrets are committed encrypted (sops --encrypt) using the age public recipient in .sops.yaml; plaintext never enters git (.gitignore guards age.key, *.key, *.dec.yaml).
  • Flux decrypts in-cluster using the age private key held in the sops-age Secret — the one documented out-of-band bootstrap action (docs/07, ADR-0007 Consequences).
  • decryption.provider: sops + secretRef: sops-age on the platform/apps Flux Kustomizations is wired by ../flux/patches/ (realising the commented TODOs in clusters/base).
  • No key material appears in scripts, docs, PRs, or logs (AGENTS.md §5).

Interface / handoff

  • .sops.yaml belongs at the REPOSITORY ROOT. SOPS discovers it by walking up from the file being encrypted, so it only governs platform/** and apps/** from root. It is authored here (in this worker's subtree); the PM/clusters owner installs it at the repo root (copy or symlink). Flagged as an escalation in the T-1.4 report.
  • Fill two placeholders at bootstrap: the age: recipient in .sops.yaml (from age-keygen.sh's output) — same value in both creation rules.
  • Order (see ../flux/README.md): age-keygen.sh → install sops-age Secret (age-key-secret.md) → ../flux/bootstrap.sh. The Flux entrypoint fails fast if the Secret is missing.