{ config, lib, pkgs, ... }: with lib; let cfg = config.fudo.password; genOpts = { options = { file = mkOption { type = types.str; description = "Password file in which to store a generated password."; }; user = mkOption { type = types.str; description = "User to which the file should belong."; }; group = mkOption { type = with types; nullOr str; description = "Group to which the file should belong."; default = "nogroup"; }; restart-services = mkOption { type = with types; listOf str; description = "List of services to restart when the password file is generated."; default = []; }; }; }; generate-passwd-file = file: user: group: pkgs.writeShellScriptBin "generate-passwd-file.sh" '' mkdir -p $(dirname ${file}) if touch ${file}; then chown ${user}${optionalString (group != null) ":${group}"} ${file} if [ $? -ne 0 ]; then rm ${file} echo "failed to set permissions on ${file}" exit 4 fi ${pkgs.pwgen}/bin/pwgen 30 1 > ${file} else echo "cannot write to ${file}" exit 2 fi if [ ! -f ${file} ]; then echo "Failed to create file ${file}" exit 3 fi ${if (group != null) then "chmod 640 ${file}" else "chmod 600 ${file}"} echo "created password file ${file}" exit 0 ''; restart-script = service-name: '' SYSCTL=${pkgs.systemd}/bin/systemctl JOBTYPE=$(${pkgs.systemd}/bin/systemctl show ${service-name} -p Type) if $SYSCTL is-active --quiet ${service-name} || [ $JOBTYPE == "Type=simple" ] || [ $JOBTYPE == "Type=oneshot" ] ; then echo "restarting service ${service-name} because password has changed." $SYSCTL restart ${service-name} fi ''; filterForRestarts = filterAttrs (name: opts: opts.restart-services != []); in { options.fudo.password = { file-generator = mkOption { type = with types; attrsOf (submodule genOpts); description = "List of password files to generate."; default = {}; }; }; config = { systemd.targets.fudo-passwords = { description = "Target indicating that all Fudo passwords have been generated."; wantedBy = [ "default.target" ]; }; systemd.services = fold (a: b: a // b) {} (mapAttrsToList (name: opts: { "file-generator-${name}" = { enable = true; partOf = [ "fudo-passwords.target" ]; serviceConfig.Type = "oneshot"; description = "Generate password file for ${name}."; script = "${generate-passwd-file opts.file opts.user opts.group}/bin/generate-passwd-file.sh"; reloadIfChanged = true; }; "file-generator-watcher-${name}" = mkIf (! (opts.restart-services == [])) { description = "Restart services upon regenerating password for ${name}"; after = [ "file-generator-${name}.service" ]; partOf = [ "fudo-passwords.target" ]; serviceConfig.Type = "oneshot"; script = concatStringsSep "\n" (map restart-script opts.restart-services); }; }) cfg.file-generator); systemd.paths = mapAttrs' (name: opts: nameValuePair "file-generator-watcher-${name}" { partOf = [ "fudo-passwords.target"]; pathConfig.PathChanged = opts.file; }) (filterForRestarts cfg.file-generator); }; }