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