Migrating LUKS with remote SSH unlock to 26.05

I have a LUKS setup with remote SSH unlock based on Early boot remote encryption on NixOS:

  boot.initrd = {
    availableKernelModules = [ "e1000e" ];
    kernelModules = [ "e1000e" ];
    preLVMCommands = lib.mkBefore "sleep 1";
    luks.forceLuksSupportInInitrd = true;
    network.postCommands =
      let
        device = "/dev/disk/by-uuid/817fa831-78c7-42c3-abe6-5d8ecc2a77a9";
      in
      ''
        echo 'cryptsetup open ${device} root --type luks && echo > /tmp/continue && exit' >> /root/.profile
        echo 'starting sshd...'
      '';
    postDeviceCommands = ''
      echo 'waiting for root device to be opened...'
      mkfifo /tmp/continue
      cat /tmp/continue
    '';
    network = {
      enable = true;
      ssh = {
        enable = true;
        authorizedKeys = [ (builtins.readFile ../data/ssh/id_ed25519.pub) ];
        hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ];
        port = meta.sshPortBoot;
      };
    };
  };

Now I’m trying to migrate this to the new systemd-backed initrd. Information on this is a bit all over the place, here’s what I ended up with:

let
  # can re-use this for main network configuration
  lanConfig = {
    matchConfig.Name = "enp0s31f6";
    networkConfig.DHCP = "ipv4";
    address = [ "${meta.ipv6}/64" ];
    routes = [ { Gateway = meta.gateway; } ];
  };
in {
  boot.initrd = {
    availableKernelModules = [ "e1000e" ];
    kernelModules = [ "e1000e" ];
    systemd = {
      enable = true;
      network.networks."10-lan" = lanConfig;
      services.systemd-networkd.enable = true;
      services."systemd-cryptsetup@".after = [ "network-online.target" ];
    };
    network = {
      enable = true;
      ssh = {
        enable = true;
        authorizedKeys = [
          ''command="systemctl default" ${builtins.readFile ../data/ssh/id_ed25519.pub}''
        ];
        hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ];
        port = meta.sshPortBoot;
      };
    };
    luks.forceLuksSupportInInitrd = true;
    luks.devices."root".device = "/dev/disk/by-uuid/817fa831-78c7-42c3-abe6-5d8ecc2a77a9";
  };
}

The release notes tell me:

If you use LUKS disk encryption, ensure that fileSystems."/".device is set to "/dev/mapper/<name>", where <name> matches the name in your boot.initrd.luks.devices.<name> definition, to avoid systemd timing out while prompting for a passphrase. If you have a more complex setup, e.g. with LVM on top of LUKS, you may need to add "x-systemd.device-timeout=infinity" to fileSystems."/".options instead.

My setup is like this:

$ lsblk --fs
NAME          FSTYPE      FSVER    LABEL UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1        zfs_member  5000     hdds  4633749780791321671
└─sda9
sdb
├─sdb1        zfs_member  5000     hdds  4633749780791321671
└─sdb9
sdc
├─sdc1        zfs_member  5000     hdds  4633749780791321671
└─sdc9
sdd
├─sdd1        zfs_member  5000     hdds  4633749780791321671
└─sdd9
sde
├─sde1        zfs_member  5000     hdds  4633749780791321671
└─sde9
sdf
├─sdf1        zfs_member  5000     hdds  4633749780791321671
└─sdf9
nvme0n1
├─nvme0n1p1   vfat        FAT32          2C54-3216                               427.9M    14% /boot/efi
└─nvme0n1p2   crypto_LUKS 2              817fa831-78c7-42c3-abe6-5d8ecc2a77a9
  └─root      LVM2_member LVM2 001       SrtwGP-CVgJ-eDeb-tiqX-ZnAp-FpL8-ZsMo3c
    ├─vg-swap swap        1        swap  dd6c5d39-0e36-4c37-82c5-1c5e963efa46                  [SWAP]
    └─vg-root ext4        1.0      root  d7dcef88-a29e-48d8-800b-3a04dc87a42c      327G    18% /nix/store
                                                                                               /

So apparently I have LVM on top of LUKS (yeah I can’t remember how I set that up). (The ZFS pool are my HDDs which probably isn’t relevant since the root partition isn’t on there.)

Do I understand it correctly that what I need to do now is to add these options for everything to work:

  fileSystems."/" = {
    device = "/dev/disk/by-uuid/acaff102-ba8d-4d2e-b4f3-6333e239dc19";
    fsType = "ext4";
    # added this line
    options = "x-systemd.device-timeout=infinity";
  };


  swapDevices = [
    {
      device = "/dev/disk/by-uuid/d26dddde-b250-486d-b46a-b64eb7b788ae";
      # and this one
      options = "x-systemd.device-timeout=infinity";
    }
  ];

I’m a bit anxious about not being able to decrypt the root partition anymore after updating, so I’m hoping to get confirmation that I understood the instructions correctly. Also I’m unsure about the updated SSH setup since I frankenstein’d it together with parts from different discussions. I hope that after confirmation, this can be a resource for other people with the same setup.

2 Likes

You shouldn’t have to manually configure the network since you’ve already got boot.initrd.network.enable = true;. But if you do want to configure it manually (which isn’t a bad idea IMO; the networkd configuration is a little more controlled, and you can match your stage 2 networkd configuration to it easily), you can:

  • Remove boot.initrd.network.enable and replace it with boot.initrd.systemd.network.enable = true;
  • Remove that services.systemd-networkd.enable = true; line, since that’s default

But again, it’s not necessary. Just boot.initrd.network.enable = true; like you had before should still be all you need for networking to work.

This line shouldn’t be necessary in either case. There’s no problem if systemd-cryptsetup@.service starts before networking is up. The password prompt will still work later.

I think you’ve got this right, yea. Well, except that options is a list, so those strings should be wrapped in list syntax. But yea, the purpose of those options is so that the system doesn’t timeout and go to emergency mode when you don’t enter your passphrase within 90sec.

Where do you think this information would have been most natural for you to come across it? And which information exactly do you think you should have been able to find there? It might make sense for us to add some more documentation about how to do this stuff, but it’s not clear which information should be where, so hearing from someone who was looking for it would be helpful.

3 Likes

Thanks for reviewing this!

I changed the options to a list and left everything else as it is for now, and that worked! Will try simplifying it as you suggested, but at a later time when I can reboot the server again for testing.

Where do you think this information would have been most natural for you to come across it? And which information exactly do you think you should have been able to find there?

I think the information flow generally was quite good. I did get an error on building the configuration for 26.05, which directed me to the release notes where I found the information about luks on initrd needing new configuration, which led me here in search for what exactly to do. Helpful topics were these:

I also found a topic suggesting the services."systemd-cryptsetup@".after bit but cannot find it anymore.

I did come along the page on the wiki which describes the outdated config:

It does carry a note linking back to the release notes, so there’s that.

A complete example was the only information I could not find. Everything else was there. So adding one to the wiki would be great, though it was the last place I looked at since I generally consider recent Discourse topic being more up-to-date.

2 Likes