Watch
0
0
Fork
You've already forked hyperhive
0

grafana: create the secrets directory before the store login

The three delivery units made /run/swarm-grafana-secrets only after
`bao login` and `bao kv get`, so with the store sealed or unreachable the
bind source was never created by them and a switch could restart the
container without it. Each script now starts with the install, from one
shared `ensureSecretDir`, and the tmpfiles comment says what is true.

The module-eval case asserts the install precedes `bao login` in all three
scripts. docs/swarm/sso.md states that after a reboot Grafana stays down
until the secret store answers.

Part of #4998 (slice 2b: grafana).
This commit is contained in:
atlas 2026-10-15 23:10:31 +02:00 • committed by mara
commit 6b7fd56f06
3 changed files with 30 additions and 7 deletions

View file

@ -299,6 +299,12 @@ let
atomicWriteSecret = import ./lib/atomic-write-secret.nix { };
refreshConsumer = import ./lib/refresh-consumer.nix { };
# First statement of each delivery script, ahead of the store login: the
# directory is the container's bind source, so it has to exist even when the
# store does not answer. tmpfiles creates it too, but unordered with the
# container on a switch.
ensureSecretDir = "install -d -m 0755 ${lib.escapeShellArg secretDir}";
# Shared host netns, like every sibling swarm container: the gateway
# reaches this at 127.0.0.1:<port>.
privateNetwork = false;
@ -554,10 +560,11 @@ in
#
# The secrets directory is the container's read-only bind source, so it
# has to exist before the container starts even when the store does not
# answer; the delivery units create it too, but unordered with the
# container on a switch. 0755 because Grafana reads the files as its own
# uid; each file is 0400 and owned by it. The legacy files are removed so
# no superseded secret stays behind on the host's disk.
# answer. The delivery units create it before their store login too
# (`ensureSecretDir`), which covers a switch, where this rule is unordered
# with the container restart. 0755 because Grafana reads the files as its
# own uid; each file is 0400 and owned by it. The legacy files are removed
# so no superseded secret stays behind on the host's disk.
systemd.tmpfiles.rules = [
"d ${deployCfg.grafana.socketDir} 0750 ${toString grafanaUid} ${toString nginxGid} - -"
"d ${secretDir} 0755 root root -"
@ -638,6 +645,8 @@ in
${atomicWriteSecret}
${refreshConsumer}
${ensureSecretDir}
# `bao`'s own message is the only thing separating a missing value from
# a refused identity from an unreachable host. This unit's degraded
# mode is correct for all three, so it reports which one rather than
@ -693,7 +702,6 @@ in
# the host cannot know it at eval time. Harmless here because 0400
# grants the group nothing; if this mode ever widens, the gid has to be
# discovered at runtime rather than assumed.
install -d -m 0755 ${lib.escapeShellArg secretDir}
if secret_differs ${lib.escapeShellArg secretPath} "$secret"; then
atomic_write_secret 0400 ${lib.escapeShellArg "${toString config.ids.uids.grafana}:0"} ${lib.escapeShellArg secretPath} "$secret"
fi
@ -750,6 +758,8 @@ in
${atomicWriteSecret}
${refreshConsumer}
${ensureSecretDir}
err="$(mktemp)"
trap 'rm -f "$err"' EXIT
@ -781,7 +791,6 @@ in
fi
# Owner and mode as for the OIDC secret above, for its reasons.
install -d -m 0755 ${lib.escapeShellArg secretDir}
if secret_differs ${lib.escapeShellArg adminPasswordPath} "$password"; then
atomic_write_secret 0400 ${lib.escapeShellArg "${toString config.ids.uids.grafana}:0"} ${lib.escapeShellArg adminPasswordPath} "$password"
fi
@ -832,6 +841,8 @@ in
${atomicWriteSecret}
${refreshConsumer}
${ensureSecretDir}
err="$(mktemp)"
trap 'rm -f "$err"' EXIT
@ -862,7 +873,6 @@ in
fi
# Owner and mode as for the OIDC secret above, for its reasons.
install -d -m 0755 ${lib.escapeShellArg secretDir}
if secret_differs ${lib.escapeShellArg metricsBearerPath} "Bearer $bearer"; then
atomic_write_secret 0400 ${lib.escapeShellArg "${toString config.ids.uids.grafana}:0"} ${lib.escapeShellArg metricsBearerPath} "Bearer $bearer"
fi