From 69e24a579c9a03e7c802323c78959a1560845bc3 Mon Sep 17 00:00:00 2001 From: Tom Fitzhenry Date: Mon, 27 Feb 2023 00:30:19 +1100 Subject: nixos/module: add boot.initrd.unl0kr --- nixos/modules/module-list.nix | 1 + nixos/modules/system/boot/unl0kr.nix | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 nixos/modules/system/boot/unl0kr.nix (limited to 'nixos') diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index cbd5e6467f82..24172cb715b1 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1406,6 +1406,7 @@ ./system/boot/stratisroot.nix ./system/boot/modprobe.nix ./system/boot/networkd.nix + ./system/boot/unl0kr.nix ./system/boot/plymouth.nix ./system/boot/resolved.nix ./system/boot/shutdown.nix diff --git a/nixos/modules/system/boot/unl0kr.nix b/nixos/modules/system/boot/unl0kr.nix new file mode 100644 index 000000000000..8d9af37382e0 --- /dev/null +++ b/nixos/modules/system/boot/unl0kr.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.boot.initrd.unl0kr; +in +{ + options.boot.initrd.unl0kr = { + enable = lib.mkEnableOption (lib.mdDoc "unl0kr in initrd") // { + description = lib.mdDoc '' + Whether to enable the unl0kr on-screen keyboard in initrd to unlock LUKS. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + meta.maintainers = with lib.maintainers; [ tomfitzhenry ]; + assertions = [ + { + assertion = cfg.enable -> config.boot.initrd.systemd.enable; + message = "boot.initrd.unl0kr is only supported with boot.initrd.systemd."; + } + ]; + + boot.initrd.systemd = { + storePaths = with pkgs; [ + "${pkgs.gnugrep}/bin/grep" + libinput + xkeyboard_config + "${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password" + "${pkgs.unl0kr}/bin/unl0kr" + ]; + services = { + unl0kr-ask-password = { + description = "Forward Password Requests to unl0kr"; + conflicts = [ + "emergency.service" + "initrd-switch-root.target" + "shutdown.target" + ]; + unitConfig.DefaultDependencies = false; + after = [ + "systemd-vconsole-setup.service" + "udev.service" + ]; + before = [ + "shutdown.target" + ]; + script = '' + # This script acts as a Password Agent: https://systemd.io/PASSWORD_AGENTS/ + + DIR=/run/systemd/ask-password/ + # If a user has multiple encrypted disks, the requests might come in different times, + # so make sure to answer as many requests as we can. Once boot succeeds, other + # password agents will be responsible for watching for requests. + while [ -d $DIR ] && [ "$(ls -A $DIR/ask.*)" ]; + do + for file in `ls $DIR/ask.*`; do + socket="$(cat "$file" | ${pkgs.gnugrep}/bin/grep "Socket=" | cut -d= -f2)" + ${pkgs.unl0kr}/bin/unl0kr | ${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password 1 "$socket" + done + done + ''; + }; + }; + + paths = { + unl0kr-ask-password = { + description = "Forward Password Requests to unl0kr"; + conflicts = [ + "emergency.service" + "initrd-switch-root.target" + "shutdown.target" + ]; + unitConfig.DefaultDependencies = false; + before = [ + "shutdown.target" + "paths.target" + "cryptsetup.target" + ]; + wantedBy = [ "sysinit.target" ]; + pathConfig = { + DirectoryNotEmpty = "/run/systemd/ask-password"; + MakeDirectory = true; + }; + }; + }; + }; + }; +} -- cgit 1.4.1 From c5512988b125e38fdf1edbd82302335ded797924 Mon Sep 17 00:00:00 2001 From: Tom Fitzhenry Date: Mon, 27 Feb 2023 00:30:25 +1100 Subject: nixos/tests: init systemd-initrd-luks-unl0kr --- nixos/tests/all-tests.nix | 1 + nixos/tests/systemd-initrd-luks-unl0kr.nix | 75 ++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 nixos/tests/systemd-initrd-luks-unl0kr.nix (limited to 'nixos') diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 9fae33a9b347..8119608b2f0b 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -773,6 +773,7 @@ in { systemd-initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix { systemdStage1 = true; }; systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {}; systemd-initrd-luks-tpm2 = handleTest ./systemd-initrd-luks-tpm2.nix {}; + systemd-initrd-luks-unl0kr = handleTest ./systemd-initrd-luks-unl0kr.nix {}; systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {}; systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; }; systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {}; diff --git a/nixos/tests/systemd-initrd-luks-unl0kr.nix b/nixos/tests/systemd-initrd-luks-unl0kr.nix new file mode 100644 index 000000000000..0658a098cfa2 --- /dev/null +++ b/nixos/tests/systemd-initrd-luks-unl0kr.nix @@ -0,0 +1,75 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: let + passphrase = "secret"; +in { + name = "systemd-initrd-luks-unl0kr"; + meta = with pkgs.lib.maintainers; { + maintainers = [ tomfitzhenry ]; + }; + + enableOCR = true; + + nodes.machine = { pkgs, ... }: { + virtualisation = { + emptyDiskImages = [ 512 512 ]; + useBootLoader = true; + mountHostNixStore = true; + useEFIBoot = true; + qemu.options = [ + "-vga virtio" + ]; + }; + boot.loader.systemd-boot.enable = true; + + boot.initrd.availableKernelModules = [ + "evdev" # for entering pw + "bochs" + ]; + + environment.systemPackages = with pkgs; [ cryptsetup ]; + boot.initrd = { + systemd = { + enable = true; + emergencyAccess = true; + }; + unl0kr.enable = true; + }; + + specialisation.boot-luks.configuration = { + boot.initrd.luks.devices = lib.mkVMOverride { + # We have two disks and only type one password - key reuse is in place + cryptroot.device = "/dev/vdb"; + cryptroot2.device = "/dev/vdc"; + }; + virtualisation.rootDevice = "/dev/mapper/cryptroot"; + virtualisation.fileSystems."/".autoFormat = true; + # test mounting device unlocked in initrd after switching root + virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2"; + }; + }; + + testScript = '' + # Create encrypted volume + machine.wait_for_unit("multi-user.target") + machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -") + machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -") + machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen -q /dev/vdc cryptroot2") + machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2") + + # Boot from the encrypted disk + machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf") + machine.succeed("sync") + machine.crash() + + # Boot and decrypt the disk + machine.start() + machine.wait_for_text("Password required for booting") + machine.screenshot("prompt") + machine.send_chars("${passphrase}") + machine.screenshot("pw") + machine.send_chars("\n") + machine.wait_for_unit("multi-user.target") + + assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount"), "/dev/mapper/cryptroot do not appear in mountpoints list" + assert "/dev/mapper/cryptroot2 on /cryptroot2 type ext4" in machine.succeed("mount") + ''; +}) -- cgit 1.4.1