Skip to content

Commit

Permalink
nixos/tests/appliance-repart-image-verity-store: init
Browse files Browse the repository at this point in the history
This test should illustrate how to build a verity-protected NixOS image
with systemd-repart, using the opinionated image.repart.verityStore module.
  • Loading branch information
WilliButz committed Sep 20, 2024
1 parent 942588c commit 56d038e
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ in {
apcupsd = handleTest ./apcupsd.nix {};
apfs = runTest ./apfs.nix;
appliance-repart-image = runTest ./appliance-repart-image.nix;
appliance-repart-image-verity-store = runTest ./appliance-repart-image-verity-store.nix;
apparmor = handleTest ./apparmor.nix {};
archi = handleTest ./archi.nix {};
aria2 = handleTest ./aria2.nix {};
Expand Down
130 changes: 130 additions & 0 deletions nixos/tests/appliance-repart-image-verity-store.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# similar to the appliance-repart-image test but with a dm-verity
# protected nix store and tmpfs as rootfs
{ lib, ... }:

{
name = "appliance-repart-image-verity-store";

meta.maintainers = with lib.maintainers; [
nikstur
willibutz
];

nodes.machine =
{
config,
lib,
pkgs,
...
}:
let
inherit (config.image.repart.verityStore) partitionIds;
in
{
imports = [ ../modules/image/repart.nix ];

virtualisation.fileSystems = lib.mkVMOverride {
"/" = {
fsType = "tmpfs";
options = [ "mode=0755" ];
};

"/usr" = {
device = "/dev/mapper/usr";
# explicitly mount it read-only otherwise systemd-remount-fs will fail
options = [ "ro" ];
fsType = config.image.repart.partitions.${partitionIds.store}.repartConfig.Format;
};

# bind-mount the store
"/nix/store" = {
device = "/usr/nix/store";
options = [ "bind" ];
};
};

image.repart = {
verityStore = {
enable = true;
# by default the module works with systemd-boot, for simplicity this test directly boots the UKI
ukiPath = "/EFI/BOOT/BOOT${lib.toUpper config.nixpkgs.hostPlatform.efiArch}.EFI";
};

name = "appliance-verity-store-image";

partitions = {
${partitionIds.esp} = {
# the UKI is injected into this partition by the verityStore module
repartConfig = {
Type = "esp";
Format = "vfat";
SizeMinBytes = if config.nixpkgs.hostPlatform.isx86_64 then "64M" else "96M";
};
};
${partitionIds.store-verity}.repartConfig = {
Minimize = "best";
};
${partitionIds.store}.repartConfig = {
Minimize = "best";
};
};
};

virtualisation = {
directBoot.enable = false;
mountHostNixStore = false;
useEFIBoot = true;
};

boot = {
loader.grub.enable = false;
initrd.systemd.enable = true;
};

system.image = {
id = "nixos-appliance";
version = "1";
};

# don't create /usr/bin/env
# this would require some extra work on read-only /usr
# and it is not a strict necessity
system.activationScripts.usrbinenv = lib.mkForce "";
};

testScript =
{ nodes, ... }: # python
''
import os
import subprocess
import tempfile
tmp_disk_image = tempfile.NamedTemporaryFile()
subprocess.run([
"${nodes.machine.virtualisation.qemu.package}/bin/qemu-img",
"create",
"-f",
"qcow2",
"-b",
"${nodes.machine.system.build.finalImage}/${nodes.machine.image.repart.imageFile}",
"-F",
"raw",
tmp_disk_image.name,
])
os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name
machine.wait_for_unit("default.target")
with subtest("Running with volatile root"):
machine.succeed("findmnt --kernel --type tmpfs /")
with subtest("/nix/store is backed by dm-verity protected fs"):
verity_info = machine.succeed("dmsetup info --target verity usr")
assert "ACTIVE" in verity_info,f"unexpected verity info: {verity_info}"
backing_device = machine.succeed("df --output=source /nix/store | tail -n1").strip()
assert "/dev/mapper/usr" == backing_device,"unexpected backing device: {backing_device}"
'';
}

0 comments on commit 56d038e

Please sign in to comment.