# SPDX-FileCopyrightText: 2020 Luke Granger-Brown # # SPDX-License-Identifier: Apache-2.0 { pkgs, config, depot, lib, ... }: let inherit (lib) mkOption types mkBefore optionalAttrs mkDefault mapAttrs; secrets = lib.mapAttrsToList (name: cOrig: cOrig // { inherit name; }) config.my.vault.secrets; secretsGroups = lib.unique (map (c: c.group) secrets); secretsRoot = "/var/lib/secrets"; secretsTemplate = map (c: { contents = c.template; destination = c.path; perms = "0640"; command = let in pkgs.writeShellScript "post-secret-${c.name}" '' chgrp "${c.group}" "${c.path}" ${lib.concatMapStringsSep "\n" (x: '' /run/current-system/sw/bin/systemctl reload-or-restart ${x} '') c.reloadOrRestartUnits} ${lib.concatMapStringsSep "\n" (x: '' /run/current-system/sw/bin/systemctl restart ${x} '') c.restartUnits} ${lib.optionalString (c.command != "") c.command} ''; }) secrets; secretsTmpdirs = [ "d ${secretsRoot} 0111 vault-agent vault-agent - -" ] ++ map (c: "d ${c.parentDir} 0750 vault-agent ${c.group} - -") secrets; allRestartableUnits = lib.unique (builtins.concatMap (c: c.reloadOrRestartUnits ++ c.restartUnits) secrets); in { imports = [ ./vault-agent.nix ]; options.my.vault.secrets = mkOption { type = with types; attrsOf (submodule ({ name, config, ...}: { options = { name = mkOption { type = str; default = name; readOnly = true; }; parentDir = mkOption { type = path; default = "${secretsRoot}/${config.name}"; readOnly = true; }; path = mkOption { type = path; default = "${config.parentDir}/secret"; readOnly = true; }; template = mkOption { type = lines; description = "Template to use for generating secret output."; }; command = mkOption { type = lines; default = ""; description = "Command to run after writing the secrets file."; }; reloadOrRestartUnits = mkOption { type = listOf str; default = []; description = "List of systemd units to reload/restart after writing the secrets file."; }; restartUnits = mkOption { type = listOf str; default = []; description = "List of systemd units to restart after writing the secrets file."; }; group = mkOption { type = str; description = "Owner group to set for the generated file."; }; }; })); default = {}; }; config = { my.vault.settings = { template = mkBefore secretsTemplate; }; systemd = optionalAttrs config.my.vault.enable { services.vault-agent = { serviceConfig = { SupplementaryGroups = mkBefore secretsGroups; }; unitConfig = { Before = mkBefore allRestartableUnits; }; wantedBy = mkBefore allRestartableUnits; }; tmpfiles.rules = secretsTmpdirs; }; security.polkit.extraConfig = lib.mkAfter '' // NixOS module: depot/lib/vault-agent-secrets.nix polkit.addRule(function(action, subject) { if (action.id !== "org.freedesktop.systemd1.manage-units" || subject.user !== "vault-agent") { return polkit.Result.NOT_HANDLED; } var verb = action.lookup("verb"); if (verb !== "restart" && verb !== "reload-or-restart") { return polkit.Result.NOT_HANDLED; } var allowedUnits = ${builtins.toJSON allRestartableUnits}; var unit = action.lookup("unit"); for (var i = 0; i < allowedUnits.length; i++) { if (allowedUnits[i] === unit) { return polkit.Result.YES; } } return polkit.Result.NOT_HANDLED; }); ''; }; }