refactor(ssh): extract the host key wiring into a module

The sops secret declarations, the empty `hostKeys`, and the `HostKey`
lines were boilerplate sitting in the host, and every future host
restoring its identity would have repeated them.

`modules.ssh` takes the encrypted file and the key types, deriving the
secret names and the `HostKey` lines from one list, so the daemon and the
secrets cannot disagree about where a key lives. The resulting system
derivation is unchanged.

Also record two gotchas: reading PR review comments needs the Gitea API
rather than tea, and host keys are not user authentication keys.
This commit is contained in:
2026-07-20 07:40:47 -04:00
parent 60738f65c2
commit 42ff195556
3 changed files with 75 additions and 32 deletions

View File

@@ -1,19 +1,6 @@
{
config,
inputs,
pkgs,
...
}:
{ inputs, pkgs, ... }:
# neogaia — Dell XPS 13 9380 laptop.
# Disk layout is in ./disk.nix; `fileSystems` are derived from it, none declared here.
let
# Read by the daemon at startup, so a re-key has to restart it to take effect.
sshHostKey = {
sopsFile = ../../secrets/neogaia.yaml;
mode = "0400";
restartUnits = [ "sshd.service" ];
};
in
{
imports = [
inputs.nixos-hardware.nixosModules.dell-xps-13-9380
@@ -40,24 +27,10 @@ in
networking.networkmanager.enable = true;
# So setup can be driven over the network.
services.openssh.enable = true;
# This host's SSH identity is restored from secrets.
# Reimaging the machine therefore keeps its fingerprint, and every client's
# `known_hosts` entry stays valid.
# The matching public halves are committed in plaintext, since publishing
# them is their purpose.
sops.secrets = {
ssh-host-ed25519-key = sshHostKey;
ssh-host-rsa-key = sshHostKey;
};
# An empty list is what stops the daemon generating keys of its own.
services.openssh.hostKeys = [ ];
services.openssh.extraConfig = ''
HostKey ${config.sops.secrets.ssh-host-ed25519-key.path}
HostKey ${config.sops.secrets.ssh-host-rsa-key.path}
'';
# The matching host public keys sit beside this file in plaintext, since
# publishing them is their purpose.
modules.ssh.enable = true;
modules.ssh.hostKeys.sopsFile = ../../secrets/neogaia.yaml;
# fish as the login shell.
modules.fish.enable = true;