98 lines
3.5 KiB
Nix
98 lines
3.5 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
let
|
|
hostname = config.instance.hostname;
|
|
host-filesystems = config.fudo.hosts.${hostname}.encrypted-filesystems;
|
|
|
|
optionalOrDefault = str: default: if (str != null) then str else default;
|
|
|
|
filesystemsToMountpointLists = mapAttrsToList
|
|
(fs: fsOpts: fsOpts.mountpoints);
|
|
|
|
concatMapAttrs = f: as: concatMap (i: i) (mapAttrsToList f as);
|
|
|
|
in {
|
|
config = {
|
|
users.groups = let
|
|
mountpointToGroups = mp: mpOpts:
|
|
optional (mpOpts.group != null)
|
|
(nameValuePair mpOpts.group {
|
|
members = mpOpts.users;
|
|
});
|
|
mountpointListToGroups =
|
|
concatMapAttrs mountpointToGroups;
|
|
mountpointListsToGroups =
|
|
concatMap mountpointListToGroups;
|
|
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;
|
|
};
|
|
};
|
|
}
|