NixOS module for TPM-backed SSH host keys using ssh-tpm-agent.
Private keys are sealed in the TPM and cannot be extracted - signing happens inside the hardware.
# flake.nix
{
inputs.ssh-tpm-hostkeys.url = "github:visualphoenix/ssh-tpm-hostkeys";
}# configuration.nix
{ inputs, ... }:
{
imports = [ inputs.ssh-tpm-hostkeys.nixosModules.default ];
services.ssh-tpm-hostkeys.enable = true;
services.openssh.enable = true;
}That's it. On first boot, existing non-TPM host keys are removed and TPM-sealed keys are generated.
| Feature | Details |
|---|---|
| TPM2 enabled | security.tpm2.enable = true set automatically |
| Key generation | ssh-tpm-genkeys.service runs before sshd |
| Agent | ssh-tpm-agent.service with socket activation |
| sshd configured | HostKeyAgent and HostKey set automatically |
| Default key type | ECDSA (better performance than RSA) |
For ephemeral root systems using preservation:
services.ssh-tpm-hostkeys = {
enable = true;
persist.backend = "preservation";
# persist.preservationPath = "/persist"; # default, change if needed
};Keys are written to ${preservationPath}/etc/ssh/ and symlinked via preservation.
| Option | Default | Description |
|---|---|---|
services.ssh-tpm-hostkeys.enable |
false |
Enable TPM-backed host keys (replaces regular keys) |
services.ssh-tpm-hostkeys.keyTypes |
["ecdsa"] |
Key types to generate: "ecdsa", "rsa", or both |
services.ssh-tpm-hostkeys.persist.backend |
"none" |
"none" or "preservation" |
services.ssh-tpm-hostkeys.persist.preservationPath |
"/persist" |
Where preservation stores persistent data |
| File | Description |
|---|---|
/etc/ssh/ssh_tpm_host_ecdsa_key.tpm |
TPM-sealed private key (not extractable) |
/etc/ssh/ssh_tpm_host_ecdsa_key.pub |
Public key |
- Hardware-bound:
.tpmfiles are sealed to the specific TPM. Different hardware = regenerate keys. - Client warnings: After key regeneration, clients see host key warnings. Update
known_hosts. - First boot: Existing non-TPM host keys in
/etc/ssh/are removed.
Keys not generating
ls -la /dev/tpm* # TPM device exists?
systemctl status ssh-tpm-genkeys # Service status
journalctl -u ssh-tpm-genkeys # Logssshd fails to start
systemctl status ssh-tpm-agent.socket
sshd -t # Config validationTest the agent
SSH_AUTH_SOCK=/run/ssh-tpm-agent.sock ssh-add -l- ssh-tpm-agent - The underlying tool
- TPM 2.0 on NixOS - NixOS TPM setup