# SOPS Secrets Management Guide This guide covers how to manage encrypted secrets in Nix-Vibe using `sops-nix` with `age` encryption. ## Overview - **Secrets File**: `secrets.yaml` (encrypted in Git) - **Configuration**: `.sops.yaml` (public keys and creation rules) - **Private Key**: Locally stored at `~/.config/sops/age/keys.txt` (Never commit this!) ## Prerequisites The project includes `sops` in the default development environment. You can also run it temporarily: ```bash nix shell nixpkgs#sops nixpkgs#age ``` ## Adding or Updating Secrets The easiest way to add a new secret (like a password or API key) is to use the `sops --set` command from the root of the repository. ### Adding a Key-Value Pair ```bash sops --set '[""][""] ""' secrets.yaml ``` *Example (Adding a server password):* ```bash sops --set '["richmond-server"]["new-password"] "supersecret123"' secrets.yaml ``` *Example (Adding a global user password):* ```bash sops --set '["users"]["petere-password"] "mypassword"' secrets.yaml ``` ### Editing the Secrets File Directly To open the entire decrypted file in your editor: ```bash sops secrets.yaml ``` ## Using Secrets in Configuration ### 1. NixOS System Secrets In `hosts//configuration.nix`: ```nix sops.secrets."machine-name/new-secret" = { owner = "root"; group = "root"; mode = "0400"; }; ``` **Note:** For user passwords, add `neededForUsers = true;` to ensure the secret is decrypted early enough for the account to be created. ### 2. Home Manager Secrets Home Manager secrets are defined in the user's profile (e.g., `home-manager/users/petere.nix`): ```nix sops.secrets."gemini-api-key" = { }; ``` Access the decrypted path in your configuration: `config.sops.secrets."gemini-api-key".path` ### 3. Rendered Templates (`sops.templates`) For config files that embed a secret (e.g. an env file consumed by a container), use `sops.templates` so sops-nix renders the file with correct permissions and re-renders it at boot/switch — no shell `preStart` needed: ```nix sops.templates."pihole-env" = { content = '' FTLCONF_webserver_api_password=${config.sops.placeholder."richmond-server/pihole-password"} ''; path = "/run/pihole-env"; mode = "0600"; }; ``` The `${config.sops.placeholder.""}` reference is substituted with the decrypted value at runtime. Live examples: `hosts/richmond-server/configuration.nix` (pihole + castopod env files). ### Multi-line Secrets Store SSH keys and other multi-line values as YAML **block scalars** (using `|`) so they decrypt with real newlines. `hosts/homeserver-1/configuration.nix` installs the `restic-ssh-key` verbatim with `install`, so that secret must be multi-line (not a single line with escaped spaces). ## Rotating / Adding New Machine Keys When deploying to a new machine, you must generate an age key and add its public key to `.sops.yaml`. 1. **Generate the key on the target machine**: ```bash mkdir -p ~/.config/sops/age age-keygen -o ~/.config/sops/age/keys.txt ``` 2. **Get the public key**: ```bash cat ~/.config/sops/age/keys.txt | age-keygen -y ``` 3. **Update `.sops.yaml`**: Add the new public key to the `age` list. 4. **Re-encrypt the secrets file**: ```bash sops updatekeys secrets.yaml ``` ## Troubleshooting - **"No sops config found"**: Ensure you are in the repository root. - **Decryption Failure**: Ensure your private key is at `~/.config/sops/age/keys.txt` or set `export SOPS_AGE_KEY_FILE=...`. - **Pure Evaluation Mode**: Nix Flakes in pure mode cannot read absolute paths (like `/run/secrets/...`). Use `sops.templates` or runtime injection instead of `preStart` (see `hosts/richmond-server/configuration.nix`).