at 24.11-pre 4.0 kB view raw
1{ config, lib, ... }: 2 3with lib; 4 5let 6 fileSystems = config.system.build.fileSystems ++ config.swapDevices; 7 encDevs = filter (dev: dev.encrypted.enable) fileSystems; 8 9 # With scripted initrd, devices with a keyFile have to be opened 10 # late, after file systems are mounted, because that could be where 11 # the keyFile is located. With systemd initrd, each individual 12 # systemd-cryptsetup@ unit has RequiresMountsFor= to delay until all 13 # the mount units for the key file are done; i.e. no special 14 # treatment is needed. 15 lateEncDevs = 16 if config.boot.initrd.systemd.enable 17 then { } 18 else filter (dev: dev.encrypted.keyFile != null) encDevs; 19 earlyEncDevs = 20 if config.boot.initrd.systemd.enable 21 then encDevs 22 else filter (dev: dev.encrypted.keyFile == null) encDevs; 23 24 anyEncrypted = 25 foldr (j: v: v || j.encrypted.enable) false encDevs; 26 27 encryptedFSOptions = { 28 29 options.encrypted = { 30 enable = mkOption { 31 default = false; 32 type = types.bool; 33 description = "The block device is backed by an encrypted one, adds this device as a initrd luks entry."; 34 }; 35 36 blkDev = mkOption { 37 default = null; 38 example = "/dev/sda1"; 39 type = types.nullOr types.str; 40 description = "Location of the backing encrypted device."; 41 }; 42 43 label = mkOption { 44 default = null; 45 example = "rootfs"; 46 type = types.nullOr types.str; 47 description = "Label of the unlocked encrypted device. Set `fileSystems.<name?>.device` to `/dev/mapper/<label>` to mount the unlocked device."; 48 }; 49 50 keyFile = mkOption { 51 default = null; 52 example = "/mnt-root/root/.swapkey"; 53 type = types.nullOr types.str; 54 description = '' 55 Path to a keyfile used to unlock the backing encrypted 56 device. When systemd stage 1 is not enabled, at the time 57 this keyfile is accessed, the `neededForBoot` filesystems 58 (see `utils.fsNeededForBoot`) will have been mounted under 59 `/mnt-root`, so the keyfile path should usually start with 60 "/mnt-root/". When systemd stage 1 is enabled, 61 `fsNeededForBoot` file systems will be mounted as needed 62 under `/sysroot`, and the keyfile will not be accessed until 63 its requisite mounts are done. 64 ''; 65 }; 66 }; 67 }; 68in 69 70{ 71 72 options = { 73 fileSystems = mkOption { 74 type = with lib.types; attrsOf (submodule encryptedFSOptions); 75 }; 76 swapDevices = mkOption { 77 type = with lib.types; listOf (submodule encryptedFSOptions); 78 }; 79 }; 80 81 config = mkIf anyEncrypted { 82 assertions = concatMap (dev: [ 83 { 84 assertion = dev.encrypted.label != null; 85 message = '' 86 The filesystem for ${dev.mountPoint} has encrypted.enable set to true, but no encrypted.label set 87 ''; 88 } 89 { 90 assertion = 91 config.boot.initrd.systemd.enable -> ( 92 dev.encrypted.keyFile == null 93 || !lib.any (x: lib.hasPrefix x dev.encrypted.keyFile) ["/mnt-root" "$targetRoot"] 94 ); 95 message = '' 96 Bad use of '/mnt-root' or '$targetRoot` in 'keyFile'. 97 98 When 'boot.initrd.systemd.enable' is enabled, file systems 99 are mounted at '/sysroot' instead of '/mnt-root'. 100 ''; 101 } 102 ]) encDevs; 103 104 boot.initrd = { 105 luks = { 106 devices = 107 builtins.listToAttrs (map (dev: { 108 name = dev.encrypted.label; 109 value = { device = dev.encrypted.blkDev; inherit (dev.encrypted) keyFile; }; 110 }) earlyEncDevs); 111 forceLuksSupportInInitrd = true; 112 }; 113 # TODO: systemd stage 1 114 postMountCommands = lib.mkIf (!config.boot.initrd.systemd.enable) 115 (concatMapStrings (dev: 116 "cryptsetup luksOpen --key-file ${dev.encrypted.keyFile} ${dev.encrypted.blkDev} ${dev.encrypted.label};\n" 117 ) lateEncDevs); 118 }; 119 }; 120}