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>
150 lines
3.2 KiB
Markdown
150 lines
3.2 KiB
Markdown
# Secrets Management with agenix
|
|
|
|
Nomarchy uses [agenix](https://github.com/ryantm/agenix) for managing encrypted secrets. Secrets are encrypted with age using SSH public keys and decrypted at system activation.
|
|
|
|
## How It Works
|
|
|
|
1. **Secrets are encrypted** with your SSH public key(s)
|
|
2. **Stored in git** as `.age` files (safe to commit)
|
|
3. **Decrypted at boot** using the host's SSH private key
|
|
4. **Available at runtime** in `/run/agenix/`
|
|
|
|
## Quick Start
|
|
|
|
### 1. Get Your SSH Public Key
|
|
|
|
```bash
|
|
cat ~/.ssh/id_ed25519.pub
|
|
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... user@host
|
|
```
|
|
|
|
### 2. Get the Host's SSH Public Key
|
|
|
|
After first boot:
|
|
```bash
|
|
ssh-keyscan localhost 2>/dev/null | grep ed25519
|
|
```
|
|
|
|
Or from your hardware-configuration.nix's host:
|
|
```bash
|
|
ssh-keyscan <hostname> 2>/dev/null | grep ed25519
|
|
```
|
|
|
|
### 3. Edit secrets/secrets.nix
|
|
|
|
```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
|
|
|
|
```bash
|
|
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
|
|
|
|
```nix
|
|
# 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
|
|
|
|
```nix
|
|
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
|
|
|
|
```nix
|
|
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
|
|
|
|
```nix
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
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
|
|
```
|