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 keyedEncDevs = filter (dev: dev.encrypted.keyFile != null) encDevs;
9 keylessEncDevs = filter (dev: dev.encrypted.keyFile == null) encDevs;
10 anyEncrypted =
11 foldr (j: v: v || j.encrypted.enable) false encDevs;
12
13 encryptedFSOptions = {
14
15 options.encrypted = {
16 enable = mkOption {
17 default = false;
18 type = types.bool;
19 description = lib.mdDoc "The block device is backed by an encrypted one, adds this device as a initrd luks entry.";
20 };
21
22 blkDev = mkOption {
23 default = null;
24 example = "/dev/sda1";
25 type = types.nullOr types.str;
26 description = lib.mdDoc "Location of the backing encrypted device.";
27 };
28
29 label = mkOption {
30 default = null;
31 example = "rootfs";
32 type = types.nullOr types.str;
33 description = lib.mdDoc "Label of the unlocked encrypted device. Set `fileSystems.<name?>.device` to `/dev/mapper/<label>` to mount the unlocked device.";
34 };
35
36 keyFile = mkOption {
37 default = null;
38 example = "/mnt-root/root/.swapkey";
39 type = types.nullOr types.str;
40 description = lib.mdDoc ''
41 Path to a keyfile used to unlock the backing encrypted
42 device. At the time this keyfile is accessed, the
43 `neededForBoot` filesystems (see
44 `fileSystems.<name?>.neededForBoot`)
45 will have been mounted under `/mnt-root`,
46 so the keyfile path should usually start with "/mnt-root/".
47 '';
48 };
49 };
50 };
51in
52
53{
54
55 options = {
56 fileSystems = mkOption {
57 type = with lib.types; attrsOf (submodule encryptedFSOptions);
58 };
59 swapDevices = mkOption {
60 type = with lib.types; listOf (submodule encryptedFSOptions);
61 };
62 };
63
64 config = mkIf anyEncrypted {
65 assertions = map (dev: {
66 assertion = dev.encrypted.label != null;
67 message = ''
68 The filesystem for ${dev.mountPoint} has encrypted.enable set to true, but no encrypted.label set
69 '';
70 }) encDevs;
71
72 boot.initrd = {
73 luks = {
74 devices =
75 builtins.listToAttrs (map (dev: {
76 name = dev.encrypted.label;
77 value = { device = dev.encrypted.blkDev; };
78 }) keylessEncDevs);
79 forceLuksSupportInInitrd = true;
80 };
81 postMountCommands =
82 concatMapStrings (dev:
83 "cryptsetup luksOpen --key-file ${dev.encrypted.keyFile} ${dev.encrypted.blkDev} ${dev.encrypted.label};\n"
84 ) keyedEncDevs;
85 };
86 };
87}