121 lines
3.8 KiB
Nix
121 lines
3.8 KiB
Nix
{ 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;
|
|
};
|
|
}
|
|
);
|
|
}
|