fix(preservation): mount /etc/ssh in initrd so key changes apply on boot

NixOS copies mode-carrying /etc entries such as authorized_keys.d during
stage-2 activation, which runs before systemd starts. preservation mounted the
persisted /etc/ssh from preservation.target afterwards and hid that copy, so a
key change only took effect on `switch`: revoking a key and rebooting silently
restored the old one.

Prepare the mount in initrd, before activation runs, and cover it with a VM
test that seeds a stale authorized_keys file, reboots, and asserts the declared
key replaced it. The same test fails on that assertion with inInitrd disabled.

Verified on all four hosts: /persistent/etc/ssh/authorized_keys.d/root is now
rewritten at boot instead of keeping the timestamp of the last switch.

Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
Ryan Yin committed 2026-10-31 01:09:16 +08:00
1 parent 7dc4e7a39f
commit 560a6cc2d8
4 files changed
+95 -2

No files matched your search

+10 -1
View File
@@ -24,8 +24,17 @@ in
# If the directory/file already exists in the root filesystem you should
# move those files/directories to /persistent first!
preservation.preserveAt."/persistent" = {
# Mount in initrd: NixOS copies mode-carrying /etc entries (such as
# authorized_keys.d) during stage-2 activation, which runs before systemd
# starts. A mount created by preservation.target comes later and would hide
# those copies behind the previous `switch`, so key changes only applied on
# `switch`, never on `boot` + reboot. Preparing the mount in initrd puts
# /persistent/etc/ssh at /sysroot/etc/ssh before activation runs.
directories = [
"/etc/ssh"
{
directory = "/etc/ssh";
inInitrd = true;
}
"/etc/nix/inputs"
"/etc/secureboot" # lanzaboote - secure boot (see ./secureboot.nix)