Problem
Packs routinely need non-sensitive Keycloak values - the realm, the internal and external server URLs, the internal and external issuer URLs - to wire up their own OIDC flows (server-to-server token validation, browser redirects, OIDC discovery). Today each pack hardcodes or re-derives these itself. That is duplicated effort and a drift risk: when the realm name or Keycloak service address changes, every pack that baked in a value breaks, while the operator's own config stays correct.
The operator is already the source of truth for all of these values. It holds the realm and the internal/external base URLs as config, and it computes both issuer URLs per provider (GetIssuerURL internal, GetExternalIssuerURL external). It should hand them to packs instead of making each pack rediscover them.
Approach
Inject the non-sensitive Keycloak values as standard env vars into NebariApp-managed workloads, using the generic pod-spec injection mechanism from #146. This is the second consumer of that seam (OTel is the first), which is what makes the "self-service config injection" framing real rather than per-feature.
Proposed env vars (names to be finalized in design):
KEYCLOAK_REALM -> realm name
KEYCLOAK_INTERNAL_URL -> in-cluster base URL
KEYCLOAK_EXTERNAL_URL -> publicly routable base URL
KEYCLOAK_INTERNAL_ISSUER_URL -> in-cluster issuer (GetIssuerURL)
KEYCLOAK_EXTERNAL_ISSUER_URL -> external issuer (GetExternalIssuerURL)
A pack reads these from its environment and is done - no per-pack wiring, no hardcoded URLs.
Out of scope: the OIDC client-secret. It is sensitive, stays in the per-app Secret, and is consumed by Envoy Gateway via the SecurityPolicy - it is never injected as an env var. The non-secret client IDs (spa-client-id, device-client-id, issuer-url) already live in that Secret and already have a delivery path, so they are not part of this issue.
Scope
Definition of Done
Dependencies
Problem
Packs routinely need non-sensitive Keycloak values - the realm, the internal and external server URLs, the internal and external issuer URLs - to wire up their own OIDC flows (server-to-server token validation, browser redirects, OIDC discovery). Today each pack hardcodes or re-derives these itself. That is duplicated effort and a drift risk: when the realm name or Keycloak service address changes, every pack that baked in a value breaks, while the operator's own config stays correct.
The operator is already the source of truth for all of these values. It holds the realm and the internal/external base URLs as config, and it computes both issuer URLs per provider (
GetIssuerURLinternal,GetExternalIssuerURLexternal). It should hand them to packs instead of making each pack rediscover them.Approach
Inject the non-sensitive Keycloak values as standard env vars into NebariApp-managed workloads, using the generic pod-spec injection mechanism from #146. This is the second consumer of that seam (OTel is the first), which is what makes the "self-service config injection" framing real rather than per-feature.
Proposed env vars (names to be finalized in design):
A pack reads these from its environment and is done - no per-pack wiring, no hardcoded URLs.
Out of scope: the OIDC
client-secret. It is sensitive, stays in the per-app Secret, and is consumed by Envoy Gateway via the SecurityPolicy - it is never injected as an env var. The non-secret client IDs (spa-client-id,device-client-id,issuer-url) already live in that Secret and already have a delivery path, so they are not part of this issue.Scope
Definition of Done
Dependencies