{ config, lib, pkgs, ... }: with lib; let hostname = config.instance.hostname; host-filesystems = config.fudo.hosts.${hostname}.encrypted-filesystems; in { config = { fileSystems = mapAttrs' (filesystem-name: opts: nameValuePair opts.target-path { device = "/dev/mapper/${filesystem-name}"; fsType = opts.filesystem-type; options = opts.filesystem-options; }) host-filesystems; systemd = { mounts = let filesystems = mapAttrstoList (fs: opts: { filesystem = fs; opts = opts; }) host-filesystems; mounts = concatMap (fs: mapAttrsToList (mp: mp-opts: nameValuePair "${fs.filesystem}-${mp}-mount" { 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 ${filesystem} mounted to ${mp}"; requires = [ "${fs.filesystem}-decrypt.service" ]; }) fs.opts.mountpoints) filesystems; in mounts; 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 = { ExecStart = pkgs.writeShellScript "decrypt-${filesystem-name}.sh" '' cryptsetup open --type luks --key-file ${opts.key-path} ${opts.device} ${filesystem-name} ''; ExecStop = pkgs.writeShellScript "close-${filesystem-name}.sh" '' cryptsetup close /dev/mapper/${filesystem-name} ''; }; }) host-filesystems; 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; }; }; }