Import the realm on every start, so the file is the source of truth

configmap-realm.yaml was a first-install seed: `start --import-realm`
skips a realm that already exists and logs "Import skipped", so editing
the file changed nothing on a restart and the truth drifted into the
database. It already had — four scope grants existed only in the running
realm.

There is no option to make the startup import overwrite. The --override
flag exists only on the standalone `import` command, and the Keycloak
documentation is explicit that re-creating realms means running that
command before starting the server. So the import moves into an init
container that runs `import --dir ... --override true`, and --import-realm
comes off the main container's args.

The init container empties JAVA_OPTS_APPEND for itself. It inherits the
main container's env, which loads the OpenTelemetry agent from a volume
the other init container downloads into and this one does not mount;
inherited verbatim, the JVM fails before the import runs.

What this costs, deliberately: the realm is replaced at every start, so
anything created at runtime and not written back to this file is lost, and
active sessions are dropped. Checked before enabling it — the five users
in the realm are the five declared here, and the only live sessions were
two LibreChat ones. Nothing is to be created through the admin console
expecting it to last.

Verified after the switch: the import logs "Strategy: OVERWRITE_EXISTING",
the realm still has its 21 clients with no optionalClientScopes
divergence, and the full identity chain still returns 200 — pm-user token,
exchanged by the Catalogue agent, accepted by catalog-mcp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Stéphane Tailland
2026-08-28 09:37:35 +02:00
parent 1b613768e7
commit a97399c2bf
+114 -1
View File
@@ -28,6 +28,120 @@ spec:
prometheus.io/path: "/metrics"
spec:
initContainers:
# Re-imports the realm from configmap-realm.yaml on every start, so that
# file is the source of truth rather than a first-install seed.
#
# It has to be a separate command: `start --import-realm` skips a realm
# that already exists and there is no option to change that — the
# --override flag exists only on the standalone `import` command. With
# the default behaviour, editing the ConfigMap changed nothing on a
# restart and the truth drifted into the database. It already had: four
# scope grants existed only in the running realm.
#
# What this costs, deliberately: the realm is replaced at every start,
# so anything created at runtime and not written back to the file is
# lost, and active sessions are dropped. Users survive only because they
# are declared in the file. Create nothing through the admin console
# expecting it to last.
- name: import-realm
image: quay.io/keycloak/keycloak:26.6.0
args:
- "import"
- "--dir"
- "/opt/keycloak/data/import"
- "--override"
- "true"
env:
- name: KC_DB
value: "postgres"
- name: KC_DB_URL_HOST
value: "keycloak-postgresql"
- name: KC_DB_URL_PORT
value: "5432"
- name: KC_DB_URL_DATABASE
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: POSTGRES_DB
- name: KC_DB_USERNAME
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KC_DB_USERNAME
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KC_DB_PASSWORD
- name: KC_BOOTSTRAP_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KC_BOOTSTRAP_ADMIN_USERNAME
- name: KC_BOOTSTRAP_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KC_BOOTSTRAP_ADMIN_PASSWORD
- name: KEYCLOAK_ADMIN
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KEYCLOAK_ADMIN
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-secrets
key: KEYCLOAK_ADMIN_PASSWORD
- name: KC_HTTP_ENABLED
value: "true"
- name: KC_PROXY_HEADERS
value: "xforwarded"
- name: KC_HOSTNAME
value: "https://keycloak.sttlab.local"
- name: KC_HOSTNAME_STRICT
value: "false"
- name: KC_HOSTNAME_BACKCHANNEL_DYNAMIC
value: "false"
- name: KC_FEATURES
value: "token-exchange,admin-fine-grained-authz,log-mdc"
# Emptied for this container only: it inherits the main container's env,
# which loads the OpenTelemetry agent from a volume the other init
# container downloads into and this one does not mount. Inheriting it
# verbatim fails the JVM before the import runs.
- name: JAVA_OPTS_APPEND
value: ""
- name: OTEL_SERVICE_NAME
value: "keycloak"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://tempo.observability.svc.cluster.local:4318"
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: "http/protobuf"
- name: OTEL_TRACES_EXPORTER
value: "otlp"
- name: OTEL_METRICS_EXPORTER
value: "none"
- name: OTEL_LOGS_EXPORTER
value: "none"
- name: KC_HTTP_ACCESS_LOG_ENABLED
value: "true"
- name: KC_LOG_LEVEL
value: "INFO,org.keycloak.events:DEBUG"
- name: KC_LOG_CONSOLE_OUTPUT
value: "json"
- name: KC_LOG_MDC_ENABLED
value: "true"
- name: KC_LOG_SERVICE_NAME
value: "keycloak"
- name: KC_LOG_SERVICE_ENVIRONMENT
value: "local"
- name: KC_HEALTH_ENABLED
value: "true"
- name: KC_METRICS_ENABLED
value: "true"
volumeMounts:
- name: realm-import
mountPath: /opt/keycloak/data/import
- name: download-otel-agent
image: curlimages/curl:8.10.0
command:
@@ -42,7 +156,6 @@ spec:
image: quay.io/keycloak/keycloak:26.6.0
args:
- "start"
- "--import-realm"
ports:
- name: http
containerPort: 8080