Grafana's two secrets, and where they live¶
grafana-auth carries admin-user and admin-password. It is a SealedSecret
next to the chart that consumes it. Grafana reads it as its admin login, and
terraform/60_grafana-config reads it back out of the cluster at apply time,
which also leaves a copy in that root's encrypted state.
grafana-oidc carries client_id and client_secret for the authentik client.
It is not sealed — terraform/50_authentik-config mints the client, writes the
credentials to OpenBao at authentik/observability/grafana, and an
ExternalSecret pulls them into the namespace. That is the right split: the
admin password is chosen by an operator, while the OIDC secret is generated by
the system that owns the client, so nobody has to see it.
grafana.ini reads the OIDC credentials from /etc/secrets/oidc with
$__file{}. The admin login comes straight from grafana-auth through the
chart's admin.existingSecret, so that Secret is not mounted.
Sealing is offline — the pinned key pair lives in secrets/sealed-secrets.yaml,
so no cluster access is needed to produce the ciphertext:
sops -d --extract '["tls_crt"]' secrets/sealed-secrets.yaml > /tmp/sealing.crt
kubeseal --cert /tmp/sealing.crt --format yaml < /tmp/grafana-auth.yaml \
> flux/50_apps/observability/grafana/auth-sealed-secret.yaml
Write the plaintext input under /tmp, never in the working tree.
Rotating the admin password is one resealed file. The tofu root picks the new value up on its next apply.