# SPDX-FileCopyrightText: 2022 Luke Granger-Brown # # SPDX-License-Identifier: Apache-2.0 { depot, pkgs, config, lib, ... }: let inherit (lib) mkIf mkOption types concatStringsSep unique optional mkAfter; pkg = depot.go.secretsmgr; cfg = config.my.vault.secretsmgr; jsonFormat = pkgs.formats.json { }; dummyHostKey = pkgs.runCommandLocal "dummy-host-key" { nativeBuildInputs = [ config.programs.ssh.package ]; } '' ssh-keygen -q -f $out -N "" ''; in { options.my.vault.secretsmgr = { enable = mkOption { type = types.bool; default = config.my.vault.enable; }; groups = mkOption { type = with types; listOf str; default = []; }; restartableUnits = mkOption { type = with types; listOf str; default = []; }; acmeCertificates.enable = mkOption { type = types.bool; default = true; }; acmeCertificates.expiryThreshold = mkOption { type = types.str; default = "744h"; }; acmeCertificates.config = mkOption { type = jsonFormat.type; default = {}; }; acmeCertificates.mount = mkOption { type = types.str; default = "acme"; }; sshCertificates.enable = mkOption { type = types.bool; default = true; }; sshCertificates.mount = mkOption { type = types.str; default = "ssh-host"; }; sshCertificates.expiryThreshold = mkOption { type = types.str; default = "72h"; }; sshCertificates.outputDir = mkOption { type = types.str; default = "/var/lib/secretsmgr/ssh"; }; sshCertificates.principals = mkOption { type = with types; listOf str; default = let inherit (config.networking) hostName; in [ "${hostName}" "${hostName}.as205479.net" "${hostName}.int.as205479.net" "${hostName}.otter-acoustic.ts.net" ]; }; sshCertificates.role = mkOption { type = types.str; default = config.networking.hostName; }; }; config = mkIf cfg.enable { my.vault.secretsmgr.restartableUnits = mkIf cfg.sshCertificates.enable (mkAfter ["sshd.service"]); users.groups.secretsmgr = {}; users.users.secretsmgr = { isSystemUser = true; group = "secretsmgr"; }; systemd.services.secretsmgr = { requires = ["vault-agent.service"]; after = ["vault-agent.service"]; restartIfChanged = true; serviceConfig = { User = "secretsmgr"; Group = "secretsmgr"; SupplementaryGroups = cfg.groups ++ [ "vault-agent" ]; AmbientCapabilities = [ "CAP_SETGID" ]; Type = "oneshot"; ExecStart = concatStringsSep " " ([ "${pkg}/bin/secretsmgr" "--logtostderr" ] ++ lib.optionals cfg.acmeCertificates.enable [ "--acme_certificates_config=${jsonFormat.generate "secretsmgr-acme-certificates-config.json" cfg.acmeCertificates.config}" "--acme_certificates_expiry_threshold=${cfg.acmeCertificates.expiryThreshold}" "--acme_certificates_mount=${cfg.acmeCertificates.mount}" ] ++ [ "--sign_ssh_host_keys=${toString cfg.sshCertificates.enable}" ] ++ lib.optionals cfg.sshCertificates.enable [ "--ssh_host_key_ca_path=${cfg.sshCertificates.mount}" "--ssh_host_key_expiry_threshold=${cfg.sshCertificates.expiryThreshold}" "--ssh_host_key_output_dir=${cfg.sshCertificates.outputDir}" "--ssh_host_key_principals=${concatStringsSep "," cfg.sshCertificates.principals}" "--ssh_host_key_role=${cfg.sshCertificates.role}" "--ssh_dummy_host_key=${dummyHostKey}" "--sshd=${config.programs.ssh.package}/bin/sshd" ]); }; }; systemd.timers.secretsmgr = { requires = ["vault-agent.service"]; wants = ["network-online.target"]; after = ["vault-agent.service" "network-online.target"]; wantedBy = ["timers.target"]; timerConfig = { OnActiveSec = "30"; OnUnitInactiveSec = "30min"; }; }; systemd.tmpfiles.rules = [ "d /var/lib/acme 0711 secretsmgr secretsmgr - -" "d /var/lib/secretsmgr 0711 secretsmgr secretsmgr - -" "d /var/lib/secretsmgr/ssh 0711 secretsmgr secretsmgr - -" ]; security.polkit.extraConfig = lib.mkAfter '' // NixOS module: depot/lib/secretsmgr.nix polkit.addRule(function(action, subject) { if (action.id !== "org.freedesktop.systemd1.manage-units" || subject.user !== "secretsmgr") { return polkit.Result.NOT_HANDLED; } var verb = action.lookup("verb"); if (verb !== "restart" && verb !== "reload-or-restart" && verb != "reload-or-try-restart") { return polkit.Result.NOT_HANDLED; } var allowedUnits = ${builtins.toJSON (unique cfg.restartableUnits)}; 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; }); ''; }; }