Key Management

This guide covers managing encryption and decryption keys for nixos-artifacts-agenix.

Key Types

nixos-artifacts-agenix supports multiple key types:

Key Type Format Use Case

SSH public key

ssh-ed25519 AAAA…​

Most common, works with SSH host keys and user keys

Age public key

age1…​

Pure age format, generated by age-keygen

YubiKey age key

age1yubikey1q0…​

Hardware security keys

Obtaining Keys

Host Keys (NixOS)

Retrieve the host’s public SSH key:

ssh-keyscan <hostname> | grep ssh-ed25519

Or from a known host:

ssh-keyscan localhost | grep ssh-ed25519

For age keys, convert SSH public keys:

nix run nixpkgs#ssh-to-age -- < /etc/ssh/ssh_host_ed25519_key.pub

User Keys

From your local SSH key:

cat ~/.ssh/id_ed25519.pub

Generate a new age key:

age-keygen -o ~/.config/age/key.txt
cat ~/.config/age/key.txt

YubiKey Keys

List connected YubiKeys:

age-plugin-yubikey --list

Generate a new identity on a YubiKey:

age-plugin-yubikey

Configuring Keys

NixOS Configuration

artifacts.config.agenix = {
  # Host's public key (required)
  publicHostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...";

  # Additional keys that can decrypt (optional)
  publicUserKeys = [
    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@laptop"
    "age1yubikey1q0..."
  ];
};

Home Manager Configuration

artifacts.config.agenix = {
  # Keys used to encrypt (required for Home Manager)
  publicUserKeys = [
    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@laptop"
  ];

  # Paths to private keys for decryption (required)
  identityPaths = [
    "${config.home.homeDirectory}/.ssh/id_ed25519"
    "${config.home.homeDirectory}/.config/age/key.txt"
  ];
};

Key Rotation

When you need to rotate encryption keys:

  1. Add the new key to configuration:

    publicUserKeys = [
      "ssh-ed25519 AAAA...new-key"
      "ssh-ed25519 AAAA...old-key"  # Keep old key during transition
    ];
  2. Re-encrypt all secrets using the TUI:

    Run the TUI and serialize your artifacts again. This encrypts secrets with ALL configured keys, including the new one.

  3. Verify decryption works (on the target machine):

    sudo agenix --decrypt /path/to/secret.age --identity /etc/ssh/ssh_host_ed25519_key
  4. Remove the old key from configuration:

    publicUserKeys = [
      "ssh-ed25519 AAAA...new-key"  # Old key removed
    ];
  5. Commit and deploy the updated configuration.

Re-encrypting After Key Changes

If keys change but secrets aren’t updated, re-serialize using the TUI to regenerate encrypted files with current keys.

Multiple Machines / Users

For secrets shared across multiple machines:

Separate Secret Files

Each machine stores its own copy:

secrets/per-machine/laptop/wifi/psk.age
secrets/per-machine/server/wifi/psk.age

Shared Secrets

Use the shared = true artifact option:

artifacts.store.wifi-password = {
  shared = true;  # Encrypted with ALL keys from all referencing machines
  files = { "psk" = { }; };
};

Configure all machines to include their public keys:

# On laptop
artifacts.config.agenix = {
  publicHostKey = "ssh-ed25519 AAAA...laptop...";
  publicUserKeys = [ "ssh-ed25519 AAAA...user..." ];
};

# On server
artifacts.config.agenix = {
  publicHostKey = "ssh-ed25519 AAAA...server...";
  publicUserKeys = [ "ssh-ed25519 AAAA...user..." ];
};

Troubleshooting

"age: error: no identity matched any of the file’s recipients"

The secret was encrypted with keys you don’t have. Solutions:

  1. Verify your key is in publicUserKeys (for Home Manager) or publicHostKey (for NixOS)

  2. Re-serialize the secrets using the TUI with your current key configuration

Decryption Fails at Runtime

Check that the decryption identity exists:

  • NixOS: Host SSH key at /etc/ssh/ssh_host_ed25519_key

  • Home Manager: Path configured in identityPaths

Verify the identity can decrypt:

# For SSH keys
agenix --decrypt secrets/per-machine/myhost/mysecret/file.age \
  --identity /etc/ssh/ssh_host_ed25519_key

# For age keys
age --decrypt -i ~/.config/age/key.txt secrets/per-user/myuser/mysecret/file.age

Permission Denied on SSH Keys

Ensure the agenix service can read the identity:

# For Home Manager
artifacts.config.agenix.identityPaths = [
  "${config.home.homeDirectory}/.ssh/id_ed25519"
];

# Ensure correct permissions
chmod 600 ~/.ssh/id_ed25519

Security Considerations

  1. Never commit private keys to version control

  2. Use hardware keys (YubiKey) for sensitive secrets

  3. Rotate keys periodically or after compromised access

  4. Limit publicUserKeys to only those who need decryption access