feat(keycloak): render the client-URL desired state from the realm import
The realm import is a one-shot: once Done=True it never re-runs, so a redirect URI
changed in git never reaches the realm. Healing that needs a DESIRED STATE the
reconciler can read -- and the reconciler pod has no Kubernetes API access at all
(automountServiceAccountToken: false), so it cannot read the KeycloakRealmImport CR.
Its desired state must be mounted, hence a ConfigMap.
A hand-authored ConfigMap would be a second source of truth for every public
hostname in the realm, free to disagree with the import -- the same shape as the bug
being closed. So it is GENERATED from the import and the render is gated, the same
render==golden idiom catalog/render.py already uses for apps/.
URL strings are copied VERBATIM: a ${BASE_DOMAIN} token in the source appears
unchanged here, and both files are rendered by the SAME Flux Kustomization
(./platform-config), so both are substituted in one pass with one value. The
renderer never parses a hostname and never reads cluster-vars, so there is no
second place the domain can be decided.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
fa4deac877
commit
51d8676f90
3 files changed
+382
No files matched your search
@@ -0,0 +1,157 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# GENERATED FILE — DO NOT EDIT BY HAND.
|
||||
#
|
||||
# source: platform/keycloak/keycloak-realm-import.yaml (spec.realm.clients)
|
||||
# regenerate: python3 ci/render-keycloak-client-urls.py --write
|
||||
# gated by: conformance/tests/l0-static/keycloak-client-secret-reconciler
|
||||
# (runs this renderer with --check on every merge)
|
||||
#
|
||||
# WHAT THIS IS: the DESIRED STATE for every environment-derived client URL in the
|
||||
# `homelab` realm — redirectUris, webOrigins, rootUrl, baseUrl, adminUrl. The
|
||||
# client-secret reconciler CronJob mounts it and makes the live realm match it.
|
||||
#
|
||||
# WHY IT IS A SEPARATE OBJECT: the realm import is a ONE-SHOT that never re-runs
|
||||
# once Done=True, so a redirect URI edited in git never reaches the realm. Prod's
|
||||
# stored redirect URIs were measured still pointing at the pre-migration hostname
|
||||
# while git declared the new one, and every OIDC login would have failed with a
|
||||
# redirect_uri mismatch. The reconciler is the level-triggered loop that closes
|
||||
# that; this file is what it reconciles TOWARDS.
|
||||
#
|
||||
# WHY IT IS GENERATED AND NOT AUTHORED: a hand-written copy of every public
|
||||
# hostname would be a second source of truth, free to disagree with the realm
|
||||
# import. It is rendered from the import and the render is gated, so the two
|
||||
# cannot drift. URL strings are copied VERBATIM — if the source uses a
|
||||
# ${BASE_DOMAIN} token it appears here unchanged, and both files are substituted
|
||||
# by the SAME Flux Kustomization (./platform-config), so the domain is decided in
|
||||
# exactly one place.
|
||||
#
|
||||
# A field that is NOT declared on a client in the realm import is simply ABSENT
|
||||
# here, and the reconciler leaves it alone. Absence means UNMANAGED, never
|
||||
# "force to empty".
|
||||
# =============================================================================
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: keycloak-client-urls
|
||||
namespace: keycloak
|
||||
labels:
|
||||
app.kubernetes.io/name: keycloak-client-urls
|
||||
app.kubernetes.io/part-of: keycloak
|
||||
data:
|
||||
client-urls.json: |
|
||||
{
|
||||
"crafty": {
|
||||
"redirectUris": [
|
||||
"https://crafty.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://crafty.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"gitea": {
|
||||
"redirectUris": [
|
||||
"https://gitea.${BASE_DOMAIN}/user/oauth2/keycloak/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://gitea.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"grafana": {
|
||||
"redirectUris": [
|
||||
"https://grafana.${BASE_DOMAIN}/login/generic_oauth"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://grafana.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"headlamp": {
|
||||
"redirectUris": [
|
||||
"https://headlamp.${BASE_DOMAIN}/oidc-callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://headlamp.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"jackett": {
|
||||
"redirectUris": [
|
||||
"https://jackett.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://jackett.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"kubernetes": {
|
||||
"redirectUris": [
|
||||
"http://localhost:8000",
|
||||
"http://localhost:8000/",
|
||||
"http://localhost:18000",
|
||||
"http://localhost:18000/",
|
||||
"http://127.0.0.1:8000",
|
||||
"http://127.0.0.1:8000/",
|
||||
"http://127.0.0.1:18000",
|
||||
"http://127.0.0.1:18000/"
|
||||
],
|
||||
"webOrigins": [
|
||||
"http://localhost",
|
||||
"http://127.0.0.1"
|
||||
]
|
||||
},
|
||||
"nextcloud": {
|
||||
"redirectUris": [
|
||||
"https://nextcloud.${BASE_DOMAIN}/apps/user_oidc/code"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://nextcloud.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"oauth2-proxy": {
|
||||
"redirectUris": [
|
||||
"https://*.${BASE_DOMAIN}/oauth2/callback",
|
||||
"https://auth.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://*.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"pihole": {
|
||||
"redirectUris": [
|
||||
"https://pihole.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://pihole.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"qbittorrent": {
|
||||
"redirectUris": [
|
||||
"https://qbittorrent.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://qbittorrent.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"radarr": {
|
||||
"redirectUris": [
|
||||
"https://radarr.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://radarr.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"semaphore": {
|
||||
"redirectUris": [
|
||||
"https://semaphore.${BASE_DOMAIN}/api/auth/oidc/keycloak/redirect"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://semaphore.${BASE_DOMAIN}"
|
||||
]
|
||||
},
|
||||
"sonarr": {
|
||||
"redirectUris": [
|
||||
"https://sonarr.${BASE_DOMAIN}/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"https://sonarr.${BASE_DOMAIN}"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user