Secrets (sops-nix)
All network secrets (passwords, keys, tokens) live encrypted in a single file managed by sops-nix 🡕. It is committed to git in encrypted form; only key holders can decrypt it.
# usr/secrets/secrets.yaml (chiffré au repos)default-password-hash: ...user: alice: password-hash: ...The two keys
Section titled “The two keys”Decryption relies on two age 🡕 keys:
| Key | Where | Role |
|---|---|---|
| Admin key | ~/.config/sops/age/keys.txt | Edit secrets from the admin workstation |
| Infra key | /etc/sops/age/infra.key | Decrypt on each host at deploy time |
- The admin key derives from your SSH key (
~/.ssh/id_ed25519, viassh-to-age). - The infra key is generated once, then pushed to each host.
- Recipients are listed in
usr/secrets/.sops.yaml(admin + infra).
Initialize (admin host)
Section titled “Initialize (admin host)”A single command prepares all the secrets machinery:
just configure-admin-hostIt is idempotent and creates, as needed:
- the deployer’s SSH key (
nix); - a random password, known to no one, for the
nixaccount: it is only accessed via its key; - the admin key (from the SSH key) and the infra key (
age-keygen); - the
.sops.yamlfile (recipients); - the fingerprint of the default password (
just passwd-default); - the Harmonia binary cache signing key;
- all internal secrets of the declared services (see below).
Internal secrets and external secrets
Section titled “Internal secrets and external secrets”The framework sorts each secret into one of two families. The reference list
lives in dnf/lib/secrets.nix ; each host of the farm is the authority on
what is claimed.
Internal — the value only makes sense to machines, no one remembers it.
just configure-admin-host draws them at random, once and for all :
| Family | Examples |
|---|---|
| Kanidm OAuth2 clients | oidc-secret-<client>, oauth2-proxy cookie |
| Backup | restic-password-<zone>, restic/<host>/rest-password |
| Matrix | MAS secrets, livekit-secret, bridge tokens, turn-secret |
| Identities | Kanidm fallback passwords, internal TLS pair |
| Services | AdGuard Home, Nextcloud, Grafana, SearXNG, Vaultwarden, Garage, MinIO… |
External — the value comes from elsewhere, DNF cannot invent it :
| Family | Origin |
|---|---|
| Account passwords | chosen by a human (just passwd) |
smtp/password (with network.smtp), wifi-password-<zone> | provider, box, operator |
mautrix-telegram-api-* | my.telegram.org |
luks-passphrase, yubikey/... | typed at boot, or derived from the physical key |
alertmanager-matrix-* | account created on the server (just configure-alert-bot) |
Manage passwords
Section titled “Manage passwords”| Command | Effect |
|---|---|
just passwd-default | Records the fleet default password (hash only) |
just passwd <user> | Sets a user’s password |
just configure-admin-host | Generates missing internal secrets (OIDC, backup, service tokens…) |
just yubikey <user> | Enrolls a YubiKey (derived LUKS secret + luks-passphrase) |
just luks <host> | Provisions disk encryption (shared + per-host passphrases) |
just sops | Edits the secrets file by hand ($EDITOR) |
After a change, deploy to propagate it:
just passwd alicejust apply @user-alice # deploys the new hashPush the key to a host
Section titled “Push the key to a host”A host can only decrypt secrets with the infra key. It is placed automatically
by just configure <host>, or manually:
just push-key <host> # copies /etc/sops/age/infra.key to the hostRotating the infra key
Section titled “Rotating the infra key”Rotation replaces the infra key across the entire fleet, in three verified steps:
-
Introduce the new key
Fenêtre de terminal just rotate init # new key + re-encryption (old + new) -
Distribute to all hosts
Fenêtre de terminal just rotate push-keys # each host receives both keysjust apply '*' -
Finalize
Fenêtre de terminal just rotate finalize # discards the old key (after verification)just apply '*'
Hashed Vaultwarden token (Argon2)?
Section titled “Hashed Vaultwarden token (Argon2)?”just invite connects on its own to the /admin panel with the plaintext
vaultwarden-admin-token value. A manually set Argon2 hash forces it to
ask for the token; just configure-admin-host reports it.
To migrate delete the entry with just sops, run
just configure-admin-host again, then just apply hcs. Vaultwarden restarts with
the new token. The panel remains protected by the network : it only responds
from the LAN and the tailnet.
New admin machine, existing project?
Section titled “New admin machine, existing project?”The project’s secrets are encrypted for the old admin machine’s keys.
just configure-admin-host therefore refuses to create new ones: first restore
/home/nix/.ssh/id_ed25519 and /etc/sops/age/infra.key (owned by nix, mode
600).
Prepare a machine without a nix account?
Section titled “Prepare a machine without a nix account?”just bootstrap-keys creates the keys and the sops skeleton under a given root,
for example /mnt from the installer, with the credentials NixOS will give the
nix account. See the Justfile.