diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix index 7837a34b4984..ab3ccddf682d 100644 --- a/nixos/modules/tasks/encrypted-devices.nix +++ b/nixos/modules/tasks/encrypted-devices.nix @@ -5,8 +5,22 @@ with lib; let fileSystems = config.system.build.fileSystems ++ config.swapDevices; encDevs = filter (dev: dev.encrypted.enable) fileSystems; - keyedEncDevs = filter (dev: dev.encrypted.keyFile != null) encDevs; - keylessEncDevs = filter (dev: dev.encrypted.keyFile == null) encDevs; + + # With scripted initrd, devices with a keyFile have to be opened + # late, after file systems are mounted, because that could be where + # the keyFile is located. With systemd initrd, each individual + # systemd-cryptsetup@ unit has RequiresMountsFor= to delay until all + # the mount units for the key file are done; i.e. no special + # treatment is needed. + lateEncDevs = + if config.boot.initrd.systemd.enable + then { } + else filter (dev: dev.encrypted.keyFile != null) encDevs; + earlyEncDevs = + if config.boot.initrd.systemd.enable + then encDevs + else filter (dev: dev.encrypted.keyFile == null) encDevs; + anyEncrypted = foldr (j: v: v || j.encrypted.enable) false encDevs; @@ -39,11 +53,14 @@ let type = types.nullOr types.str; description = lib.mdDoc '' Path to a keyfile used to unlock the backing encrypted - device. At the time this keyfile is accessed, the - `neededForBoot` filesystems (see - `fileSystems..neededForBoot`) - will have been mounted under `/mnt-root`, - so the keyfile path should usually start with "/mnt-root/". + device. When systemd stage 1 is not enabled, at the time + this keyfile is accessed, the `neededForBoot` filesystems + (see `utils.fsNeededForBoot`) will have been mounted under + `/mnt-root`, so the keyfile path should usually start with + "/mnt-root/". When systemd stage 1 is enabled, + `fsNeededForBoot` file systems will be mounted as needed + under `/sysroot`, and the keyfile will not be accessed until + its requisite mounts are done. ''; }; }; @@ -62,26 +79,41 @@ in }; config = mkIf anyEncrypted { - assertions = map (dev: { - assertion = dev.encrypted.label != null; - message = '' - The filesystem for ${dev.mountPoint} has encrypted.enable set to true, but no encrypted.label set - ''; - }) encDevs; + assertions = concatMap (dev: [ + { + assertion = dev.encrypted.label != null; + message = '' + The filesystem for ${dev.mountPoint} has encrypted.enable set to true, but no encrypted.label set + ''; + } + { + assertion = + config.boot.initrd.systemd.enable -> ( + dev.encrypted.keyFile == null + || !lib.any (x: lib.hasPrefix x dev.encrypted.keyFile) ["/mnt-root" "$targetRoot"] + ); + message = '' + Bad use of '/mnt-root' or '$targetRoot` in 'keyFile'. + + When 'boot.initrd.systemd.enable' is enabled, file systems + are mounted at '/sysroot' instead of '/mnt-root'. + ''; + } + ]) encDevs; boot.initrd = { luks = { devices = builtins.listToAttrs (map (dev: { name = dev.encrypted.label; - value = { device = dev.encrypted.blkDev; }; - }) keylessEncDevs); + value = { device = dev.encrypted.blkDev; inherit (dev.encrypted) keyFile; }; + }) earlyEncDevs); forceLuksSupportInInitrd = true; }; postMountCommands = concatMapStrings (dev: "cryptsetup luksOpen --key-file ${dev.encrypted.keyFile} ${dev.encrypted.blkDev} ${dev.encrypted.label};\n" - ) keyedEncDevs; + ) lateEncDevs; }; }; } diff --git a/nixos/tests/installer-systemd-stage-1.nix b/nixos/tests/installer-systemd-stage-1.nix index 85155a6c682b..608a21ef6372 100644 --- a/nixos/tests/installer-systemd-stage-1.nix +++ b/nixos/tests/installer-systemd-stage-1.nix @@ -12,11 +12,11 @@ btrfsSubvolDefault btrfsSubvolEscape btrfsSubvols - # encryptedFSWithKeyfile + encryptedFSWithKeyfile # grub1 - # luksroot - # luksroot-format1 - # luksroot-format2 + luksroot + luksroot-format1 + luksroot-format2 # lvm separateBoot separateBootFat diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 9ff1d8f5d039..15ece034898a 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -515,7 +515,7 @@ let enableOCR = true; preBootCommands = '' machine.start() - machine.wait_for_text("Passphrase for") + machine.wait_for_text("[Pp]assphrase for") machine.send_chars("supersecret\n") ''; }; @@ -781,7 +781,7 @@ in { encrypted.enable = true; encrypted.blkDev = "/dev/vda3"; encrypted.label = "crypt"; - encrypted.keyFile = "/mnt-root/keyfile"; + encrypted.keyFile = "/${if systemdStage1 then "sysroot" else "mnt-root"}/keyfile"; }; ''; };