Skip to content

Secrets (sops-nix)

All network secrets (passwords, keys, tokens) live encrypted in a single file, managed by sops-nix 🡕. It is versioned in git in encrypted form; only key holders can decrypt it.

# usr/secrets/secrets.yaml (encrypted at rest)
default-password: ...
default-password-hash: ...
user:
alice:
password-hash: ...

Decryption relies on two age 🡕 keys:

KeyWhereRole
Admin key~/.config/sops/age/keys.txtEdit secrets from the admin workstation
Infra key/etc/sops/age/infra.keyDecrypt on each host at deploy time
  • The admin key derives from your SSH key (~/.ssh/id_ed25519, via ssh-to-age).
  • The infra key is generated once, then pushed to each host.
  • Recipients are listed in usr/secrets/.sops.yaml (admin + infra).

A single command prepares all the secrets infrastructure:

Fenêtre de terminal
just configure-admin-host

It is idempotent and creates, if needed:

  • the deployer SSH key (nix);
  • the admin key (from the SSH key) and the infra key (age-keygen);
  • the .sops.yaml file (recipients);
  • a default password (just passwd-default);
  • the Harmonia binary cache signing key.
CommandEffect
just passwd-default(Re)sets the default password for accounts
just passwd <user>Sets a user’s password
just passwd-resticGenerates backup secrets (per host / zone)
just sopsEdits the secrets file manually ($EDITOR)

After a change, deploy to propagate it:

Fenêtre de terminal
just passwd alice
just apply @user-alice # deploys the new hash

A host can only decrypt secrets with the infra key. It is placed automatically by just configure <host>, or manually:

Fenêtre de terminal
just push-key <host> # copies /etc/sops/age/infra.key to the host

Rotation replaces the infra key across the entire fleet, in three verified steps:

  1. Introduce the new key

    Fenêtre de terminal
    just rotate init # new key + re-encryption (old + new)
  2. Distribute to all hosts

    Fenêtre de terminal
    just rotate push-keys # each host receives both keys
    just apply '*'
  3. Finalize

    Fenêtre de terminal
    just rotate finalize # discards the old key (after verification)
    just apply '*'