--- description: "Use when working with SOPS in this repo: editing secrets, adding multiline values, changing recipients, or wiring sops-nix consumers. Captures repo conventions, safe commands, and validation habits." applyTo: ".sops.yaml, keys/secrets.yaml, modules/hosts/**/secrets.yaml, modules/hosts/**/*.nix, modules/programs/sops.nix, modules/features/**/*.nix, modules/services/**/*.nix" --- # Using SOPS In This Repo This repo treats SOPS files as the source of encrypted runtime material, and Nix code as the wiring that exposes those secrets to services. Keep those roles separate: edit secret values with SOPS, consume them through sops-nix paths, and keep recipient policy scoped to the machines or operators that actually need access. ## Mental Model - Secrets live in encrypted YAML files; Nix modules should refer to secret paths, not decrypted values. - Host-only credentials belong in `modules/hosts//secrets.yaml`. - Shared credentials belong in `keys/secrets.yaml` only when multiple hosts intentionally consume the same material. - `.sops.yaml` controls who can decrypt each file; keep those recipient sets narrow and explicit. - Secret key names are an interface. Rename them only when every consumer changes in the same edit. ## Editing Secrets - Use SOPS tooling for all value changes: `sops `, `edit-secrets`, or `sops set ...`. - Do not hand-edit `ENC[...]` payloads. That bypasses SOPS and breaks the encrypted document's integrity metadata. - Keep plaintext out of tracked files. Temporary plaintext files are acceptable only as local working inputs and should be removed after use. - Prefer `SOPS_EDITOR=nvim sops ` for interactive edits when editor choice matters. For large or generated values, avoid putting the secret directly in shell history: ```bash sops set --value-file '["parent"]["key"]' /path/to/plaintext-value ``` If using inline `sops set`, the value argument must be valid JSON. ## Multiline Values Use YAML literal blocks for private keys, certificates, provisioner keys, and other values where newlines matter: ```yaml janus: ssh_user_ca_key: |- -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- ``` - Use `|-` when the final trailing newline should be stripped. - Use `|` when the consuming program expects the final trailing newline. - Avoid folded style (`>`) for keys and certs because it rewrites line breaks. ## Wiring Secrets Into Nix - Consume secrets through `config.sops.secrets."".path` or `config.sops.placeholder` where templating requires it. - Do not read decrypted secret contents during Nix evaluation. - Set `owner`, `group`, and `mode` explicitly for non-root services. - Use `path` or `sops.templates` when a service needs a specific file layout instead of copying secret contents into the store or tracked files. - If moving a secret between shared and host-local files, update `sops.defaultSopsFile`, `mysops.hostSecretFile`, and every affected `sops.secrets` declaration together. ## Recipient And Rotation Practices - Add dedicated `.sops.yaml` `path_regex` rules for host-local files before broad fallback rules. - Keep broad fallback rules conservative; do not expand them to grant casual access to every YAML or JSON file. - Run `sops updatekeys ` after changing recipients so data is rewrapped for the new key set. - Rotate or migrate in order: update recipients, re-encrypt affected files, update consumers, then validate affected hosts. ## Validation Habits After SOPS or sops-nix changes, check the contract rather than only the syntax: 1. The expected secrets file is still selected by `sops.defaultSopsFile` or `mysops.hostSecretFile`. 2. `.sops.yaml` has a specific rule for any host-local `secrets.yaml` touched. 3. Secret names in YAML still match the `sops.secrets.""` declarations. 4. Services that need restart or reload behavior have `restartUnits` or `reloadUnits` set. 5. Affected host evaluation/build catches missing secret keys before deployment.