Skip to content

Commit 7b1335e

Browse files
committed
add wip verity
1 parent d32f2d1 commit 7b1335e

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

lib/types/verity.nix

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
{ config, options, lib, diskoLib, parent, ... }:
2+
# EXPERIMENTAL: This module provides verification of install images through dm-verity
3+
# We do not provide updating nixos configuration through nixos-rebuild switch, when using this.
4+
# This is mainly useful in the context of generated images, that are booted with secure boot.
5+
let
6+
diskoConfig = config;
7+
in
8+
{
9+
options = {
10+
type = lib.mkOption {
11+
type = lib.types.enum [ "verity" ];
12+
internal = true;
13+
description = "Type";
14+
};
15+
name = lib.mkOption {
16+
type = lib.types.str;
17+
default = config._module.args.name;
18+
description = "Name of the veritysetup device";
19+
};
20+
# can we get those from device directly?
21+
dataDevice = lib.mkOption {
22+
type = lib.types.str;
23+
description = "Device to store the data";
24+
};
25+
hashDevice = lib.mkOption {
26+
type = lib.types.str;
27+
description = "Device to store the merkle tree";
28+
};
29+
extraFormatArgs = lib.mkOption {
30+
type = lib.types.listOf lib.types.str;
31+
default = [ ];
32+
description = "Extra arguments to pass to `veritysetup format`";
33+
example = [ "--debug" ];
34+
};
35+
extraOpenArgs = lib.mkOption {
36+
type = lib.types.listOf lib.types.str;
37+
default = [ ];
38+
description = "Extra arguments to pass to `cryptsetup luksOpen` when opening";
39+
example = [ "--timeout 10" ];
40+
};
41+
content = diskoLib.deviceType { parent = config; device = "/dev/mapper/${config.name}"; };
42+
_parent = lib.mkOption {
43+
internal = true;
44+
default = parent;
45+
};
46+
_meta = lib.mkOption {
47+
internal = true;
48+
readOnly = true;
49+
type = lib.types.functionTo diskoLib.jsonType;
50+
default = dev:
51+
lib.optionalAttrs (config.content != null) (config.content._meta dev);
52+
description = "Metadata";
53+
};
54+
_create = diskoLib.mkCreateOption {
55+
inherit config options;
56+
default = {};
57+
};
58+
_mount = diskoLib.mkMountOption {
59+
inherit config options;
60+
default = {};
61+
};
62+
_unmount = diskoLib.mkMountOption {
63+
inherit config options;
64+
default = {};
65+
};
66+
_config = lib.mkOption {
67+
internal = true;
68+
readOnly = true;
69+
default = [
70+
({config, pkgs, ...}: {
71+
# Maybe secureboot should be left to the user?
72+
boot.uki.settings = {
73+
# TODO
74+
# SecureBootPrivateKey = "./out";
75+
};
76+
# TODO: upstream this.
77+
assertions = [
78+
{
79+
assertion = config.boot.inird.systemd.enable;
80+
message = ''
81+
veritysetup with disko requires systemd in the initrd to be enabled.
82+
'';
83+
}
84+
];
85+
# TODO: we want actually
86+
boot.kernelParams = [
87+
"systemd.verity_root_data=${diskoConfig.dataDevice}"
88+
"systemd.verity_root_hash=${diskoConfig.hashDevice}"
89+
];
90+
boot.initrd = {
91+
availableKernelModules = [ "dm_mod" "dm_verity" ];
92+
# We need LVM for dm-verity to work.
93+
services.lvm.enable = true;
94+
95+
systemd = {
96+
additionalUpstreamUnits = [ "veritysetup-pre.target" "veritysetup.target" "remote-veritysetup.target" ];
97+
storePaths = [
98+
"${config.boot.initrd.systemd.package}/lib/systemd/systemd-veritysetup"
99+
"${config.boot.initrd.systemd.package}/lib/systemd/system-generators/systemd-veritysetup-generator"
100+
];
101+
};
102+
};
103+
104+
boot.bootspec.enable = true;
105+
boot.loader.external = {
106+
enable = true;
107+
installHook =
108+
let
109+
bootspecNamespace = ''"org.nixos.bootspec.v1"'';
110+
installer = pkgs.writeShellApplication {
111+
name = "install-uki";
112+
runtimeInputs = with pkgs; [ jq systemd binutils ];
113+
text = ''
114+
boot_json=/nix/var/nix/profiles/system-1-link/boot.json
115+
tempdir=$(mktemp -d)
116+
trap 'rm -rf "$tempdir"' EXIT
117+
kernel=$(jq -r '.${bootspecNamespace}.kernel' "$boot_json")
118+
initrd=$(jq -r '.${bootspecNamespace}.initrd' "$boot_json")
119+
init=$(jq -r '.${bootspecNamespace}.init' "$boot_json")
120+
121+
# TODO: get access to the unmount script for config.dataDevice by injecting toplevel-config into disko
122+
veritysetup format ${config.dataDevice} ${config.hashDevice} \
123+
--root-hash-file "$tempdir/verity_roothash_${config.name}"
124+
125+
${pkgs.systemdUkify}/lib/systemd/ukify \
126+
"$kernel" \
127+
"$initrd" \
128+
--stub="${pkgs.systemd}/lib/systemd/boot/efi/linux${pkgs.hostPlatform.efiArch}.efi.stub" \
129+
--cmdline="init=$init ${builtins.toString config.boot.kernelParams} roothash=$(<$tempdir/verity_roothash_${config.name})" \
130+
--os-release="@${config.system.build.etc}/etc/os-release" \
131+
--output=uki.efi
132+
133+
esp=${config.boot.loader.efi.efiSysMountPoint}
134+
135+
bootctl install --esp-path="$esp"
136+
install uki.efi "$esp"/EFI/Linux/
137+
'';
138+
};
139+
in
140+
"${lib.getExe installer}";
141+
};
142+
143+
})
144+
] ++ (lib.optional (config.content != null) config.content._config);
145+
description = "NixOS configuration";
146+
};
147+
_pkgs = lib.mkOption {
148+
internal = true;
149+
readOnly = true;
150+
type = lib.types.functionTo (lib.types.listOf lib.types.package);
151+
default = pkgs: lib.optionals (config.content != null) (config.content._pkgs pkgs);
152+
description = "Packages";
153+
};
154+
};
155+
}

0 commit comments

Comments
 (0)