dotfiles/secrets
2025-09-30 17:57:13 +07:00
..
.gitignore add sops nix for secret management 2025-09-30 17:57:13 +07:00
README.md add sops nix for secret management 2025-09-30 17:57:13 +07:00

Secrets with sops-nix

This repo wires sops-nix into the Home Manager profile so secrets are decrypted on-demand into ~/.config/secrets. The module is enabled by default and auto-generates an Age key if one does not already exist. Only the encrypted payloads under secrets/*.sops.yaml are meant to live in git; decrypted files never leave your machine.

One-time setup

  1. Ensure age and sops are available (e.g. nix develop or nix profile install nixpkgs#age nixpkgs#sops).
  2. Generate or import an Age key. Either let Home Manager create one automatically on first activation or run age-keygen -o ~/.config/sops/age/keys.txt yourself.
  3. Capture the public half with age-keygen -y -f ~/.config/sops/age/keys.txt and add it to the recipients list in each encrypted file (age1…). Commit the public key under version control or share it through your password manager so other hosts can decrypt.
  4. (Optional) Store the private key securely in macOS Keychain or 1Password (security add-generic-password …) so rebuilds work without manual prompts.

Managing secrets

  • Declare secrets in Home Manager under rsydn.secrets.secrets. Each entry is forwarded to sops.secrets.<name> and defaults to writing ~/.config/secrets/<name> with mode 0400.
  • Structure encrypted data however you like (YAML, JSON, .env). Only the encrypted file is tracked; plaintext never leaves sops.
  • Keep sensitive values scoped. Per-project secrets usually live in .env.sops + direnv; long-lived device secrets belong here.

Example snippet for modules/home/rsydn/secrets.nix consumers:

rsydn.secrets.secrets = {
  "openai-api-key" = {
    sopsFile = ./secrets.sops.yaml;
    path = "${config.xdg.configHome}/secrets/openai-api-key";
  };
};

Create or update secrets by running:

SOPS_AGE_KEY_FILE=$HOME/.config/sops/age/keys.txt \
  sops secrets/secrets.sops.yaml

When Home Manager activates, the secret is decrypted to the target path. Source it in Nushell with something like:

let-openai-key = (open $env.XDG_CONFIG_HOME ++ "/secrets/openai-api-key" | str trim)

Because the secret stays on disk, prefer reading it only when needed (inside commands/functions) instead of exporting it globally. For project workflows, you can also load it into env vars temporarily:

def with-openai-key [cmd] {
  let key = open $env.XDG_CONFIG_HOME ++ "/secrets/openai-api-key" | str trim
  with-env { OPENAI_API_KEY: $key } { nu -c $cmd }
}

To attach multiple secrets at once, use structured data (e.g. a YAML mapping) and parse it with Nushell's from yaml.

Rotating keys

If you regenerate your Age key, re-encrypt the file with the new recipient (sops updatekeys secrets/secrets.sops.yaml) and re-run darwin-rebuild --dry-run --flake .#macbook-pro to verify the deployment. Remember to remove old recipients so machines without access can no longer decrypt.

Frequently asked questions

  • Where do encrypted files live? In this repo under secrets/*.sops.yaml; they are safe to commit.
  • Where does plaintext live? At runtime under ~/.config/secrets/* (managed by Home Manager). Keep permissions tight and never add these paths to git.
  • How do I share secrets with another machine? Copy the Age public key from that machine into the recipients list, re-run sops updatekeys, commit, then pull and rebuild on the other host.
  • Can I keep using .env? Yes—encrypt it (e.g. secrets/project.env.sops) and load it with sops exec-env inside direnv so per-project shells receive the decrypted variables without storing them on disk.