SOPS Secret Management¶
This configuration uses SOPS (Secrets OPerationS) with Age encryption for managing secrets securely.
Overview¶
SOPS is used for:
- User password hashes
- Other sensitive configuration data
Files¶
secrets/users.yaml- Encrypted user data (passwords, etc.).sops.yaml- SOPS configuration with age recipients
Architecture¶
System-Level Secrets¶
- Managed via NixOS SOPS module
- SSH host keys used for age encryption/decryption
- Secrets available at
/run/secrets/during boot
User-Space Environment Variables¶
For secrets that need to be available in shell sessions (SSH, console):
- SOPS Template: Create template in NixOS module
- Systemd User Service: Copy template to user-accessible location
- Home Manager Integration: Source environment variables in shell configurations
Example pattern:
# NixOS module
sops.templates."app-env-user" = {
content = ''
APP_SECRET=${config.sops.placeholder."app/secret"}
'';
owner = "user";
group = "users";
mode = "0400";
};
systemd.user.services.app-env = {
description = "Copy app environment to user space";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "app-env-setup" ''
mkdir -p "$HOME/.config/environment.d"
cp "${config.sops.templates."app-env-user".path}" "$HOME/.config/environment.d/50-app.conf"
chmod 600 "$HOME/.config/environment.d/50-app.conf"
'';
};
};
# Home Manager module
home.file.".local/bin/load-app-env" = {
text = ''
#!/bin/sh
if [ -f "$HOME/.config/environment.d/50-app.conf" ]; then
set -a
source "$HOME/.config/environment.d/50-app.conf"
set +a
fi
'';
executable = true;
};
# Shell integration
programs.bash.bashrcExtra = ''
if [ -x "$HOME/.local/bin/load-app-env" ]; then
source "$HOME/.local/bin/load-app-env"
fi
'';
Usage¶
To edit secrets:
To view decrypted secrets:
YubiKey-backed Age Identity (End-to-End)¶
This repository supports adding a YubiKey-backed recipient in addition to existing recipients.
Current behavior:
- Existing host and admin recipients continue to work
- New YubiKey recipient is added for operator decryption/editing
- Files remain decryptable during migration
1. Install tools on each workstation¶
Required tools:
sopsageage-plugin-yubikey
This repo now includes these packages in:
- macOS/Home Manager development package sets
- WSL host package set (
darth-vader) - development shell (
nix develop)
Home Manager now also manages:
~/.config/sops/age/sops-yubikey-inithelper command
Home Manager does not manage ~/.config/sops/age/yubikey.txt contents,
which prevents clobbering your generated identity on rebuilds.
2. Initialize a fresh YubiKey identity¶
Plug in the YubiKey and run:
By default this uses slot 1. It first tries to load identity metadata from
that slot and only generates a new identity in the same slot if none exists.
To regenerate and overwrite:
If you accidentally generated multiple slots previously, keep using the slot
that matches .sops.yaml recipient (or update .sops.yaml to the new
recipient).
List recipients and copy the age... recipient value:
3. Add YubiKey recipient to repository policy¶
In .sops.yaml:
- Add a new key anchor under
keys:(for example&admin_karl_yubikey) - Add that key to each relevant
creation_rules[*].key_groups[*].agelist - Keep existing recipients during migration
Example pattern:
keys:
- &admin_karl age1...
- &admin_karl_yubikey age1...
- &r2d2_host age1...
creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *admin_karl
- *admin_karl_yubikey
- *r2d2_host
4. Rewrap existing encrypted files with updated recipients¶
Run updatekeys for existing secrets so metadata includes the new recipient:
For non-interactive usage:
5. Verify decryption with YubiKey¶
Expected behavior:
- Touch prompt appears on YubiKey (with
touch-policy always) - PIN prompt appears according to PIN policy (
oncecaches during session)
6. Multi-workstation usage model¶
You can use the same YubiKey on macOS and WSL, but each workstation still needs:
- installed tooling (
sops,age,age-plugin-yubikey) - a local YubiKey identity file (for example
~/.config/sops/age/yubikey.txt)
The identity file is metadata (not the private key). The private key material stays on the YubiKey.
7. Migration and hardening¶
Recommended rollout:
- Add YubiKey recipient alongside existing keys
- Validate decryption/edit workflow from each workstation
- Remove old software admin recipient later (optional hardening)
- Run
sops updatekeysagain after recipient removal
Troubleshooting¶
- If decryption fails, confirm
age-plugin-yubikeyis inPATH - On Linux/WSL environments, ensure smartcard/PCSC plumbing is available
- If you switch YubiKey applets frequently (SSH/FIDO/PIV), PIN cache may reset
- Use
age-plugin-yubikey --listto confirm the expected recipient is visible