Files
quincy/docs/SECRETS.md
Brandon Lucas 5a52b3c159 Add agenix secrets management
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>
2026-02-15 02:56:25 -05:00

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

  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

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