From 2dece8300907ea2841bdafb2322d690265379de9 Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Tue, 6 Jan 2026 20:38:58 -0600 Subject: [PATCH] Introduce softDepend/hardDepend; add secret path units and timer --- flakes/secrets-bao/nixos-module.nix | 130 +++++++++++++++++++--------- hosts/juni/flake.nix | 14 +-- 2 files changed, 97 insertions(+), 47 deletions(-) diff --git a/flakes/secrets-bao/nixos-module.nix b/flakes/secrets-bao/nixos-module.nix index 1b03034b..acac7a8f 100644 --- a/flakes/secrets-bao/nixos-module.nix +++ b/flakes/secrets-bao/nixos-module.nix @@ -428,10 +428,16 @@ in description = "Field under .Data.data to render."; }; - dependencies = lib.mkOption { + softDepend = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; - description = "Systemd service names to restart after this secret is rendered."; + description = "Systemd service names to try-restart when this secret changes (does not block startup)."; + }; + + hardDepend = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Systemd service names that should only start when this secret exists; started when the secret changes."; }; configChanges = lib.mkOption { @@ -476,17 +482,62 @@ in sec ]; - systemd.tmpfiles.rules = [ - "d /run/openbao 0700 root root - -" - "f /run/openbao/zitadel.jwt 0400 root root - -" - "d /run/secrets 0711 root root - -" - ]; + systemd.tmpfiles.rules = [ + "d /run/openbao 0700 root root - -" + "f /run/openbao/zitadel.jwt 0400 root root - -" + "d /run/secrets 0711 root root - -" + ]; + + systemd.paths = lib.mapAttrs' ( + name: secret: + lib.nameValuePair "openbao-secret-${name}" { + description = "Path unit for OpenBao secret ${name}"; + wantedBy = [ "multi-user.target" ]; + + pathConfig = { + PathChanged = secret.path; + PathExists = secret.path; + Unit = "openbao-secret-changed-${name}.service"; + }; + } + ) cfg.secrets; + + systemd.services = lib.mkMerge [ + ( + lib.mkMerge ( + lib.concatLists ( + lib.mapAttrsToList ( + secretName: secret: + map ( + svc: + { + systemd.services.${svc} = { + unitConfig.ConditionPathExists = secret.path; + wants = lib.mkAfter [ "openbao-secret-${secretName}.path" ]; + after = lib.mkAfter [ "openbao-secret-${secretName}.path" ]; + }; + } + ) secret.hardDepend + ) cfg.secrets + ) + ) + ) + { + systemd.timers.zitadel-mint-jwt = { + description = "Refresh Zitadel JWT for OpenBao"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "30s"; + OnUnitActiveSec = "2m"; + Unit = "zitadel-mint-jwt.service"; + }; + }; + + + + zitadel-mint-jwt = { + description = "Mint Zitadel access token (JWT) for OpenBao"; - systemd.services = lib.mkMerge [ - { - zitadel-mint-jwt = { - description = "Mint Zitadel access token (JWT) for OpenBao"; - wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" "nss-lookup.target" @@ -590,17 +641,16 @@ in }; }; - vault-agent = { - description = "OpenBao agent for rendering secrets"; - wantedBy = [ "multi-user.target" ]; - after = [ - "network-online.target" - "zitadel-mint-jwt.service" - ]; - wants = [ - "network-online.target" - "zitadel-mint-jwt.service" - ]; + vault-agent = { + description = "OpenBao agent for rendering secrets"; + wantedBy = [ "multi-user.target" ]; + after = [ + "network-online.target" + ]; + wants = [ + "network-online.target" + "zitadel-mint-jwt.service" + ]; serviceConfig = { Type = "simple"; @@ -617,47 +667,47 @@ in (lib.mapAttrs' ( name: secret: - lib.nameValuePair "openbao-secret-${name}" { - description = "Wait for OpenBao secret ${name}"; + lib.nameValuePair "openbao-secret-changed-${name}" { + description = "React to OpenBao secret ${name} changes"; + wants = [ "vault-agent.service" ]; after = [ "vault-agent.service" ]; - requires = [ "vault-agent.service" ]; - wantedBy = map (svc: "${svc}.service") secret.dependencies; startLimitIntervalSec = 300; - startLimitBurst = 3; + startLimitBurst = 6; serviceConfig = { Type = "oneshot"; User = "root"; Group = "root"; UMask = "0077"; - ExecStart = pkgs.writeShellScript "openbao-wait-secret-${name}" '' + ExecStart = pkgs.writeShellScript "openbao-secret-changed-${name}" '' #!/usr/bin/env bash set -euo pipefail p=${lib.escapeShellArg secret.path} - for i in {1..60}; do - if [ -s "$p" ]; then - break - fi - sleep 1 - done - if [ ! -s "$p" ]; then - echo "Secret file not rendered: $p" >&2 - exit 1 + echo "Secret not present (skipping): $p" >&2 + exit 0 fi ${lib.concatStringsSep "\n" ( map (svc: '' - echo "Restarting ${svc} due to secret ${name}" >&2 + echo "Trying restart of ${svc} due to secret ${name}" >&2 systemctl try-restart ${lib.escapeShellArg (svc + ".service")} || true - '') secret.dependencies + '') secret.softDepend + )} + + ${lib.concatStringsSep "\n" ( + map (svc: '' + echo "Starting ${svc} due to secret ${name}" >&2 + systemctl start ${lib.escapeShellArg (svc + ".service")} || true + '') secret.hardDepend )} ''; }; } ) cfg.secrets) + ]; } ] diff --git a/hosts/juni/flake.nix b/hosts/juni/flake.nix index 9ec10aef..286c37fd 100644 --- a/hosts/juni/flake.nix +++ b/hosts/juni/flake.nix @@ -121,13 +121,14 @@ secrets = { headscale_auth = { kvPath = "kv/data/machines/home_roaming/headscale_auth"; - dependencies = [ "tailscaled" ]; + softDepend = [ "tailscaled" ]; configChanges.services.tailscale.authKeyFile = "$SECRET_PATH"; }; "atuin-key-josh" = { owner = "josh"; group = "users"; mode = "0400"; + hardDepend = [ "atuin-autologin" ]; template = ''{{- with secret "kv/data/machines/home_roaming/atuin-key-josh" -}}{{ printf "%s\n%s\n%s" .Data.data.user .Data.data.password .Data.data.value }}{{- end -}}''; }; nix2github = { @@ -305,9 +306,8 @@ systemd.services.atuin-autologin = { description = "Auto-login to Atuin (if logged out)"; wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "openbao-secret-atuin-key-josh.service" ]; - wants = [ "network-online.target" "openbao-secret-atuin-key-josh.service" ]; - requires = [ "openbao-secret-atuin-key-josh.service" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; serviceConfig = { Type = "oneshot"; @@ -337,9 +337,9 @@ exit 1 fi - username="$(${pkgs.coreutils}/bin/sed -n '1p' "$secret")" - password="$(${pkgs.coreutils}/bin/sed -n '2p' "$secret")" - key="$(${pkgs.coreutils}/bin/sed -n '3p' "$secret")" + username="$(${pkgs.gnused}/bin/sed -n '1p' "$secret")" + password="$(${pkgs.gnused}/bin/sed -n '2p' "$secret")" + key="$(${pkgs.gnused}/bin/sed -n '3p' "$secret")" exec ${pkgs.atuin}/bin/atuin login --username "$username" --password "$password" --key "$key" '';