From 67688c2aa652728c6d74dfa91d83064d72378133 Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sun, 15 Mar 2026 21:12:03 -0500 Subject: [PATCH] added mtls renewal service --- modules/services/step-ca/mtls.nix | 89 ++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/modules/services/step-ca/mtls.nix b/modules/services/step-ca/mtls.nix index 0323e21..9fb5ee6 100644 --- a/modules/services/step-ca/mtls.nix +++ b/modules/services/step-ca/mtls.nix @@ -9,6 +9,12 @@ mtlsBundle = "${certDir}/${cfg.bundleFilename}"; rootCA = "${cfg.certDir}/certs/root_ca.crt"; sanArgs = lib.concatMapStringsSep " " (san: "--san \"${san}\"") cfg.san; + renewReloadScript = lib.concatMapStringsSep "\n" (unit: '' + if ${lib.getExe' pkgs.systemd "systemctl"} --quiet is-active "${unit}"; then + ${lib.getExe' pkgs.systemd "systemctl"} try-reload-or-restart "${unit}" + fi + '') cfg.renew.reloadUnits; + renewPostCommands = lib.concatStringsSep "\n" cfg.renew.postCommands; in { options.mtls = { @@ -50,9 +56,36 @@ type = lib.types.str; default = "admin"; }; + renew = { + enable = lib.mkOption { + description = "Enable automatic mTLS certificate renewal using a systemd timer."; + type = lib.types.bool; + default = true; + }; + onCalendar = lib.mkOption { + description = "systemd OnCalendar schedule for mTLS certificate renewal checks."; + type = lib.types.str; + default = "*:1/15"; + }; + randomizedDelaySec = lib.mkOption { + description = "Randomized delay added to renewal timer runs to avoid synchronized renewals."; + type = lib.types.str; + default = "5m"; + }; + reloadUnits = lib.mkOption { + description = "systemd units to try-reload-or-restart after a successful certificate renewal."; + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + postCommands = lib.mkOption { + description = "Shell commands to run after a successful certificate renewal."; + type = lib.types.listOf lib.types.lines; + default = [ ]; + }; + }; }; - config = { + config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; lib.optionals cfg.enable [ (writeShellScriptBin "mtls-generate" '' set -euo pipefail @@ -71,6 +104,60 @@ -enddate -in ${mtlsBundle} '') ]; + + systemd.services.mtls-renew = lib.mkIf cfg.renew.enable { + description = "Renew the mTLS certificate when Smallstep marks it ready"; + wantedBy = [ ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + path = [ pkgs.coreutils pkgs.step-cli pkgs.systemd ]; + serviceConfig = { + Type = "oneshot"; + User = "root"; + Group = "root"; + }; + script = '' + set -euo pipefail + + if ${lib.getExe pkgs.step-cli} certificate needs-renewal "${tlsCert}"; then + echo "Renewing mTLS certificate" + else + rc=$? + if [ "$rc" -eq 1 ]; then + echo "mTLS certificate does not need renewal" + exit 0 + fi + + if [ "$rc" -eq 2 ]; then + echo "mTLS certificate missing: ${tlsCert}" >&2 + exit 1 + fi + + echo "step certificate needs-renewal failed with rc=$rc" >&2 + exit "$rc" + fi + + ${lib.getExe pkgs.step-cli} ca renew --force "${tlsCert}" "${tlsKey}" + + umask 077 + cat "${tlsCert}" "${tlsKey}" > "${mtlsBundle}" + + ${renewReloadScript} + ${renewPostCommands} + ''; + }; + + systemd.timers.mtls-renew = lib.mkIf cfg.renew.enable { + description = "Periodic Smallstep renewal for the mTLS certificate"; + wantedBy = [ "timers.target" ]; + timerConfig = { + Persistent = true; + OnCalendar = cfg.renew.onCalendar; + AccuracySec = "1us"; + RandomizedDelaySec = cfg.renew.randomizedDelaySec; + Unit = "mtls-renew.service"; + }; + }; }; }; } \ No newline at end of file