Phase 3: Encrypted secrets - Add secrets module with agenix integration - Create secrets/secrets.nix template for key definitions - Installer generates SSH key if missing - Installer creates personalized secrets.nix with user's key - Full documentation in docs/SECRETS.md Features: - Secrets encrypted with age using SSH keys - Decrypted automatically at system activation - Safe to commit .age files to git - Support for WiFi passwords, API keys, service credentials Usage: agenix -e secrets/my-secret.age age.secrets.my-secret.file = ./secrets/my-secret.age; Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
3.2 KiB
3.2 KiB
Secrets Management with agenix
Nomarchy uses agenix for managing encrypted secrets. Secrets are encrypted with age using SSH public keys and decrypted at system activation.
How It Works
- Secrets are encrypted with your SSH public key(s)
- Stored in git as
.agefiles (safe to commit) - Decrypted at boot using the host's SSH private key
- Available at runtime in
/run/agenix/
Quick Start
1. Get Your SSH Public Key
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... user@host
2. Get the Host's SSH Public Key
After first boot:
ssh-keyscan localhost 2>/dev/null | grep ed25519
Or from your hardware-configuration.nix's host:
ssh-keyscan <hostname> 2>/dev/null | grep ed25519
3. Edit secrets/secrets.nix
let
user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...";
host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...";
allKeys = [ user host ];
in {
"wifi-home.age".publicKeys = allKeys;
"github-token.age".publicKeys = allKeys;
}
4. Create a Secret
cd ~/.config/nomarchy
agenix -e secrets/wifi-home.age
This opens your editor. Enter the secret content, save, and exit.
5. Use the Secret in Your Config
# In your custom module
{ config, ... }: {
age.secrets.wifi-home = {
file = ./secrets/wifi-home.age;
owner = "root";
mode = "0400";
};
# Use the decrypted secret
networking.wireless.networks."MyNetwork".pskRaw =
"file:${config.age.secrets.wifi-home.path}";
}
Common Use Cases
WiFi Passwords
age.secrets.wifi-password.file = ./secrets/wifi.age;
# For NetworkManager (wpa_supplicant)
networking.wireless.networks."NetworkName".psk =
builtins.readFile config.age.secrets.wifi-password.path;
API Keys
age.secrets.github-token = {
file = ./secrets/github-token.age;
owner = "youruser";
mode = "0400";
};
# In your shell config
home.sessionVariables.GITHUB_TOKEN =
"$(cat ${config.age.secrets.github-token.path})";
Service Credentials
age.secrets.syncthing-key = {
file = ./secrets/syncthing-key.age;
owner = "youruser";
};
services.syncthing.key = config.age.secrets.syncthing-key.path;
Re-keying Secrets
If you change hosts or keys, re-encrypt all secrets:
cd ~/.config/nomarchy
agenix --rekey
Security Notes
- Never commit unencrypted secrets
- Keep your SSH private key secure
- The host's SSH key is generated during install
- Secrets are decrypted to a tmpfs (
/run/agenix/) - Consider using separate keys for different security levels
Troubleshooting
"No identity found"
Ensure /etc/ssh/ssh_host_ed25519_key exists and is readable by root.
"Failed to decrypt"
Check that the host's public key is in secrets.nix and re-encrypt:
agenix --rekey
"Secret file not found"
Make sure the .age file exists and the path in your config is correct.
File Structure
~/.config/nomarchy/
├── secrets/
│ ├── secrets.nix # Key definitions
│ ├── wifi.age # Encrypted WiFi password
│ └── github.age # Encrypted API key
└── flake.nix