Skip to content

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.