nixos-config/lib/fudo/host-filesystems.nix

94 lines
3.4 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
hostname = config.instance.hostname;
host-filesystems = config.fudo.hosts.${hostname}.encrypted-filesystems;
optionalOrDefault = tst: str: default: if tst then str else default;
filesystemsToMountpointLists = mapAttrsToList
(fs: fsOpts: fsOpts.mountpoints);
in {
config = {
users.groups = let
mountpointToGroups = mp: mpOpts:
optional (mpOpts.group != null)
(nameValuePair mpOpts.group {
members = mpOpts.users;
});
mountpointListsToGroups = mapConcat
(mps: mapAttrsToList mountpointToGroups mps);
in listToAttrs
(mountpointListsToGroups
(filesystemsToMountpointLists host-filesystems));
systemd = {
# Ensure the mountpoints exist
tmpfiles.rules = let
mountpointToPath = mp: mpOpts:
"d '${mp}' - root ${optionalOrDefault mpOpts.group "-"} - -";
filesystemsToMountpointLists = mapAttrsToList
(fs: fsOpts: fsOpts.mountpoints);
mountpointListsToPaths = concatMap
(mps: mapAttrsToList mountpointToPath mps);
in mountpointListsToPaths (filesystemsToMountpointLists host-filesystems);
# Actual mounts of decrypted filesystems
mounts = let
filesystems = mapAttrsToList
(fs: opts: { filesystem = fs; opts = opts; })
host-filesystems;
mounts = concatMap
(fs: mapAttrsToList
(mp: mp-opts:
{
what = "/dev/mapper/${fs.filesystem}";
type = fs.opts.filesystem-type;
where = mp;
options = concatStringsSep "," (fs.opts.options ++ mp-opts.options);
wantedBy = [ "default.target" ];
description = "${fs.opts.filesystem-type} filesystem on ${fs.filesystem} mounted to ${mp}";
requires = [ "${fs.filesystem}-decrypt.service" ];
})
fs.opts.mountpoints)
filesystems;
in mounts;
# Jobs to decrypt the encrypted devices
services = mapAttrs' (filesystem-name: opts:
nameValuePair "${filesystem-name}-decrypt"
{
wantedBy = [ "default.target" ];
description = "Decrypt the ${filesystem-name} filesystem when the key is available at ${opts.key-path}";
path = with pkgs; [ cryptsetup ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "decrypt-${filesystem-name}.sh" ''
[ ! -d /dev/mapper/${filesystem-name} ] || cryptsetup open --type luks --key-file ${opts.key-path} ${opts.encrypted-device} ${filesystem-name}
'';
ExecStop = pkgs.writeShellScript "close-${filesystem-name}.sh" ''
cryptsetup close /dev/mapper/${filesystem-name}
'';
};
})
host-filesystems;
# Watch the path of the key, trigger decrypt when it's available
paths = mapAttrs' (filesystem-name: opts:
nameValuePair "${filesystem-name}-decrypt"
{
wantedBy = [ "default.target" ];
description = "Watch for decryption key, then decrypt the target filesystem.";
pathConfig = {
PathExists = opts.key-path;
Service = "${filesystem-name}-decrypt.service";
};
}) host-filesystems;
};
};
}