Watch
0
0
Fork
You've already forked hyperhive
0

grafana: fix the sso.md admin claim, deny the publisher the admin password

docs/swarm/sso.md still said Grafana ships admin/admin and that a dead
provider locks out the built-in admin. The password is minted into the
store and the API still takes basic auth for it, so the paragraph now says
where an operator reads it in an emergency. secrets.md says how to rotate
the password and to deploy the store's host first, and no longer calls SSO
the only way in.

The secret publisher's `services/*` write covered the admin-password
leaf, so a file-copier could set the password Grafana applies at its next
start. The leaf gets the same exact-path deny as the callout seeds, with
an arm in module-eval-bao-grants.
This commit is contained in:
atlas 2026-10-12 12:16:08 +02:00 • committed by mara
commit eecd2b62e8
4 changed files with 71 additions and 30 deletions

View file

@ -482,6 +482,9 @@ let
# prefix, are denied. A write to the xkey's would replace the key every
# queue request is sealed to; the issuer's is the authority to admit anyone
# to the queue, and the user's is the one identity exempt from callout.
# Grafana's admin password is denied the same way: a write to it sets the
# password `grafana.service` applies to the server-admin account at its next
# start.
secretPublisherPolicyText = ''
path "${credentialMountPath}/data/swarm/hives/*" {
capabilities = ["create", "update"]
@ -503,6 +506,10 @@ let
capabilities = ["deny"]
}
path "${credentialMountPath}/data/${grafanaAdminLeaf}" {
capabilities = ["deny"]
}
path "${credentialMountPath}/data/${controllerClientLeaf}" {
capabilities = ["create", "update"]
}
@ -860,7 +867,7 @@ let
cn = baoDeploy.grafanaOidcCommonName;
policyText =
readStanza "${credentialMountPath}/data/swarm/services/${hyperhiveCfg.swarm.grafana.oidc.clientId}/oidc/client"
+ createStanza "${credentialMountPath}/data/swarm/services/${hyperhiveCfg.swarm.grafana.oidc.clientId}/admin/password";
+ createStanza "${credentialMountPath}/data/${grafanaAdminLeaf}";
}
];
@ -922,6 +929,10 @@ let
userSeedLeaf = "swarm/services/swarm-nats/callout/user-seed";
userPublicLeaf = "swarm/public/swarm-nats/callout-user";
# Grafana's admin password, which only Grafana's leaf creates. The nix half
# of `adminPasswordStorePath` in ./swarm-grafana.nix.
grafanaAdminLeaf = "swarm/services/${hyperhiveCfg.swarm.grafana.oidc.clientId}/admin/password";
createStanza = path: ''
path "${path}" {
capabilities = ["create", "read"]

View file

@ -462,6 +462,23 @@ let
"update"
];
}
{
# Grafana's admin password sits under the publisher's `services/*` write
# too, and a planted value is the password the next Grafana start applies
# to the server-admin account. The OIDC leaf beside it is the control:
# still the prefix's.
name = "the publisher may not write Grafana's admin password";
ok =
let
grants = grantsIn baoGrantHere.systemd.services.swarm-bao-secret-publisher-policy.script;
in
(grantFor grants "secret/data/swarm/services/swarm-grafana/admin/password").caps == [ "deny" ]
&&
(grantFor grants "secret/data/swarm/services/swarm-grafana/oidc/client").caps == [
"create"
"update"
];
}
{
# The ordering is load-bearing and invisible at runtime: the controller's
# unit creates the KV and cert-auth mounts this one writes into, so