This commit is contained in:
RingOfStorms (Joshua Bell) 2026-01-06 21:08:58 -06:00
commit fe7a1ac82d
3 changed files with 91 additions and 40 deletions

View file

@ -18,6 +18,27 @@
else else
value; value;
deepMerge = a: b:
if builtins.isAttrs a && builtins.isAttrs b then
builtins.foldl'
(acc: key:
let
newVal = builtins.getAttr key b;
mergedVal =
if builtins.hasAttr key acc then
deepMerge (builtins.getAttr key acc) newVal
else
newVal;
in
acc // (builtins.listToAttrs [ { name = key; value = mergedVal; } ])
)
a
(builtins.attrNames b)
else if builtins.isList a && builtins.isList b then
a ++ b
else
b;
fragments = builtins.attrValues (builtins.mapAttrs ( fragments = builtins.attrValues (builtins.mapAttrs (
name: s: name: s:
let let
@ -26,7 +47,7 @@
substitute secretPath (s.configChanges or { }) substitute secretPath (s.configChanges or { })
) secrets); ) secrets);
in in
builtins.foldl' (acc: v: acc // v) { } fragments; builtins.foldl' deepMerge { } fragments;
applyHmChanges = secrets: applyHmChanges = secrets:
let let
@ -40,6 +61,27 @@
else else
value; value;
deepMerge = a: b:
if builtins.isAttrs a && builtins.isAttrs b then
builtins.foldl'
(acc: key:
let
newVal = builtins.getAttr key b;
mergedVal =
if builtins.hasAttr key acc then
deepMerge (builtins.getAttr key acc) newVal
else
newVal;
in
acc // (builtins.listToAttrs [ { name = key; value = mergedVal; } ])
)
a
(builtins.attrNames b)
else if builtins.isList a && builtins.isList b then
a ++ b
else
b;
fragments = builtins.attrValues (builtins.mapAttrs ( fragments = builtins.attrValues (builtins.mapAttrs (
name: s: name: s:
let let
@ -48,7 +90,7 @@
substitute secretPath (s.hmChanges or { }) substitute secretPath (s.hmChanges or { })
) secrets); ) secrets);
merged = builtins.foldl' (acc: v: acc // v) { } fragments; merged = builtins.foldl' deepMerge { } fragments;
in in
if merged == { } then if merged == { } then
{ } { }

View file

@ -390,6 +390,12 @@ in
default = "/run/openbao/vault-agent.token"; default = "/run/openbao/vault-agent.token";
}; };
vaultAgentLogLevel = lib.mkOption {
type = lib.types.str;
default = "info";
description = "Log level for `bao agent` (debug is very noisy).";
};
secrets = lib.mkOption { secrets = lib.mkOption {
type = lib.types.attrsOf ( type = lib.types.attrsOf (
lib.types.submodule ( lib.types.submodule (
@ -502,42 +508,40 @@ in
} }
) cfg.secrets; ) cfg.secrets;
systemd.services = lib.mkMerge [ systemd.timers.zitadel-mint-jwt = {
( description = "Refresh Zitadel JWT for OpenBao";
lib.mkMerge ( wantedBy = [ "timers.target" ];
lib.concatLists ( timerConfig = {
lib.mapAttrsToList ( OnBootSec = "1min";
secretName: secret: OnUnitActiveSec = "10min";
map ( Unit = "zitadel-mint-jwt.service";
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";
};
};
systemd.services = lib.mkMerge [
(
lib.mkMerge (
lib.concatLists (
lib.mapAttrsToList (
secretName: secret:
map (
svc: {
${svc} = {
unitConfig.ConditionPathExists = secret.path;
wants = lib.mkAfter [ "openbao-secret-${secretName}.path" ];
after = lib.mkAfter [ "openbao-secret-${secretName}.path" ];
};
}
) secret.hardDepend
) cfg.secrets
)
)
)
{
zitadel-mint-jwt = {
description = "Mint Zitadel access token (JWT) for OpenBao";
zitadel-mint-jwt = {
description = "Mint Zitadel access token (JWT) for OpenBao";
after = [ after = [
"network-online.target" "network-online.target"
"nss-lookup.target" "nss-lookup.target"
@ -634,7 +638,12 @@ in
trap '${pkgs.coreutils}/bin/rm -f "$tmp"' EXIT trap '${pkgs.coreutils}/bin/rm -f "$tmp"' EXIT
${pkgs.coreutils}/bin/printf '%s' "$jwt" > "$tmp" ${pkgs.coreutils}/bin/printf '%s' "$jwt" > "$tmp"
# In-place update so the agent's file watcher sees changes. if [ -s "${cfg.zitadelJwtPath}" ] && ${pkgs.coreutils}/bin/cmp -s "$tmp" "${cfg.zitadelJwtPath}"; then
echo "zitadel-mint-jwt: token unchanged; skipping" >&2
exit 0
fi
# Update the token file (the agent watches it).
${pkgs.coreutils}/bin/cat "$tmp" > "${cfg.zitadelJwtPath}" ${pkgs.coreutils}/bin/cat "$tmp" > "${cfg.zitadelJwtPath}"
${pkgs.coreutils}/bin/chmod 0400 "${cfg.zitadelJwtPath}" || true ${pkgs.coreutils}/bin/chmod 0400 "${cfg.zitadelJwtPath}" || true
''; '';
@ -660,7 +669,7 @@ in
RestartSec = "10s"; RestartSec = "10s";
TimeoutStartSec = "30s"; TimeoutStartSec = "30s";
UMask = "0077"; UMask = "0077";
ExecStart = "${pkgs.openbao}/bin/bao agent -log-level=debug -config=${mkAgentConfig}"; ExecStart = "${pkgs.openbao}/bin/bao agent -log-level=${lib.escapeShellArg cfg.vaultAgentLogLevel} -config=${mkAgentConfig}";
}; };
}; };
} }
@ -693,14 +702,14 @@ in
${lib.concatStringsSep "\n" ( ${lib.concatStringsSep "\n" (
map (svc: '' map (svc: ''
echo "Trying restart of ${svc} due to secret ${name}" >&2 echo "Trying restart of ${svc} due to secret ${name}" >&2
systemctl try-restart ${lib.escapeShellArg (svc + ".service")} || true systemctl try-restart --no-block ${lib.escapeShellArg (svc + ".service")} || true
'') secret.softDepend '') secret.softDepend
)} )}
${lib.concatStringsSep "\n" ( ${lib.concatStringsSep "\n" (
map (svc: '' map (svc: ''
echo "Starting ${svc} due to secret ${name}" >&2 echo "Starting ${svc} due to secret ${name}" >&2
systemctl start ${lib.escapeShellArg (svc + ".service")} || true systemctl start --no-block ${lib.escapeShellArg (svc + ".service")} || true
'') secret.hardDepend '') secret.hardDepend
)} )}
''; '';

View file

@ -139,7 +139,7 @@
nix2bitbucket = { nix2bitbucket = {
owner = "josh"; owner = "josh";
group = "users"; group = "users";
hmChanges.programs.ssh.matchBlocks."bitbucket.com".identityFile = "$SECRET_PATH"; hmChanges.programs.ssh.matchBlocks."bitbucket.org".identityFile = "$SECRET_PATH";
}; };
nix2gitforgejo = { nix2gitforgejo = {
owner = "josh"; owner = "josh";