Boot.initrd.luks.devices specific order

Hello there,

I’m trying to setup my server with NixOS. My root partition and all other disks are encrypted with a key file. The key file itself gets unlocked by me via passphrase at boot (via keyboard or ssh unlock). So far, so good.
The problem I’m encountering now is the encryption order of the devices. The first partition to be decrypted has to be the key partition, followed by the other partitions.
But boot.initrd.luks.devices.<...> decrypts the devices in alphabetical order. That means that my bck0 device will be decrypted first, followed by key and nixos (root). bck0 will fail because it will not find the key file for decryption and the boot process ends in kernel panic. Is there any possibility to determine the order in which all devices will be decrypted? I got a very silly workaround at the moment by just changing the names of the devices, so that key will always be the first device to be decrypted.

Important parts of my nix-config:

...
boot.initrd.luks.devices."key" = {
  device = "/dev/disk/by-uuid/b6c3f5e1-...";
};

boot.initrd.luks.devices."nixos" = {
  device = "/dev/disk/by-uuid/94181b7a-...";
  keyFileSize = 4096;
  keyFile = "/dev/mapper/key";
};

boot.initrd.luks.devices."zbck0" = {
  device = "/dev/disk/by-uuid/25f70ac2-..."    
  keyFileSize = 4096;
  keyFile = "/dev/mapper/key";
};
...

Thanks in advance!

There’s a reasonable chance this will Just Work™ with systemd initrd. Now, this is still considered an experimental feature, but so far it’s been fairly reliable for those of us using it.

boot.initrd.systemd.enable = true;

systemd’s builtin tools for handling encrypted devices and key files and whatnot along with their ordering is substantially more sophisticated, and I believe it will create the necessary dependencies to ensure a LUKS device’s key file is available, either by requiring the mount units to reach the file or by requiring the device unit for it if it’s just a device (like your case)

1 Like

Thanks for reply!

Do I need only this option or do I have to reconfigure everything with the whole initrd.systemd.<...> module?

Should just be that one option. The boot.initrd.luks options as you have them are compatible.

If you use any options like boot.initrd.postDeviceCommands or similar to run commands during initrd, those won’t run in systemd initrd, you would need to set up equivalent oneshot systemd services using boot.initrd.systemd.services.

Okay, I tried it and it worked. Had to find a workaround for closing the key partition after fully restarting with a cron job, but that’s no big deal. I’ll have a look at systemd oneshots.

The problem I have now is that my ssh unlock does not work anymore. Without initrd.systemd.enable my config file for ssh unlock looked like this:

boot = {
    initrd = {
      network = {
        enable = true;
        ssh = {
          enable = true;
          port = 22;
          shell = "/bin/cryptsetup-askpass";
          authorizedKeys = [ "ssh-ed25519 AAAA..." ];
          hostKeys = [ "/root/.ssh/..." ];
        };
      };
      availableKernelModules = [ "r8169" ];
    };
    kernelParams = [ "ip=dhcp" ];
  };

With initrd.systemd.enable activated I had to comment out the shell option to let it reconfigure. After rebooting I got into stage 1 shell.
Is there any way to get it back working again with initrd.systemd.enable activated?

When you SSH into the machine with systemd stage 1, you can use systemd-tty-ask-password-agent to respond to the password prompt. Personally I just run ssh -t root@host systemctl default, which waits for the initrd to reach its main target and prompts for any passphrase prompts it encounters along the way (with proper echo behavior due to -t). We don’t support the boot.initrd.network.ssh.shell option for this, but that’s probably something we could fix.

1 Like

Got it, everything works now, thanks a lot! :blush:
It would be nice if the shell option will be patched in the future, because it makes to ssh client side much easier and convenient.

Final parts in my config:

boot.initrd.systemd.enable = true;

boot.initrd.luks.devices."key" = {
  device = "/dev/disk/by-uuid/b6c3f5e1-...";
};

boot.initrd.luks.devices."nixos" = {
  device = "/dev/disk/by-uuid/94181b7a-...";
  keyFileSize = 4096;
  keyFile = "/dev/mapper/key";
};

boot.initrd.luks.devices."zbck0" = {
  device = "/dev/disk/by-uuid/25f70ac2-..."    
  keyFileSize = 4096;
  keyFile = "/dev/mapper/key";
};

...

boot = {
  initrd = {
    network = {
      enable = true;
      ssh = {
        enable = true;
        port = 22;
        authorizedKeys = [ "ssh-ed25519 AAAA..." ];
        hostKeys = [ "/root/.ssh/..." ];
      };
    };
    availableKernelModules = [ "r8169" ];
  };
  kernelParams = [ "ip=dhcp" ];
};