diff --git a/machines/raven/configuration.nix b/machines/raven/configuration.nix index 13b1e8e..7cf07e8 100644 --- a/machines/raven/configuration.nix +++ b/machines/raven/configuration.nix @@ -90,5 +90,14 @@ "192.168.94.1" = [ "raven.lab.fablab-nea.de" "labsync.lab.fablab-nea.de" ]; }; + fablab.luksUsbUnlock = { + enable = true; + devices."${config.disko.devices.disk.nvme.content.partitions.luks.content.name}" = { + keyPath = "${config.networking.hostName}.key"; + usbDevice = "by-label/RAM_USB"; + waitForDevice = 10; + }; + }; + system.stateVersion = "24.05"; } diff --git a/machines/raven/disko.nix b/machines/raven/disko.nix index 6492d69..8414703 100644 --- a/machines/raven/disko.nix +++ b/machines/raven/disko.nix @@ -26,9 +26,6 @@ name = "raven-crypt"; settings = { allowDiscards = true; - keyFileSize = 4096; - keyFile = "/dev/disk/by-id/usb-jalr_USB_RAM_disk_prototype-01-0:0"; - keyFileTimeout = 10; }; extraFormatArgs = [ "--hash sha512 --use-random --pbkdf argon2id --iter-time 5000 --pbkdf-memory ${builtins.toString (4*1024*1024)} --pbkdf-parallel 4" ]; content = { diff --git a/modules/default.nix b/modules/default.nix index 244c94d..f3fbce0 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,6 +1,7 @@ { imports = [ ./base.nix + ./luksusb.nix ./nix.nix ./pipewire.nix ./pubkeys.nix diff --git a/modules/luksusb.nix b/modules/luksusb.nix new file mode 100644 index 0000000..17b931b --- /dev/null +++ b/modules/luksusb.nix @@ -0,0 +1,121 @@ +{ config, lib, ... }: +let + cfg = config.fablab.luksUsbUnlock; +in +{ + options.fablab.luksUsbUnlock = with lib; with lib.types; { + enable = mkEnableOption "unlock LUKS volumes with a USB device on boot"; + devices = mkOption { + default = { }; + example = { + cryptroot = { + keyPath = "/path/to/the/key"; + usbDevice = "by-label/MY_USB"; + }; + }; + type = types.attrsOf (types.submodule { + options = { + keyPath = mkOption { + example = "/mykey.key"; + description = mdDoc '' + Path to the key file inside the USB device's filesystem. + `/` is relative to the device's filesystem root. + ''; + type = types.str; + }; + + usbDevice = mkOption { + example = "by-label/BOOTKEY"; + description = mdDoc '' + Path to the USB device that contains the keys. (Path relative to `/dev/disk/`) + ''; + type = types.str; + }; + + waitForDevice = mkOption { + default = 5; + example = 10; + description = mdDoc '' + How many seconds to wait for the USB device to be detected by the + kernel. + ''; + type = types.ints.unsigned; + }; + }; + }); + }; + }; + config = lib.mkIf cfg.enable ( + let + makeUsbDevPath = usbDevice: "/dev/disk/" + usbDevice; + makeMountPath = usbDevice: "/key/" + (builtins.hashString "md5" usbDevice); + usbFsType = "vfat"; + + mapAttrsNameValue = f: set: + lib.listToAttrs (map f (lib.attrsToList set)); + in + { + boot.initrd = { + kernelModules = [ "uas" "usbcore" "usb_storage" "vfat" "nls_cp437" "nls_iso8859_1" ]; + systemd.services = + let + makeService = name: { usbDevice, waitForDevice, ... }: + let + usbDevPath = makeUsbDevPath usbDevice; + usbMountPath = makeMountPath usbDevice; + in + { + description = "Mount ${name} key"; + wantedBy = [ "cryptsetup.target" ]; + before = [ "systemd-cryptsetup@${name}.service" ]; + after = [ "systemd-modules-load.service" ]; + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + + script = '' + if awk -v mountpoint="${usbMountPath}" '$2==mountpoint {f=1} END {exit !f}' /proc/mounts; then + exit 0 + fi + + attempts=0 + while [ ! -e ${lib.escapeShellArg usbDevPath} ]; do + sleep 1 + if [ $attempts -ge ${toString waitForDevice} ]; then + break; + fi + attempts=$((attempts+1)) + done + + if [ -e ${lib.escapeShellArg usbDevPath} ]; then + mkdir -m0500 -p ${lib.escapeShellArg usbMountPath} + mount \ + -n \ + -t ${lib.escapeShellArg usbFsType} \ + -o ro,fmask=0137,dmask=0027 \ + ${lib.escapeShellArg usbDevPath} \ + ${lib.escapeShellArg usbMountPath} + fi + ''; + }; + in + mapAttrsNameValue + ({ name, value }: { + name = "luksusb-${name}"; + value = makeService name value; + }) + cfg.devices; + + luks.devices = builtins.mapAttrs + (_: { keyPath, usbDevice, ... }: + let + usbMountPath = makeMountPath usbDevice; + in + { + keyFile = "${usbMountPath}/${keyPath}"; + keyFileTimeout = 1; + }) + cfg.devices; + }; + } + ); +}