Replace the gitignored plaintext infra/tofu/.r2.env and backend.hcl with a
single committed, SOPS/age-encrypted dotenv (secrets.sops.env) plus a thin
wrapper (tf.sh), so tofu runs with no manual secret entry and secrets live
encrypted in git like the repo's other secrets.
- .sops.yaml: creation rule encrypting infra/tofu/secrets.sops.env (all values)
to the existing age recipient.
- secrets.sops.env: encrypted, PLACEHOLDER values only. Holds R2 S3 keys, the
state-encryption passphrase (TF_STATE_PASSPHRASE scalar), and the Proxmox API
token/endpoint. Operator fills real values via `sops`.
- tf.sh: sops exec-env decrypts the dotenv, exports PROXMOX_VE_*/AWS_*, builds
the multi-line TF_ENCRYPTION HCL from TF_STATE_PASSPHRASE, and runs tofu
(injecting -backend-config=backend.r2.hcl on init). Proxmox token stays env-only,
never a tofu variable/state.
- backend.r2.hcl: committed non-secret R2 bucket/key/endpoint (account id is not
a credential), passed to `tofu init`.
- Retire .r2.env/backend.hcl(.example): drop the committed templates; keep the
gitignore lines as a safety net for leftover local plaintext.
- Update backend.tf/README/REMOTE-STATE for the new day-2 flow and DR story
(repo + age key is sufficient).
Verified: placeholder file round-trips sops -e/-d with the repo age key; tf.sh
exports the expected VAR NAMES and builds valid TF_ENCRYPTION HCL (stub tofu, no
real plan/secrets).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Two dev.sh gaps surfaced while running bootstrap/sops/install-age-key.sh:
- kubectl defaulted to localhost:8080 (connection refused) because KUBECONFIG
was never set in the toolbox. Set KUBECONFIG=/work/infra/ansible/.cache/dev.kubeconfig
(override via DEV_KUBECONFIG); --network host already reaches 10.73.0.11:6443.
- age-keygen.sh writes the PRIVATE key to ~/.config/sops/age/keys.txt, but that
path was not mounted in the --rm container, so the key was lost on exit. Mount
${HOME}/.config/sops -> /root/.config/sops (created first) so the key persists
on the host and SOPS_AGE_KEY_FILE resolves to it.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>