Decrypting other drives after the root device has been decrypted using a keyfile

  # Setup keyfile
  boot.initrd.secrets = {
    "/crypto_keyfile.bin" = null;
  };
  boot.initrd.luks.devices = {
     r3t6crypt = {
      device = "/dev/disk/by-uuid/ae7aefce-2ddd-44eb-aa4c-16a915ac6753";
      keyFile = "/mnt-root/root/crypto_keyfile.bin";
    };
  };

My root hard disk is already getting decrypted by the autogenerated hardware-configuration.nix file, but for some reason I cannot for the life of me get subsequent hard disks decrypted. I’ve been tryingt his for hours to no avail, any clues?

3 Likes

So the problem is that NixOS’s initrd is scripted in distinct phases. It does all LUKS devices, and then it mounts file systems. So you can’t have a LUKS device whose key file is on any such file system. There’s a couple of ways to fix this today.

  1. Firstly (and I recommend this one if it works for you), is just not decrypting the disk in initrd. If the file system being decrypted isn’t needed in initrd (i.e. if it isn’t one of these ones), then you can just use the regular ole stage 2 /etc/crypttab instead of the NixOS initrd options.

    environment.etc."crypttab".text = ''
      r3t6crypt /dev/disk/by-uuid/ae7aefce-2ddd-44eb-aa4c-16a915ac6753 /root/crypto_keyfile.bin
    '';
    

    This doesn’t do decryption in initrd; it does it in stage 2 when the real OS is booting up. This is generally preferable if the FS isn’t needed in initrd because systemd does quite a lot to make the boot process more robust and user friendly, so allowing it to manage the decryption and mounting of file systems, especially with the context of the real OS, is generally better.

  2. But secondly, if the file system is needed in initrd (e.g. if the /nix/store is on a separate encrypted disk from the root fs), you can try the experimental option boot.initrd.systemd.enable = true;. This enables the new systemd-based initrd. It brings many of the benefits I described about doing it in stage 2 above into the initrd (though it’s still better to do it in stage 2 if you can). And it implements most of the same initrd options like the boot.initrd.luks options you’re using in terms of systemd stuff; LUKS devices are actually just translated into an /etc/crypttab file for initrd to use. The only difference for your config is that with systemd-based initrd, your root fs is mounted at /sysroot instead of /mnt-root in initrd.

    This feature is currently considered experimental. But several of us have been using it on our daily drivers for months now and this is exactly the kind of problem it was intended to fix.

5 Likes

Thank you very very very much. This helped me quite a lot.

For others encountering a similar issue when configurating multi-disk encryption with a single master boot key which is contained within your root hard disk, here is my configuration

  # Setup keyfile
  boot.initrd.secrets = {
    "/crypto_keyfile.bin" = null;
  };
    environment.etc."crypttab".text = ''
    ssd476g9crypt /dev/disk/by-uuid/8983aee6-0cec-46b7-b5c6-5ffefa5a0e41 /crypto_keyfile.bin
    '';
    fileSystems."/home" =
    { device = "/dev/disk/by-uuid/4e4adce6-cf79-4f2c-bf74-7099d808c1ea";
        fsType = "btrfs";
        options = [ "subvol=@home" ];
    };

Important to note here is that this will NOT work unless environment.“etc”.text.cryptab comes after boot.initrd.secrets.

Thank you again. :slight_smile:

2 Likes

wut. Nix doesn’t care about the order of defitions. { a = 1; b = 2; } is literally the exact same thing as { b = 2; a = 1; }

Can you please explain what this does? What happens if i don’t set any boot.initrd setting? Is there no keyfile then and nothing at risk or is there an unencrypted keyfile?

I’m asking because i wasn’t able to define a /boot/efi partition with the current/unstable calamares installer (it was complaining and didn’t boot when i created a 512MB FAT32 partition with the boot flag. Having it unmounted or mounting it as /boot/efi or /efi all didn’t work. The only thing that calamares accepted without complaints and that worked afterwards was an unencrypted /boot partition. Using /boot/efi in calamares was possible in 22.11).

This code says that the initrd should contain a file /crypto_keyfile.bin which is copied from the root partition’s /crypto_keyfile.bin file.

This is risky, and you shouldn’t do it unless you know what you’re doing or the calamares installer did it for you. And even then, the calamares installer did it wrong before 23.11.

This file will be stored in plaintext in the initrd. If you use an unencrypted /boot partition, this means this key file is in plaintext on disk. The only way to encrypt /boot is to use Grub, which the calamares installer will not do for UEFI systems. With systemd-boot, your initrd is going to be stored on an unencrypted partition, and you should not use boot.initrd.secrets except for files that you don’t mind leaking. For disk decryption with systemd-boot, this means you should have initrd ask for the password, since the boot loader can’t.

In reality, the difference between the two methods is negligible from a security perspective; encrypting the initrd serves no security purpose when the boot loader still has to be unencrypted, and there’s no difference between typing your password into Grub vs typing it in while initrd boots (except that the initrd is way way faster and more flexible at it).

1 Like

Ah, glad that i asked. Thank you for your explaination!