Files
Nix-Vibe/docs/sops-secrets.md

3.7 KiB

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:

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

sops --set '["<host-or-category>"]["<secret-name>"] "<value>"' secrets.yaml

Example (Adding a server password):

sops --set '["richmond-server"]["new-password"] "supersecret123"' secrets.yaml

Example (Adding a global user password):

sops --set '["users"]["petere-password"] "mypassword"' secrets.yaml

Editing the Secrets File Directly

To open the entire decrypted file in your editor:

sops secrets.yaml

Using Secrets in Configuration

1. NixOS System Secrets

In hosts/<hostname>/configuration.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):

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:

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."<secret>"} 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:

    mkdir -p ~/.config/sops/age
    age-keygen -o ~/.config/sops/age/keys.txt
    
  2. Get the public key:

    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:

    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).