return 12; // good enough for now

Decrypt NixOS via SSH at boot

2023-07-22

In my NixOS setup I have my root and swap partitions fully encrypted. This is the default setup when you set the “encrypt system” checkbox on the graphical installer.

During boot I’m asked for the decryption password. This isn’t idea as the box runs headlessly under my desk and may also require rebooting when I’m not in the same physical location. Therefore, I need a way to remotely supply the password. This can be done by configuring NixOS to allow SSH access before the machine fully boots.

Create key pair

It’s best to create a new key pair specifically for this pre-boot SSH setup.

$ ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key

Determine the network card driver you need

To ensure the right drivers are installed in the minimal boot state, it needs to be specified in the available kernal modules (see below). The driver required can be found with lspci.

$ nix-shell -p pciutils
$ lspci -v

# Therell be some output similar to this
26:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 04)
	...
	Kernel driver in use: r8169  # In this case, 'r8169' is the value I want
	Kernel modules: r8169

Configure minimal network setup for initrd

# configuration.nix

boot.initrd = {
  network = {
    enable = true;
    ssh = {
      enable = true;
      port = 2222;  # Use a separate port to prevent conflict in your known
                    # hosts
      hostKeys = [ "/etc/ssh/initrd_ssh_host_ed25519_key" ];
      authorizedKeys = config.users.users.<root|user>.openssh.authorizedKeys.keys;
    };
  };
  availableKernelModules = [ "r8169" ];
};
networking.useDHCP = false;
networking.interfaces.enp6s0.useDHCP = true;  # network interface found in
                                              # hardward-configuration.nix

Now, when rebooting, we can see the sshd daemon starting before the prompt for the luks password appears. Connect to be able to access the boot partition.

$ ssh root@<host-ip> -p 2222

Once logged in the partition can be decrypted.

I’ve seen examples where cryptroot-unlock or cryptsetup open were used to unlock the partition, but none of these worked for me. Tabbing around I found the cryptsetup-askpass command.

$ cryptsetup-askpass
Passphrase for /dev/disk/by-uuid/b0b4a2bf-12e4-4e62-985a-f48f722c3789:

That’s it. Once entered, the port 2222 sshd is stopped and the boot continues as normal.

Automatic password prompt

For a slightly less interactive version, set an alias as suggested by Daniel Wayne Armstrong.

# ~/.ssh/config

Host unlock-<host>
    Hostname <host-ip>
    User root
    Port 2222
    RequestTTY yes
    RemoteCommand cryptsetup-askpass

Now just ssh in and you’ll be asked for the password. Once boot is complete your session will be closed.

$ ssh unlock-host
Passphrase for /dev/disk/by-uuid/b0b4a2bf-12e4-4e62-985a-f48f722c3789: 
Waiting 10 seconds for LUKS to request a passphrase.......Connection to 192.168.88.97 closed by remote host.
Connection to 192.168.88.97 closed.

Elsewhere