diff --git a/.github/actions/collect_diagnostics/action.yaml b/.github/actions/collect_diagnostics/action.yaml
index 1802dbe40..a23ed05f6 100644
--- a/.github/actions/collect_diagnostics/action.yaml
+++ b/.github/actions/collect_diagnostics/action.yaml
@@ -11,6 +11,7 @@ runs:
run: |
mkdir -p kind-diagnostics
kubectl get pods -o wide -A > kind-diagnostics/pods-list.txt
+ kubectl get all -A > kind-diagnostics/kubectl-get-all.txt
kubectl describe pods -A > kind-diagnostics/pods-describe.txt
mage logutils:collectArgoDiags > kind-diagnostics/argo-diag.txt
kubectl get applications -o yaml -A > kind-diagnostics/argocd-applications.yaml
@@ -23,6 +24,7 @@ runs:
name: kind-diagnostics
path: |
kind-diagnostics/pods-list.txt
+ kind-diagnostics/kubectl-get-all.txt
kind-diagnostics/pods-describe.txt
kind-diagnostics/argo-diag.txt
kind-diagnostics/argocd-applications.yaml
diff --git a/.github/workflows/virtual-integration.yml b/.github/workflows/virtual-integration.yml
index 66c7eb2df..4c831a968 100644
--- a/.github/workflows/virtual-integration.yml
+++ b/.github/workflows/virtual-integration.yml
@@ -758,7 +758,7 @@ jobs:
REQUESTS_CA_BUNDLE: /usr/local/share/ca-certificates/orch-ca.crt
LIBVIRT_DEFAULT_URI: 'qemu:///system'
run: |
- KC_ADMIN_PWD=$(kubectl -n orch-platform get secrets platform-keycloak -o jsonpath='{.data.admin-password}' | base64 -d)
+ KC_ADMIN_PWD=$(kubectl -n keycloak-system get secrets platform-keycloak -o jsonpath='{.data.password}' | base64 -d)
# Add the password to the orchestrator config
yq eval ".orchestrator.admin_password = \"${KC_ADMIN_PWD}\"" -i orchestrator-configs/on-prem.yaml
diff --git a/argocd/applications/configs/app-deployment-manager.yaml b/argocd/applications/configs/app-deployment-manager.yaml
index b20732eb1..d7d41da1d 100644
--- a/argocd/applications/configs/app-deployment-manager.yaml
+++ b/argocd/applications/configs/app-deployment-manager.yaml
@@ -5,7 +5,7 @@
adm:
resources: null
catalogService: app-orch-catalog-grpc-server:8080
- keycloakServerEndpoint: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakServerEndpoint: "http://platform-keycloak.keycloak-system.svc.cluster.local"
secretService:
enabled: true
endpoint: "http://vault.orch-platform.svc.cluster.local:8200"
@@ -31,7 +31,7 @@ adm:
openidc:
# -- the endpoint of a Keycloak Realm e.g. http://keycloak/realms/master
- issuer: "http://platform-keycloak.orch-platform.svc/realms/master"
+ issuer: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
insecureSkipVerify: false
gitea:
diff --git a/argocd/applications/configs/app-interconnect-manager.yaml b/argocd/applications/configs/app-interconnect-manager.yaml
index 7b9ffad7e..2538bd808 100644
--- a/argocd/applications/configs/app-interconnect-manager.yaml
+++ b/argocd/applications/configs/app-interconnect-manager.yaml
@@ -8,5 +8,5 @@ interconnect_manager:
create: false
name: orch-svc
vaultServer: "http://vault.orch-platform.svc.cluster.local:8200"
- keycloakServer: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakServer: "http://platform-keycloak.keycloak-system.svc.cluster.local"
resources: null
diff --git a/argocd/applications/configs/app-orch-catalog.yaml b/argocd/applications/configs/app-orch-catalog.yaml
index 53082941d..23dee7159 100644
--- a/argocd/applications/configs/app-orch-catalog.yaml
+++ b/argocd/applications/configs/app-orch-catalog.yaml
@@ -14,7 +14,7 @@ traefikReverseProxy:
enabled: true
secretName: tls-orch ## must be created in orch-gateway namespace
openidc:
- issuer: http://platform-keycloak.orch-platform.svc/realms/master
+ issuer: http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master
storage:
size: 1Gi
postgres:
diff --git a/argocd/applications/configs/app-orch-tenant-controller.yaml b/argocd/applications/configs/app-orch-tenant-controller.yaml
index 6dcf53c0b..45783c97c 100644
--- a/argocd/applications/configs/app-orch-tenant-controller.yaml
+++ b/argocd/applications/configs/app-orch-tenant-controller.yaml
@@ -8,7 +8,7 @@ configProvisioner:
admServer: app-deployment-api-grpc-server.orch-app.svc.cluster.local:8080
namespace: orch-app
vaultServer: "http://vault.orch-platform.svc.cluster.local:8200"
- keycloakServiceBase: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakServiceBase: "http://platform-keycloak.keycloak-system.svc.cluster.local"
releaseServiceBase: "rs-proxy.orch-platform.svc.cluster.local:8081"
releaseServiceProxyRootUrl: "oci://rs-proxy.orch-platform.svc.cluster.local:8443"
manifestPath: "/edge-orch/en/file/cluster-extension-manifest"
diff --git a/argocd/applications/configs/app-resource-manager.yaml b/argocd/applications/configs/app-resource-manager.yaml
index 9805a442c..09c70775c 100644
--- a/argocd/applications/configs/app-resource-manager.yaml
+++ b/argocd/applications/configs/app-resource-manager.yaml
@@ -19,5 +19,5 @@ traefikApiGroup: "traefik.io/v1alpha1"
resources: null
vncProxyResources: null
vaultServer: "http://vault.orch-platform.svc.cluster.local:8200"
-keycloakServer: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+keycloakServer: "http://platform-keycloak.keycloak-system.svc.cluster.local"
defaultNamespace: "orch-app"
diff --git a/argocd/applications/configs/auth-service.yaml b/argocd/applications/configs/auth-service.yaml
index e5c69d430..15ee6cf14 100644
--- a/argocd/applications/configs/auth-service.yaml
+++ b/argocd/applications/configs/auth-service.yaml
@@ -3,3 +3,5 @@
# SPDX-License-Identifier: Apache-2.0
resources: null
+
+jwksURL: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master/protocol/openid-connect/certs"
diff --git a/argocd/applications/configs/copy-db-to-keycloak-ns.yaml b/argocd/applications/configs/copy-db-to-keycloak-ns.yaml
new file mode 100644
index 000000000..07516e4bc
--- /dev/null
+++ b/argocd/applications/configs/copy-db-to-keycloak-ns.yaml
@@ -0,0 +1,28 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# Sync the Keycloak PostgreSQL database credentials from keycloak-system namespace to orch-platform
+# Source: platform-keycloak-local-postgresql secret (created during bootstrap, in deploy.go)
+# Target: platform-keycloak-local-postgresql secret (required by keycloak-tenant-controller init container)
+# Also this source and target gets updated in customs/platform-keycloak.tpl
+# Note: Syncs all PostgreSQL connection environment variables (PGDATABASE, PGHOST, PGPASSWORD, PGPORT, PGUSER)
+remoteNamespace: orch-platform
+refreshInterval: "0m"
+targetSecretName: platform-keycloak-aurora-postgresql
+sourceSecretName: platform-keycloak-aurora-postgresql
+keyName:
+ - source: PGDATABASE
+ target: PGDATABASE
+ - source: PGHOST
+ target: PGHOST
+ - source: PGPASSWORD
+ target: PGPASSWORD
+ - source: PGPORT
+ target: PGPORT
+ - source: PGUSER
+ target: PGUSER
+ - source: password
+ target: password
+
+externalSecretsApiGroup: external-secrets.io/v1
diff --git a/argocd/applications/configs/copy-keycloak-admin-to-platform.yaml b/argocd/applications/configs/copy-keycloak-admin-to-platform.yaml
new file mode 100644
index 000000000..6456b6962
--- /dev/null
+++ b/argocd/applications/configs/copy-keycloak-admin-to-platform.yaml
@@ -0,0 +1,17 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# Sync the Keycloak bootstrap admin credentials from keycloak-system namespace to orch-platform
+# Source: platform-keycloak secret (created during bootstrap, in deploy.go)
+# Target: platform-keycloak secret (required by keycloak-tenant-controller init container)
+# Note: Maps 'password' key to 'admin-password' for keycloak-tenant-controller compatibility
+remoteNamespace: keycloak-system
+refreshInterval: "0m"
+targetSecretName: platform-keycloak
+sourceSecretName: platform-keycloak
+keyName:
+ - source: password
+ target: admin-password
+
+externalSecretsApiGroup: external-secrets.io/v1
diff --git a/argocd/applications/configs/infra-core.yaml b/argocd/applications/configs/infra-core.yaml
index 455052122..ef119e76d 100644
--- a/argocd/applications/configs/infra-core.yaml
+++ b/argocd/applications/configs/infra-core.yaml
@@ -15,7 +15,7 @@ credentials:
serviceAccount:
name: "orch-svc"
params:
- keycloakUrl: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakUrl: "http://platform-keycloak.keycloak-system.svc.cluster.local"
vaultUrl: "http://vault.orch-platform.svc.cluster.local:8200"
curlImage:
name: badouralix/curl-jq@sha256
@@ -37,7 +37,7 @@ api:
oidc:
name: "keycloak-api"
oidc_env_name: "OIDC_SERVER_URL"
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
oidc_tls_insecure_skip_verify_env_name: "OIDC_TLS_INSECURE_SKIP_VERIFY"
oidc_tls_insecure_skip_verify_value: "true"
multiTenancy:
@@ -64,7 +64,7 @@ apiv2:
oidc:
name: "keycloak-api"
oidc_env_name: "OIDC_SERVER_URL"
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
oidc_tls_insecure_skip_verify_env_name: "OIDC_TLS_INSECURE_SKIP_VERIFY"
oidc_tls_insecure_skip_verify_value: "true"
resources: null
@@ -81,6 +81,11 @@ inventory:
tag: 16.10-bookworm
ssl: false
secrets: inventory-local-postgresql
+ oidc:
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
+ name: "keycloak-inventory"
+ oidc_tls_insecure_skip_verify_env_name: "OIDC_TLS_INSECURE_SKIP_VERIFY"
+ oidc_tls_insecure_skip_verify_value: "true"
resources: null
serviceAccount:
name: "orch-svc"
@@ -90,7 +95,7 @@ tenant-controller:
inventoryAddress: "inventory.orch-infra.svc.cluster.local:50051"
traceURL: "orchestrator-observability-opentelemetry-collector.orch-platform.svc:4318"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc.cluster.local/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
resources: null
serviceAccount:
name: "orch-svc"
diff --git a/argocd/applications/configs/infra-external.yaml b/argocd/applications/configs/infra-external.yaml
index fc088ebf6..918893be3 100644
--- a/argocd/applications/configs/infra-external.yaml
+++ b/argocd/applications/configs/infra-external.yaml
@@ -19,7 +19,7 @@ loca-manager:
env:
vaultUrl: "http://vault.orch-platform.svc.cluster.local:8200"
vaultRole: "orch-svc"
- keycloakUrl: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakUrl: "http://platform-keycloak.keycloak-system.svc.cluster.local"
loca-metadata-manager:
serviceAccount:
@@ -78,7 +78,7 @@ loca-credentials:
serviceAccount:
name: "orch-svc"
params:
- keycloakUrl: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakUrl: "http://platform-keycloak.keycloak-system.svc.cluster.local"
vaultUrl: "http://vault.orch-platform.svc.cluster.local:8200"
curlImage:
name: badouralix/curl-jq@sha256
@@ -131,7 +131,7 @@ amt:
password: ""
env:
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
oidc_tls_insecure_skip_verify_value: "true"
curlImage:
name: badouralix/curl-jq@sha256
diff --git a/argocd/applications/configs/infra-managers.yaml b/argocd/applications/configs/infra-managers.yaml
index 14978ba91..b64d6a8c5 100644
--- a/argocd/applications/configs/infra-managers.yaml
+++ b/argocd/applications/configs/infra-managers.yaml
@@ -17,7 +17,7 @@ host-manager:
secretName: "tls-orch"
tlsOption: "gateway-tls"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
multiTenancy:
enforceMultiTenancy: "true"
resources: null
@@ -36,7 +36,7 @@ maintenance-manager:
secretName: "tls-orch"
tlsOption: "gateway-tls"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
telemetryMgrArgs:
enableVal: false # disable telemetry profile validation
multiTenancy:
@@ -66,7 +66,7 @@ telemetry-manager:
secretName: "tls-orch"
tlsOption: "gateway-tls"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
multiTenancy:
enforceMultiTenancy: "true"
resources: null
@@ -85,7 +85,7 @@ os-resource-manager:
image:
pullPolicy: IfNotPresent
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc.cluster.local/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
autoProvision:
enabled: false # autoprovisioning disabled by default, can be enabled by enable-autoprovision profile
multiTenancy:
@@ -104,7 +104,7 @@ attestationstatus-manager:
secretName: "tls-orch"
tlsOption: "gateway-tls"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
multiTenancy:
enforceMultiTenancy: "true"
resources: null
diff --git a/argocd/applications/configs/infra-onboarding.yaml b/argocd/applications/configs/infra-onboarding.yaml
index f2394d522..56a9c5634 100644
--- a/argocd/applications/configs/infra-onboarding.yaml
+++ b/argocd/applications/configs/infra-onboarding.yaml
@@ -35,14 +35,14 @@ onboarding-manager:
env:
tinkerActionsVersion: "1.19.9"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
# Skip AuthZ for CDN-boots
clients:
bypass:
- cdn-boots
vaultUrl: "http://vault.orch-platform.svc.cluster.local:8200"
vaultRole: "orch-svc"
- keycloakUrl: "http://platform-keycloak.orch-platform.svc.cluster.local:8080"
+ keycloakUrl: "http://platform-keycloak.keycloak-system.svc.cluster.local"
multiTenancy:
enforceMultiTenancy: true
resources: null
@@ -55,7 +55,7 @@ dkam:
env:
rs_proxy_address: "rs-proxy.orch-platform.svc.cluster.local:8081/"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
resources: null
infra-config:
diff --git a/argocd/applications/configs/intel-infra-provider.yaml b/argocd/applications/configs/intel-infra-provider.yaml
index 49e43bd7d..7003b737a 100644
--- a/argocd/applications/configs/intel-infra-provider.yaml
+++ b/argocd/applications/configs/intel-infra-provider.yaml
@@ -6,7 +6,7 @@ manager:
inventory:
endpoint: "inventory.orch-infra.svc.cluster.local:50051"
oidc:
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
# https://doc.traefik.io/traefik/migrate/v2-to-v3-details/#kubernetes-crds-api-group-traefikcontainous
traefikApiGroup: "traefik.io/v1alpha1"
diff --git a/argocd/applications/configs/keycloak-operator.yaml b/argocd/applications/configs/keycloak-operator.yaml
new file mode 100644
index 000000000..6b0e4615d
--- /dev/null
+++ b/argocd/applications/configs/keycloak-operator.yaml
@@ -0,0 +1,146 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# Base configuration for keycloak-operator deployment
+# This file provides default values for the Keycloak Operator that can be overridden
+
+# Keycloak Operator namespace
+namespace: keycloak-system
+
+# Operator deployment configuration
+operator:
+ # Deployment replicas
+ replicas: 1
+
+ # Container image (uses upstream version from Chart.yaml)
+ image: "quay.io/keycloak/keycloak-operator:26.4.5"
+ imagePullPolicy: IfNotPresent
+
+ # Related Keycloak image for operator to deploy
+ relatedImage:
+ keycloak: "quay.io/keycloak/keycloak:26.4.5"
+
+ # Service account name
+ serviceAccountName: keycloak-operator
+
+ # Deployment annotations (from upstream)
+ annotations:
+ app.quarkus.io/quarkus-version: "3.27.0"
+ app.quarkus.io/vcs-uri: "https://github.com/keycloak/keycloak.git"
+ app.quarkus.io/build-timestamp: "2025-10-23 - 07:06:46 +0000"
+
+ # Pod labels (from upstream)
+ podLabels:
+ app.kubernetes.io/managed-by: quarkus
+
+ # Pod security context
+ securityContext:
+ runAsNonRoot: true
+ runAsUser: 1000
+ fsGroup: 1000
+
+ # Container configuration
+ container:
+ name: keycloak-operator
+
+ # Container security context
+ securityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ seccompProfile:
+ type: RuntimeDefault
+ capabilities:
+ drop:
+ - ALL
+
+ # Resource allocation
+ resources:
+ requests:
+ cpu: 300m
+ memory: 450Mi
+ limits:
+ cpu: 700m
+ memory: 450Mi
+
+ # Container port configuration
+ ports:
+ - name: http
+ containerPort: 8080
+ protocol: TCP
+
+ # Environment variables
+ env:
+ - name: KUBERNETES_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: RELATED_IMAGE_KEYCLOAK
+ value: "quay.io/keycloak/keycloak:26.4.5"
+
+ # Liveness probe
+ livenessProbe:
+ httpGet:
+ scheme: HTTP
+ path: /q/health/live
+ port: 8080
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 10
+ failureThreshold: 3
+ successThreshold: 1
+
+ # Readiness probe
+ readinessProbe:
+ httpGet:
+ scheme: HTTP
+ path: /q/health/ready
+ port: 8080
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 10
+ failureThreshold: 3
+ successThreshold: 1
+
+ # Startup probe
+ startupProbe:
+ httpGet:
+ scheme: HTTP
+ path: /q/health/started
+ port: 8080
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 10
+ failureThreshold: 3
+ successThreshold: 1
+
+# Security context for operator pods (pod-level)
+securityContext:
+ runAsNonRoot: true
+ seccompProfile:
+ type: RuntimeDefault
+
+# Container security context (backward compatibility)
+containerSecurityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ seccompProfile:
+ type: RuntimeDefault
+ capabilities:
+ drop:
+ - ALL
+
+# Temporary volume mounts for operator
+volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: var-cache
+ mountPath: /var/cache
+
+# Empty directory volumes for temporary storage
+volumes:
+ - name: tmp
+ emptyDir: {}
+ - name: var-cache
+ emptyDir: {}
diff --git a/argocd/applications/configs/kyverno-extra-policies.yaml b/argocd/applications/configs/kyverno-extra-policies.yaml
index ebbc997eb..a5f392f3c 100644
--- a/argocd/applications/configs/kyverno-extra-policies.yaml
+++ b/argocd/applications/configs/kyverno-extra-policies.yaml
@@ -5,12 +5,16 @@
require_ro_rootfs:
FailureAction: "Audit"
exclude:
- namespaces: []
+ namespaces:
+ - keycloak-system
names: []
# Define namespace & pod (including wildcard) exceptions for restricted cluster policy.
# These are used for 1st party pods. Exceptions for 3rd party namespaces are defined in cluster policy.
restrictedPolicyOrch:
+ - namespace: "keycloak-system"
+ names:
+ - "platform-keycloak-*"
- namespace: "orch-iam"
names:
- "iam-umbrella-nexus-api-gw-*"
diff --git a/argocd/applications/configs/kyverno-istio-policy.yaml b/argocd/applications/configs/kyverno-istio-policy.yaml
index b3ee63558..730792450 100644
--- a/argocd/applications/configs/kyverno-istio-policy.yaml
+++ b/argocd/applications/configs/kyverno-istio-policy.yaml
@@ -43,3 +43,4 @@ excludedNamespaces:
- capr-system
- capk-system
- postgresql-operator
+ - keycloak-system
diff --git a/argocd/applications/configs/kyverno-traefik-policy.yaml b/argocd/applications/configs/kyverno-traefik-policy.yaml
index 2b34c1327..f4d7fbfd8 100644
--- a/argocd/applications/configs/kyverno-traefik-policy.yaml
+++ b/argocd/applications/configs/kyverno-traefik-policy.yaml
@@ -4,6 +4,10 @@
---
jwtMiddlewareException:
+ - namespace: "keycloak-system"
+ names:
+ - "platform-keycloak"
+ - "platform-keycloak-*"
- namespace: "orch-gateway"
names:
- "harbor-oci"
diff --git a/argocd/applications/configs/metadata-broker.yaml b/argocd/applications/configs/metadata-broker.yaml
index e83c27016..cbaced8b3 100644
--- a/argocd/applications/configs/metadata-broker.yaml
+++ b/argocd/applications/configs/metadata-broker.yaml
@@ -5,7 +5,7 @@
# Intentionally blank. There are no base settings overrides.
openidc:
- issuer: http://platform-keycloak.orch-platform.svc/realms/master
+ issuer: http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master
service:
traefik:
diff --git a/argocd/applications/configs/nexus-api-gw.yaml b/argocd/applications/configs/nexus-api-gw.yaml
index e128e9873..8c9d0e5ed 100644
--- a/argocd/applications/configs/nexus-api-gw.yaml
+++ b/argocd/applications/configs/nexus-api-gw.yaml
@@ -19,7 +19,6 @@ traefikApiGroup: "traefik.io/v1alpha1"
oidc:
name: "keycloak-api"
oidc_env_name: "OIDC_SERVER_URL"
- # TODO: Use `platform-keycloak.orch-platform.svc.cluster.local` to avoid possible DNS search domain problems.
- oidc_server_url: "http://platform-keycloak.orch-platform.svc/realms/master"
+ oidc_server_url: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
oidc_tls_insecure_skip_verify_env_name: "OIDC_TLS_INSECURE_SKIP_VERIFY"
oidc_tls_insecure_skip_verify_value: "true"
diff --git a/argocd/applications/configs/platform-keycloak.yaml b/argocd/applications/configs/platform-keycloak.yaml
index 9339d0430..276d0f461 100644
--- a/argocd/applications/configs/platform-keycloak.yaml
+++ b/argocd/applications/configs/platform-keycloak.yaml
@@ -2,1279 +2,167 @@
#
# SPDX-License-Identifier: Apache-2.0
-global:
- security:
- allowInsecureImages: true
-image:
- registry: docker.io
- repository: bitnamilegacy/keycloak
- tag: 26.1.3-debian-12-r0
- pullPolicy: IfNotPresent
+# NOTE: realmMaster realm configuration is defined in custom/platform-keycloak.tpl
+# where it can access clusterSpecific values with templated domain names
-containerSecurityContext:
- allowPrivilegeEscalation: false
- capabilities:
- drop: ["ALL"]
- seccompProfile:
- type: "RuntimeDefault"
+# Keycloak Config CLI job configuration
+keycloakConfigCli:
+ enabled: true
-# disable network policy to avoid intermittent dns issues
-networkPolicy:
- enabled: false
+ serviceAccount:
+ name: keycloak-config-cli
+ namespace: keycloak-system
+ labels:
+ app.kubernetes.io/name: keycloak-config-cli
+ app.kubernetes.io/instance: keycloak-config-cli
+ app.kubernetes.io/version: "6.4.0"
-## PostgreSQL chart configuration
-## ref: https://github.com/bitnami/charts/blob/main/bitnami/postgresql/values.yaml
-## @param postgresql.enabled Switch to enable or disable the PostgreSQL helm chart
-postgresql:
- enabled: false
+ configMap:
+ name: keycloak-config-cli-realm-master
+ namespace: keycloak-system
+ labels:
+ app.kubernetes.io/name: keycloak-config-cli
+ app.kubernetes.io/instance: keycloak-config-cli
-## Service configuration
-##
-service:
- ## @param service.type Kubernetes service type, default: LoadBalancer
- ##
- type: ClusterIP
- ports:
- http: 8080
+ job:
+ name: keycloak-config-cli
+ namespace: keycloak-system
+ labels:
+ app.kubernetes.io/name: keycloak-config-cli
+ app.kubernetes.io/instance: keycloak-config-cli
+ app.kubernetes.io/version: "6.4.0"
-## Keycloak authentication parameters
-## ref: https://github.com/bitnami/containers/tree/main/bitnami/keycloak#admin-credentials
-##
-auth:
- ## @param auth.adminUser Keycloak administrator user
- ##
- adminUser: admin
- ## @param auth.adminPassword Keycloak administrator password for the new user
- ##
- adminPassword: ""
+ ttlSecondsAfterFinished: 3600
+ backoffLimit: 5
+ restartPolicy: Never
- passwordSecretKey: admin-password
- existingSecret: platform-keycloak
+ podLabels:
+ sidecar.istio.io/inject: "false"
-## Adds argument for enabling legacy logout redirect
-## This is needed for the Grafana client integration which does not currently support the new way keycloak does single sign-out.
-## Keycloak mentions that this legacy feature will be removed in Keycloak 23.0.
-extraStartupArgs: >-
- --spi-login-protocol-openid-connect-legacy-logout-redirect-uri=true
- --spi-brute-force-protector-default-brute-force-detector-allow-concurrent-requests=true
+ securityContext:
+ runAsNonRoot: true
+ runAsUser: 65534
+ runAsGroup: 65534
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 65534
-## Configuration for keycloak-config-cli
-## ref: https://github.com/adorsys/keycloak-config-cli
-##
-keycloakConfigCli:
- image:
- pullPolicy: IfNotPresent
- registry: docker.io
- repository: bitnamilegacy/keycloak-config-cli
- tag: 6.4.0-debian-12-r0
+ initContainers:
+ - name: wait-for-keycloak
+ image: busybox:1.36
+ imagePullPolicy: IfNotPresent
+ command:
+ - sh
+ - -c
+ - |
+ set -e
+ echo "Waiting for Keycloak to be ready..."
+ MAX_ATTEMPTS=60
+ ATTEMPT=0
+ while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
+ if timeout 2 sh -c "echo '' | nc -w1 platform-keycloak.keycloak-system.svc 8080" >/dev/null 2>&1; then
+ echo "Keycloak port 8080 is open!"
+ exit 0
+ fi
+ ATTEMPT=$((ATTEMPT + 1))
+ echo "Attempt $ATTEMPT/$MAX_ATTEMPTS - Waiting for Keycloak..."
+ sleep 5
+ done
+ echo "WARNING: Keycloak did not respond, but proceeding anyway..."
+ exit 0
+ resources:
+ requests:
+ cpu: 50m
+ memory: 64Mi
+ limits:
+ cpu: 100m
+ memory: 128Mi
+ securityContext:
+ allowPrivilegeEscalation: false
+ runAsNonRoot: true
+ runAsUser: 65534
+ runAsGroup: 65534
+ seccompProfile:
+ type: RuntimeDefault
+ capabilities:
+ drop:
+ - ALL
+ readOnlyRootFilesystem: true
- ## @param keycloakConfigCli.enabled Whether to enable keycloak-config-cli job
- ##
- enabled: true
- args:
- - --import.managed.group="no-delete"
- - --import.managed.required-action="no-delete"
- - --import.managed.role="no-delete"
- - --import.managed.client="no-delete"
+ container:
+ name: keycloak-config-cli
+ image: docker.io/adorsys/keycloak-config-cli:6.4.0-26
+ imagePullPolicy: IfNotPresent
+
+ env:
+ - name: KEYCLOAK_URL
+ value: "http://platform-keycloak.keycloak-system.svc.cluster.local/"
+ - name: KEYCLOAK_USER
+ value: "admin"
+ - name: KEYCLOAK_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: platform-keycloak
+ key: password
+ - name: KEYCLOAK_AVAILABILITYCHECK_ENABLED
+ value: "true"
+ - name: KEYCLOAK_AVAILABILITYCHECK_TIMEOUT
+ value: "120s"
+ - name: IMPORT_VARSUBSTITUTION_ENABLED
+ value: "true"
+ - name: IMPORT_FILES_LOCATIONS
+ value: "/config/*"
+ - name: IMPORT_MANAGED_GROUP
+ value: "no-delete"
+ - name: IMPORT_MANAGED_REQUIRED_ACTION
+ value: "no-delete"
+ - name: IMPORT_MANAGED_ROLE
+ value: "no-delete"
+ - name: IMPORT_MANAGED_CLIENT
+ value: "no-delete"
+ - name: IMPORT_REMOTE_STATE_ENABLED
+ value: "true"
+ - name: LOGGING_LEVEL_ROOT
+ value: "INFO"
+ - name: LOGGING_LEVEL_KEYCLOAKCONFIGCLI
+ value: "DEBUG"
+
+ resources:
+ requests:
+ cpu: 200m
+ memory: 512Mi
+ limits:
+ cpu: 1000m
+ memory: 1Gi
- ## @param keycloakConfigCli.annotations [object] Annotations for keycloak-config-cli job
- ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
- ##
- annotations:
- helm.sh/hook: "post-install"
- helm.sh/hook-delete-policy: "hook-succeeded"
+ volumeMounts:
+ - name: config
+ mountPath: /config
+ readOnly: true
+ - name: tmp
+ mountPath: /tmp
- ## do not inject sidecar to pods for job
- podLabels:
- sidecar.istio.io/inject: "false"
+ securityContext:
+ allowPrivilegeEscalation: false
+ runAsNonRoot: true
+ runAsUser: 65534
+ runAsGroup: 65534
+ seccompProfile:
+ type: RuntimeDefault
+ capabilities:
+ drop:
+ - ALL
+ readOnlyRootFilesystem: true
- ## @param keycloakConfigCli.configuration keycloak-config-cli realms configuration
- ## NOTE: nil keys will be considered files to import locally
- ## Example:
- ## configuration:
- ## realm1.json: |
- ## {
- ## "realm": "realm1",
- ## "clients": []
- ## }
- ## files/realm2.yaml:
- ## realm3.yaml: |
- ## realm: realm3
- ## clients: []
- ##
+ volumes:
+ - name: config
+ configMap:
+ name: keycloak-config-cli-realm-master
+ defaultMode: 0444
+ - name: tmp
+ emptyDir: {}
- # yamllint disable rule:line-length
- configuration:
- realm-master.json: |
- {
- "realm": "master",
- "accountTheme": "keycloak",
- "displayName": "Keycloak",
- "displayNameHtml": "
",
- "defaultSignatureAlgorithm": "PS512",
- "accessTokenLifespan": 3600,
- "ssoSessionIdleTimeout": 5400,
- "ssoSessionMaxLifespan": 43200,
- "passwordPolicy": "length(14) and digits(1) and specialChars(1) and upperCase(1) and lowerCase(1)",
- "bruteForceProtected": true,
- "permanentLockout": false,
- "maxFailureWaitSeconds": 900,
- "minimumQuickLoginWaitSeconds": 60,
- "waitIncrementSeconds": 300,
- "quickLoginCheckMilliSeconds": 200,
- "maxDeltaTimeSeconds": 43200,
- "failureFactor": 5,
- "roles": {
- "realm": [
- {
- "name": "en-agent-rw"
- },
- {
- "name": "secrets-root-role"
- },
- {
- "name": "rs-access-r"
- },
- {
- "name": "rs-proxy-r"
- },
- {
- "name": "app-service-proxy-read-role"
- },
- {
- "name": "app-service-proxy-write-role"
- },
- {
- "name": "app-deployment-manager-read-role"
- },
- {
- "name": "app-deployment-manager-write-role"
- },
- {
- "name": "app-resource-manager-read-role"
- },
- {
- "name": "app-resource-manager-write-role"
- },
- {
- "name": "app-vm-console-write-role"
- },
- {
- "name": "catalog-publisher-read-role"
- },
- {
- "name": "catalog-publisher-write-role"
- },
- {
- "name": "catalog-other-read-role"
- },
- {
- "name": "catalog-other-write-role"
- },
- {
- "name": "catalog-restricted-read-role"
- },
- {
- "name": "catalog-restricted-write-role"
- },
- {
- "name": "clusters-read-role"
- },
- {
- "name": "clusters-write-role"
- },
- {
- "name": "cluster-templates-read-role"
- },
- {
- "name": "cluster-templates-write-role"
- },
- {
- "name": "cluster-artifacts-read-role"
- },
- {
- "name": "cluster-artifacts-write-role"
- },
- {
- "name": "infra-manager-core-read-role"
- },
- {
- "name": "infra-manager-core-write-role"
- },
- {
- "name": "alrt-r"
- },
- {
- "name": "alrt-rw"
- },
- {
- "name": "alrt-rx-rw"
- },
- {
- "name": "ao-m2m-rw"
- },
- {
- "name": "co-m2m-rw"
- },
- {
- "name": "org-read-role"
- },
- {
- "name": "org-write-role"
- },
- {
- "name": "org-update-role"
- },
- {
- "name": "org-delete-role"
- }
- ],
- "client": {
- "alerts-m2m-client": [],
- "host-manager-m2m-client": [],
- "co-manager-m2m-client": [],
- "ktc-m2m-client": [],
- "3rd-party-host-manager-m2m-client": [],
- "edge-manager-m2m-client": [],
- "en-m2m-template-client": [],
- "webui-client": [],
- "docsui-client": [],
- "account": [
- {
- "name": "view-profile",
- "clientRole": true
- },
- {
- "name": "manage-account",
- "clientRole": true
- }
- ],
- "telemetry-client": [
- {
- "name": "admin",
- "clientRole": true
- },
- {
- "name": "viewer",
- "clientRole": true
- }
- ],
- "cluster-management-client": [
- {
- "name": "restricted-role",
- "clientRole": true
- },
- {
- "name": "standard-role",
- "clientRole": true
- },
- {
- "name": "base-role",
- "clientRole": true
- }
- ],
- "registry-client": [
- {
- "name": "registry-admin-role",
- "clientRole": true
- },
- {
- "name": "registry-editor-role",
- "clientRole": true
- },
- {
- "name": "registry-viewer-role",
- "clientRole": true
- }
- ]
- }
- },
- "clients": [
- {
- "clientId": "alerts-m2m-client",
- "name": "Alerts M2M Client",
- "description": "Client for Alerts",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "clientId": "host-manager-m2m-client",
- "name": "Host Manager Client",
- "description": "Client for the EN Host Manager to use in creating edgenode m2m clients",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "clientId": "co-manager-m2m-client",
- "name": "Cluster Orchestrator Manager M2M Client",
- "description": "Client for cluster-manager to access Keycloak for JWT TTL management",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "email",
- "basic",
- "groups"
- ],
- "optionalClientScopes": [
- "offline_access"
- ]
- },
- {
- "clientId": "ktc-m2m-client",
- "name": "Keycloak Tenant Controller client",
- "description": "Client for the Keycloak Tenant Controller to use in creating Tenant specific roles and groups in Keycloak",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "groups",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "clientId": "3rd-party-host-manager-m2m-client",
- "name": "3rd Party Host Manager Client",
- "description": "Client for the 3rd party Host Manager to use in creating edgenode m2m clients",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "clientId": "edge-manager-m2m-client",
- "name": "Edge Manager M2M Client",
- "description": "Client for the accessing Orchestrator with Edge-Manager persona",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "email",
- "groups",
- "basic"
- ],
- "optionalClientScopes": [
- "offline_access",
- ]
- },
- {
- "clientId": "en-m2m-template-client",
- "name": "Edge Node M2M Template Client",
- "description": "Client to use as basis for Roles to assign to new Edge Node M2M clients",
- "surrogateAuthRequired": false,
- "enabled": false,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "profile",
- "roles",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "clientId": "telemetry-client",
- "name": "Telemetry Client",
- "rootUrl": {{ .Values.clusterSpecific.telemetryClientRootUrl | toJson }},
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": {{ .Values.clusterSpecific.telemetryRedirectUrls | toJson }},
- "webOrigins": [
- "+"
- ],
- "protocol": "openid-connect",
- "directAccessGrantsEnabled": true,
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "client.secret.creation.time": "1683218404",
- "backchannel.logout.session.required": "true",
- "post.logout.redirect.uris": "+",
- "display.on.consent.screen": "false",
- "use.jwks.url": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "profile",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "groups",
- "offline_access"
- ]
- },
- {
- "clientId": "cluster-management-client",
- "name": "Cluster Management Client",
- "rootUrl": {{ .Values.clusterSpecific.clusterManagementClientRootUrl | toJson }},
- "adminUrl": {{ .Values.clusterSpecific.clusterManagementClientRootUrl | toJson }},
- "surrogateAuthRequired": false,
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": {{ .Values.clusterSpecific.clusterManagementRedirectUrls | toJson }},
- "webOrigins": [
- "+"
- ],
- "directAccessGrantsEnabled": true,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.revoke.offline.tokens": "false",
- "use.refresh.tokens": "true",
- "oidc.ciba.grant.enabled": "false",
- "backchannel.logout.session.required": "true",
- "client_credentials.use_refresh_token": "false",
- "require.pushed.authorization.requests": "false",
- "tls.client.certificate.bound.access.tokens": "false",
- "display.on.consent.screen": "false",
- "token.response.type.bearer.lower-case": "false",
- },
- "fullScopeAllowed": true,
- "protocolMappers": [
- {
- "name": "Group Path",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-group-membership-mapper",
- "consentRequired": false,
- "config": {
- "full.path": "true",
- "id.token.claim": "false",
- "access.token.claim": "false",
- "claim.name": "full_group_path",
- "userinfo.token.claim": "true"
- }
- },
- {
- "name": "Groups Mapper",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-group-membership-mapper",
- "consentRequired": false,
- "config": {
- "full.path": "false",
- "id.token.claim": "false",
- "access.token.claim": "false",
- "claim.name": "groups",
- "userinfo.token.claim": "true"
- }
- },
- {
- "name": "Client Audience",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-audience-mapper",
- "consentRequired": false,
- "config": {
- "included.client.audience": "cluster-management-client",
- "id.token.claim": "false",
- "access.token.claim": "true"
- }
- }
- ],
- "defaultClientScopes": [
- "profile",
- "roles",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "groups",
- "offline_access",
- ],
- "authorizationServicesEnabled": false
- },
- {
- "clientId": "webui-client",
- "name": "WebUI Client",
- "rootUrl": {{ .Values.clusterSpecific.webuiClientRootUrl | toJson }},
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": {{ .Values.clusterSpecific.webuiRedirectUrls | toJson }},
- "webOrigins": [
- "+"
- ],
- "protocol": "openid-connect",
- "directAccessGrantsEnabled": false,
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "client.secret.creation.time": "1683218404",
- "backchannel.logout.session.required": "true",
- "post.logout.redirect.uris": "+",
- "display.on.consent.screen": "false",
- "oauth2.device.authorization.grant.enabled": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "profile",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "groups",
- "offline_access"
- ]
- },
- {
- "clientId": "docsui-client",
- "name": "DocsUI Client",
- "rootUrl": {{ .Values.clusterSpecific.docsuiClientRootUrl | toJson }},
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": {{ .Values.clusterSpecific.docsuiRedirectUrls | toJson }},
- "webOrigins": [
- "+"
- ],
- "protocol": "openid-connect",
- "directAccessGrantsEnabled": false,
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "client.secret.creation.time": "1683218404",
- "backchannel.logout.session.required": "true",
- "post.logout.redirect.uris": "+",
- "display.on.consent.screen": "false",
- "oauth2.device.authorization.grant.enabled": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "profile",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "groups",
- "offline_access"
- ]
- },
- {
- "clientId": "system-client",
- "name": "System Client",
- "surrogateAuthRequired": false,
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": [],
- "webOrigins": [],
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": true,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "true",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "profile",
- "email",
- "basic"
- ],
- "optionalClientScopes": [
- "groups",
- "offline_access"
- ]
- },
- {
- "frontchannelLogout": true,
- "standardFlowEnabled": true,
- "clientId": "registry-client",
- "name": "Registry Client",
- "rootUrl": {{ .Values.clusterSpecific.registryClientRootUrl | toJson }},
- "enabled": true,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": [
- "/c/oidc/callback"
- ],
- "webOrigins": [
- "+"
- ],
- "protocol": "openid-connect",
- "directAccessGrantsEnabled": true,
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "client.secret.creation.time": "1683218404",
- "backchannel.logout.session.required": "true",
- "post.logout.redirect.uris": "+",
- "display.on.consent.screen": "false",
- "use.jwks.url": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "fullScopeAllowed": true,
- "defaultClientScopes": [
- "roles",
- "profile",
- "email",
- "groups",
- "basic"
- ],
- "optionalClientScopes": [
- "offline_access"
- ]
- }
- ],
- "clientScopes": [
- {
- "name": "groups",
- "description": "Groups scope",
- "type": "Optional",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true"
- },
- "protocolMappers": [
- {
- "name": "groups",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-group-membership-mapper",
- "consentRequired": false,
- "config": {
- "multivalued": "true",
- "full.path": "false",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "groups",
- "userinfo.token.claim": "true",
- "jsonType.label": "String"
- }
- }
- ]
- },
- {
- "name": "roles",
- "description": "OpenID Connect scope for add user roles to the access token",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "gui.order": "",
- "consent.screen.text": '{{"$"}}{{"{"}}roleScopeConsentText{{"}"}}'
- },
- "protocolMappers": [
- {
- "name": "realm roles",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-realm-role-mapper",
- "consentRequired": false,
- "config": {
- "multivalued": "true",
- "userinfo.token.claim": "true",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "realm_access.roles",
- "jsonType.label": "String"
- }
- },
- {
- "name": "client roles",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-client-role-mapper",
- "consentRequired": false,
- "config": {
- "multivalued": "true",
- "userinfo.token.claim": "true",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "resource_access.{{"$"}}{{"{"}}client_id{{"}"}}.roles",
- "jsonType.label": "String"
- }
- }
- ]
- }
- ],
- "groups": [
- {
- "name": "registry-app-admin-group",
- "path": "/registry-app-admin-group",
- },
- {
- "name": "registry-app-editor-group",
- "path": "/registry-app-editor-group",
- },
- {
- "name": "registry-app-viewer-group",
- "path": "/registry-app-viewer-group",
- },
- {
- "name": "apps-m2m-service-account",
- "path": "/apps-m2m-service-account",
- "realmRoles": [
- "ao-m2m-rw",
- "co-m2m-rw"
- ]
- },
- {
- "name": "org-admin-group",
- "path": "/org-admin-group",
- "realmRoles": [
- "org-read-role",
- "org-update-role",
- "org-delete-role",
- "org-write-role"
- ]
- },
- {
- "name": "sre-admin-group",
- "path": "/sre-admin-group",
- "realmRoles": [
- "alrt-r"
- ],
- "clientRoles": {
- "account": [
- "view-profile",
- "manage-account"
- ],
- "telemetry-client": [
- "viewer"
- ]
- }
- },
- {
- "name": "iam-admin-group",
- "path": "/iam-admin-group",
- "realmRoles": [
- "admin",
- "secrets-root-role"
- ],
- "clientRoles": {
- "account": [
- "view-profile",
- "manage-account"
- ],
- "master-realm": [
- "view-users",
- "query-users",
- "manage-clients"
- ]
- }
- },
- {
- "name": "service-admin-group",
- "path": "/service-admin-group",
- "realmRoles": [
- "alrt-rx-rw",
- "rs-access-r",
- "infra-manager-core-read-role",
- "infra-manager-core-write-role",
- "alrt-rw"
- ],
- "clientRoles": {
- "account": [
- "view-profile",
- "manage-account"
- ],
- "master-realm": [
- "view-users",
- "query-users",
- "manage-clients"
- ],
- "telemetry-client": [
- "admin"
- ],
- "cluster-management-client": [
- "restricted-role",
- "standard-role",
- "base-role"
- ],
- "registry-client": [
- "registry-admin-role"
- ]
- }
- },
- {
- "name": "edge-manager-group",
- "path": "/edge-manager-group",
- "realmRoles": [
- "app-service-proxy-read-role",
- "app-service-proxy-write-role",
- "app-deployment-manager-read-role",
- "app-deployment-manager-write-role",
- "app-resource-manager-read-role",
- "app-resource-manager-write-role",
- "app-vm-console-write-role",
- "catalog-publisher-read-role",
- "catalog-publisher-write-role",
- "catalog-other-read-role",
- "catalog-other-write-role",
- "catalog-restricted-read-role",
- "catalog-restricted-write-role",
- "clusters-read-role",
- "clusters-write-role",
- "cluster-templates-read-role",
- "cluster-templates-write-role",
- "cluster-artifacts-read-role",
- "cluster-artifacts-write-role",
- "infra-manager-core-read-role",
- "alrt-rw"
- ],
- "clientRoles": {
- "telemetry-client": [
- "viewer"
- ],
- "cluster-management-client": [
- "standard-role",
- "base-role"
- ],
- "registry-client": [
- "registry-editor-role"
- ]
- }
- },
- {
- "name": "edge-operator-group",
- "path": "/edge-operator-group",
- "realmRoles": [
- "app-service-proxy-read-role",
- "app-service-proxy-write-role",
- "app-deployment-manager-read-role",
- "app-deployment-manager-write-role",
- "app-resource-manager-read-role",
- "app-resource-manager-write-role",
- "app-vm-console-write-role",
- "catalog-publisher-read-role",
- "catalog-other-read-role",
- "clusters-read-role",
- "clusters-write-role",
- "cluster-templates-read-role",
- "cluster-artifacts-read-role",
- "cluster-artifacts-write-role",
- "infra-manager-core-read-role",
- "alrt-r"
- ],
- "clientRoles": {
- "telemetry-client": [
- "viewer"
- ],
- "registry-client": [
- "registry-viewer-role"
- ]
- }
- },
- {
- "name": "host-manager-group",
- "path": "/host-manager-group",
- "realmRoles": [
- "infra-manager-core-read-role",
- "infra-manager-core-write-role"
- ],
- "clientRoles": {
- "telemetry-client": [
- "viewer"
- ]
- }
- },
- {
- "name": "sre-group",
- "path": "/sre-group",
- "realmRoles": [
- "alrt-r",
- "clusters-read-role",
- "clusters-write-role",
- "cluster-templates-read-role",
- "infra-manager-core-read-role"
- ],
- "clientRoles": {
- "telemetry-client": [
- "viewer"
- ],
- "cluster-management-client": [
- "base-role",
- "restricted-role"
- ]
- }
- }
- ],
- "users": [
- {
- "username": "service-account-alerts-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "alerts-m2m-client",
- "realmRoles": [
- "default-roles-master"
- ],
- "clientRoles": {
- "alerts-m2m-client": [
- "uma_protection"
- ],
- "master-realm": [
- "view-users"
- ]
- },
- "notBefore": 0
- },
- {
- "username": "service-account-host-manager-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "host-manager-m2m-client",
- "realmRoles": [
- "default-roles-master",
- "rs-access-r"
- ],
- "clientRoles": {
- "host-manager-m2m-client": [
- "uma_protection"
- ],
- "master-realm": [
- "query-clients",
- "manage-authorization",
- "view-clients",
- "view-users",
- "create-client",
- "manage-users",
- "manage-clients",
- "view-realm"
- ]
- },
- "notBefore": 0
- },
- {
- "username": "service-account-co-manager-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "co-manager-m2m-client",
- "realmRoles": [
- "default-roles-master"
- ],
- "clientRoles": {
- "co-manager-m2m-client": [
- "uma_protection"
- ],
- "master-realm": [
- "view-clients",
- "manage-clients"
- ]
- },
- "notBefore": 0,
- "groups": [
- "/edge-manager-group",
- "/apps-m2m-service-account"
- ]
- },
- {
- "username": "service-account-ktc-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "ktc-m2m-client",
- "realmRoles": [
- "admin",
- "create-realm",
- "default-roles-master",
- "rs-access-r"
- ],
- "clientRoles": {
- "ktc-m2m-client": [
- "uma_protection"
- ],
- "master-realm": [
- "query-clients",
- "manage-authorization",
- "view-clients",
- "view-users",
- "create-client",
- "manage-users",
- "manage-clients"
- ]
- },
- "notBefore": 0
- },
- {
- "username": "service-account-3rd-party-host-manager-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "3rd-party-host-manager-m2m-client",
- "realmRoles": [
- "default-roles-master",
- "rs-access-r"
- ],
- "clientRoles": {
- "3rd-party-host-manager-m2m-client": [
- "uma_protection"
- ],
- "master-realm": [
- "query-clients",
- "manage-authorization",
- "view-clients",
- "view-users",
- "create-client",
- "manage-users",
- "manage-clients",
- "view-realm",
- ]
- },
- "notBefore": 0
- },
- {
- "username": "service-account-en-m2m-template-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "en-m2m-template-client",
- "realmRoles": [
- "default-roles-master",
- "rs-access-r",
- "en-agent-rw"
- ],
- "clientRoles": {
- "en-m2m-template-client": [
- "uma_protection"
- ]
- },
- "notBefore": 0
- },
- {
- "username": "service-account-edge-manager-m2m-client",
- "enabled": true,
- "totp": false,
- "serviceAccountClientId": "edge-manager-m2m-client",
- "realmRoles": [
- "default-roles-master"
- ],
- "clientRoles": {
- "edge-manager-m2m-client": [
- "uma_protection"
- ]
- },
- "notBefore": 0,
- "groups": [
- "/edge-manager-group",
- "/apps-m2m-service-account"
- ]
- },
- ],
- "components": {
- "org.keycloak.keys.KeyProvider": [
- {
- "name": "fallback-PS512",
- "providerId": "rsa-generated",
- "subComponents": {},
- "config": {
- "keySize": [
- "4096"
- ],
- "active": [
- "true"
- ],
- "priority": [
- "-100"
- ],
- "enabled": [
- "true"
- ],
- "algorithm": [
- "PS512"
- ]
- }
- }
- ]
- }
- }
-# yamllint enable rule:line-length
+# ArgoCD configuration for cluster-specific overrides
+argo:
+ # Cluster domain suffix for dynamic URL generation
+ clusterDomain: "kind.internal"
diff --git a/argocd/applications/configs/secrets-config.yaml b/argocd/applications/configs/secrets-config.yaml
index 68e1da9fc..90c37074e 100644
--- a/argocd/applications/configs/secrets-config.yaml
+++ b/argocd/applications/configs/secrets-config.yaml
@@ -6,6 +6,6 @@ auth:
orchSvcs:
roleMaxTTL: 1h
oidc:
- idPAddr: "http://platform-keycloak.orch-platform.svc"
- idPDiscoveryURL: "http://platform-keycloak.orch-platform.svc/realms/master"
+ idPAddr: "http://platform-keycloak.keycloak-system.svc.cluster.local"
+ idPDiscoveryURL: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master"
roleMaxTTL: 1h
diff --git a/argocd/applications/configs/token-fs.yaml b/argocd/applications/configs/token-fs.yaml
index 27a87a5fc..9fb2d733f 100644
--- a/argocd/applications/configs/token-fs.yaml
+++ b/argocd/applications/configs/token-fs.yaml
@@ -6,3 +6,5 @@ tlsOption: "gateway-tls"
# https://doc.traefik.io/traefik/migrate/v2-to-v3-details/#kubernetes-crds-api-group-traefikcontainous
traefikApiGroup: "traefik.io/v1alpha1"
+
+jwksURL: "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master/protocol/openid-connect/certs"
diff --git a/argocd/applications/configs/traefik-extra-objects.yaml b/argocd/applications/configs/traefik-extra-objects.yaml
index 27a87a5fc..27d2b37c7 100644
--- a/argocd/applications/configs/traefik-extra-objects.yaml
+++ b/argocd/applications/configs/traefik-extra-objects.yaml
@@ -6,3 +6,5 @@ tlsOption: "gateway-tls"
# https://doc.traefik.io/traefik/migrate/v2-to-v3-details/#kubernetes-crds-api-group-traefikcontainous
traefikApiGroup: "traefik.io/v1alpha1"
+
+keycloakJwksUrl: http://platform-keycloak.keycloak-system.svc
diff --git a/argocd/applications/configs/traefik.yaml b/argocd/applications/configs/traefik.yaml
index 2615a1bcb..4f58cd94c 100644
--- a/argocd/applications/configs/traefik.yaml
+++ b/argocd/applications/configs/traefik.yaml
@@ -19,6 +19,7 @@ providers:
- "orch-ui"
- "orch-secret"
- "orch-iam"
+ - "keycloak-system"
ingressRoute:
dashboard:
enabled: false
diff --git a/argocd/applications/custom/cluster-manager.tpl b/argocd/applications/custom/cluster-manager.tpl
index b43c4fb75..40561efea 100644
--- a/argocd/applications/custom/cluster-manager.tpl
+++ b/argocd/applications/custom/cluster-manager.tpl
@@ -2,6 +2,13 @@
#
# SPDX-License-Identifier: Apache-2.0
+# Keycloak internal service URL
+{{- $keycloakUrl := "http://platform-keycloak.keycloak-system.svc.cluster.local/realms/master" }}
+{{- $keycloakHost := "platform-keycloak.keycloak-system.svc.cluster.local" }}
+
+openidc:
+ issuer: {{ $keycloakUrl }}
+
clusterManager:
args:
clusterdomain: {{ .Values.argo.clusterDomain }}
@@ -9,6 +16,30 @@ clusterManager:
# If kubeconfig-ttl-hours=0 token expires at creation
# keycloak realm settings and upbounded by the SSO sessions max: 12h
kubeconfig-ttl-hours: 3
+ # Add init container to wait for Keycloak to be ready
+ # This prevents cluster-manager from crashing when Keycloak is not ready
+ initContainers:
+ - name: wait-for-keycloak
+ image: curlimages/curl:8.5.0
+ command:
+ - sh
+ - -c
+ - |
+ echo "Waiting for Keycloak at {{ $keycloakHost }} to be ready..."
+ until curl --fail --connect-timeout 5 --max-time 10 -s {{ $keycloakUrl }} > /dev/null 2>&1; do
+ echo "Keycloak not ready yet, retrying in 5 seconds..."
+ sleep 5
+ done
+ echo "Keycloak is ready!"
+ securityContext:
+ runAsNonRoot: true
+ runAsUser: 65534
+ allowPrivilegeEscalation: false
+ seccompProfile:
+ type: RuntimeDefault
+ capabilities:
+ drop:
+ - ALL
image:
repository: cluster/cluster-manager
registry:
@@ -63,7 +94,7 @@ credentialsM2M:
authPath: "auth/kubernetes"
keycloak:
- service: "platform-keycloak.orch-platform.svc.cluster.local" # internal k8s DNS always uses cluster.local
+ service: "platform-keycloak.keycloak-system.svc.cluster.local" # internal k8s DNS always uses cluster.local
port: 8080
realm: "master"
adminSecretName: "platform-keycloak"
diff --git a/argocd/applications/custom/copy-db-to-keycloak-ns.tpl b/argocd/applications/custom/copy-db-to-keycloak-ns.tpl
new file mode 100644
index 000000000..0afba85a3
--- /dev/null
+++ b/argocd/applications/custom/copy-db-to-keycloak-ns.tpl
@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+sourceSecretName: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+targetSecretName: platform-keycloak-{{.Values.argo.database.type}}-postgresql
diff --git a/argocd/applications/custom/keycloak-operator.tpl b/argocd/applications/custom/keycloak-operator.tpl
new file mode 100644
index 000000000..32f150256
--- /dev/null
+++ b/argocd/applications/custom/keycloak-operator.tpl
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# Custom overrides for keycloak-operator deployment
+# This template applies cluster-specific customizations on top of base configuration
+
+# Override operator deployment resources if specified
+{{- if and .Values.argo .Values.argo.resources .Values.argo.resources.keycloakOperator }}
+operator:
+ container:
+ resources:
+ {{- toYaml .Values.argo.resources.keycloakOperator | nindent 6 }}
+{{- end }}
+
+# Override operator replicas if specified
+{{- if and .Values.argo .Values.argo.keycloakOperator .Values.argo.keycloakOperator.replicas }}
+operator:
+ replicas: {{ .Values.argo.keycloakOperator.replicas }}
+{{- end }}
+
+# Override operator image if specified
+{{- if and .Values.argo .Values.argo.keycloakOperator .Values.argo.keycloakOperator.image }}
+operator:
+ image: {{ .Values.argo.keycloakOperator.image | quote }}
+{{- end }}
+
+# Override operator imagePullSecrets if specified
+{{- if and .Values.argo .Values.argo.keycloakOperator .Values.argo.keycloakOperator.imagePullSecrets }}
+imagePullSecrets:
+ {{- toYaml .Values.argo.keycloakOperator.imagePullSecrets | nindent 2 }}
+{{- end }}
diff --git a/argocd/applications/custom/keycloak-tenant-controller.tpl b/argocd/applications/custom/keycloak-tenant-controller.tpl
index bacd77237..aeb10a677 100644
--- a/argocd/applications/custom/keycloak-tenant-controller.tpl
+++ b/argocd/applications/custom/keycloak-tenant-controller.tpl
@@ -33,6 +33,8 @@ keycloakAdmin:
passwordSecret:
name: platform-keycloak # name of the secret
key: admin-password # key of the secret
+ # URL pointing to Keycloak in keycloak-system namespace (migration from orch-platform)
+ url: "http://platform-keycloak.keycloak-system.svc:8080"
keycloak_realm: "master"
argo:
clusterDomain: {{.Values.argo.clusterDomain}}
diff --git a/argocd/applications/custom/platform-keycloak.tpl b/argocd/applications/custom/platform-keycloak.tpl
index b053f6132..1e031304e 100644
--- a/argocd/applications/custom/platform-keycloak.tpl
+++ b/argocd/applications/custom/platform-keycloak.tpl
@@ -2,64 +2,1477 @@
#
# SPDX-License-Identifier: Apache-2.0
-## Cluster-Specific values
-## These values are not part of bitnami helm chart and are used to parameterize substrings in
-## the larger keycloakConfigCli.configuration.realm-master.json value.
-## @param clusterSpecific.webuiClientRootUrl The Keycloak Master realm UI Client's rootUrl value as a quoted JSON string
-## @param clusterSpecific.webuiRedirectUrls The Keycloak Master realm UI Client's reirectUrl values as a JSON array of quoted JSON strings
-## @param clusterSpecific.registryClientRootUrl The Keycloak Master realm Harbor Client's rootUrl value as a quoted JSON string
-## @param clusterSpecific.telemetryClientRootUrl The Keycloak Master realm Grafana Client's rootUrl value as a quoted JSON string
-## @param clusterSpecific.telemetryRedirectUrls The Keycloak Master realm Grafana Client's reirectUrl values as a JSON array of quoted JSON strings
-clusterSpecific:
- webuiClientRootUrl: "https://web-ui.{{ .Values.argo.clusterDomain }}"
- webuiRedirectUrls: ["https://web-ui.{{ .Values.argo.clusterDomain }}", "https://app-service-proxy.{{ .Values.argo.clusterDomain }}/app-service-proxy-index.html*", "https://vnc.{{ .Values.argo.clusterDomain }}/*", "https://{{ .Values.argo.clusterDomain }}"{{- if index .Values.argo "platform-keycloak" "extraUiRedirects" -}}, {{- index .Values.argo "platform-keycloak" "extraUiRedirects" -}}{{- end -}}]
- registryClientRootUrl: "https://registry-oci.{{ .Values.argo.clusterDomain }}"
- telemetryClientRootUrl: "https://observability-ui.{{ .Values.argo.clusterDomain }}"
- telemetryRedirectUrls: ["https://observability-admin.{{ .Values.argo.clusterDomain }}/login/generic_oauth", "https://observability-ui.{{ .Values.argo.clusterDomain }}/login/generic_oauth"]
-
-## External PostgreSQL configuration
-## All of these values are only used when postgresql.enabled is set to false
-## @param externalDatabase.existingSecret Name of an existing secret resource containing the database credentials
-## @param externalDatabase.existingSecretHostKey Name of an existing secret key containing the database host name
-## @param externalDatabase.existingSecretPortKey Name of an existing secret key containing the database port
-## @param externalDatabase.existingSecretUserKey Name of an existing secret key containing the database user
-## @param externalDatabase.existingSecretDatabaseKey Name of an existing secret key containing the database name
-## @param externalDatabase.existingSecretPasswordKey Name of an existing secret key containing the database credentials
-externalDatabase:
- existingSecret: platform-keycloak-{{.Values.argo.database.type}}-postgresql
- existingSecretHostKey: PGHOST
- existingSecretPortKey: PGPORT
- existingSecretUserKey: PGUSER
- existingSecretDatabaseKey: PGDATABASE
- existingSecretPasswordKey: PGPASSWORD
-
-# Use index to handle values with hyphen
-{{- if index .Values.argo "platform-keycloak" "localRegistrySize"}}
-persistence:
- persistentVolumeClaim:
- registry:
- size: {{index .Values.argo "platform-keycloak" "localRegistrySize"}}
-{{- end}}
-
-extraEnvVars:
- - name: HTTPS_PROXY
- value: {{.Values.argo.proxy.httpsProxy}}
- - name: HTTP_PROXY
- value: {{.Values.argo.proxy.httpProxy}}
- - name: NO_PROXY
- value: {{.Values.argo.proxy.noProxy}}
- {{ if index .Values.argo "platform-keycloak" "db" }}
- - name: KC_DB_POOL_INITIAL_SIZE
- value: {{ index .Values.argo "platform-keycloak" "db" "poolInitSize" | default "5" | quote}}
- - name: KC_DB_POOL_MIN_SIZE
- value: {{ index .Values.argo "platform-keycloak" "db" "poolMinSize" | default "5" | quote}}
- - name: KC_DB_POOL_MAX_SIZE
- value: {{ index .Values.argo "platform-keycloak" "db" "poolMaxSize" | default "100" | quote}}
- {{ end }}
- - name: KC_PROXY_HEADERS
- value: "xforwarded"
-
-{{- with .Values.argo.resources.platformKeycloak }}
-resources:
- {{- toYaml . | nindent 2}}
+
+# Keycloak instance configuration (Keycloak CRD)
+keycloak:
+ # Container image (uses upstream version from Chart.yaml)
+ image: "quay.io/keycloak/keycloak:26.4.5"
+ imagePullPolicy: IfNotPresent
+
+ # Bootstrap admin credentials
+ bootstrapAdmin:
+ secret: platform-keycloak
+
+ # Database configuration
+ database:
+ vendor: postgres
+ usernameSecret:
+ name: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+ key: PGUSER
+ passwordSecret:
+ name: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+ key: PGPASSWORD
+ # Connection pool settings
+ poolInitialSize: 5
+ poolMinSize: 5
+ poolMaxSize: 50
+
+ # HTTP configuration
+ http:
+ httpEnabled: true
+ httpPort: 8080
+ relativeUrl: "/"
+
+ # Proxy headers for reverse proxy
+ proxy:
+ headers: xforwarded
+
+ # Ingress configuration
+ ingress:
+ enabled: false
+
+ # Pod resource allocation
+ resources:
+ requests:
+ cpu: 500m
+ memory: 512Mi
+ limits:
+ cpu: 2000m
+ memory: 2Gi
+
+ # Runtime configuration options
+ additionalOptions:
+ # Read database connection details from secret
+ - name: db-url-host
+ secret:
+ name: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+ key: PGHOST
+ - name: db-url-port
+ secret:
+ name: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+ key: PGPORT
+ - name: db-url-database
+ secret:
+ name: platform-keycloak-{{.Values.argo.database.type}}-postgresql
+ key: PGDATABASE
+ - name: hostname-strict
+ value: "false"
+ - name: http-relative-path
+ value: "/"
+ - name: http-enabled
+ value: "true"
+ - name: db-url-properties
+ value: "?tcpKeepAlives=true&socketTimeout=120&connectTimeout=120"
+ - name: http-management-port
+ value: "9000"
+ - name: spi-login-protocol-openid-connect-legacy-logout-redirect-uri
+ value: "true"
+ - name: spi-brute-force-protector-default-brute-force-detector-allow-concurrent-requests
+ value: "true"
+ - name: log-level
+ value: "INFO"
+ - name: log-console-output
+ value: "json"
+
+ # Pod optimization
+ startOptimized: true
+ instances: 1
+
+ # Pod template security and initialization
+ podTemplate:
+ # Pod security context
+ securityContext:
+ runAsUser: 1000
+ runAsGroup: 1000
+ fsGroup: 1000
+ seccompProfile:
+ type: RuntimeDefault
+
+ # Init container for building optimized Keycloak image
+ initContainers:
+ - name: keycloak-builder
+ image: "quay.io/keycloak/keycloak:26.4.5"
+ imagePullPolicy: IfNotPresent
+ command:
+ - /bin/bash
+ args:
+ - -c
+ - |
+ set -e
+ /opt/keycloak/bin/kc.sh build \
+ --db=postgres \
+ --health-enabled=true \
+ --metrics-enabled=true \
+ --http-relative-path=/
+
+ mkdir -p /shared/keycloak
+ cp -r /opt/keycloak/* /shared/keycloak/
+
+ resources:
+ requests:
+ cpu: 500m
+ memory: 512Mi
+ limits:
+ cpu: 1500m
+ memory: 1Gi
+
+ securityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: false
+ runAsNonRoot: true
+ runAsUser: 1000
+ runAsGroup: 1000
+ capabilities:
+ drop:
+ - ALL
+ seccompProfile:
+ type: RuntimeDefault
+
+ volumeMounts:
+ - name: shared-keycloak
+ mountPath: /shared/keycloak
+ - name: tmp
+ mountPath: /tmp
+
+ # Main container security context
+ containerSecurityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+ runAsGroup: 1000
+ capabilities:
+ drop:
+ - ALL
+ seccompProfile:
+ type: RuntimeDefault
+
+ # Container volume mounts
+ containerVolumeMounts:
+ - name: shared-keycloak
+ mountPath: /opt/keycloak
+ readOnly: true
+ - name: tmp
+ mountPath: /tmp
+ - name: keycloak-data
+ mountPath: /opt/keycloak/data
+
+ # Pod volumes
+ volumes:
+ - name: shared-keycloak
+ emptyDir:
+ sizeLimit: 1Gi
+ - name: tmp
+ emptyDir:
+ sizeLimit: 100Mi
+ - name: keycloak-data
+ emptyDir:
+ sizeLimit: 500Mi
+{{- if and .Values.argo .Values.argo.resources .Values.argo.resources.platformKeycloak }}
+ resources:
+ {{- toYaml .Values.argo.resources.platformKeycloak | nindent 4 }}
{{- end }}
+
+## These values are used to configure:
+## 1. Realm import configuration (clients, redirect URIs, etc.)
+## 2. Keycloak instance deployment parameters
+
+{{- $clusterDomain := .Values.argo.clusterDomain -}}
+{{- $extraUiRedirects := index .Values.argo "platform-keycloak" "extraUiRedirects" -}}
+{{- $webuiRootUrl := printf "https://web-ui.%s" $clusterDomain -}}
+{{- $docsuiRootUrl := printf "https://docs-ui.%s" $clusterDomain -}}
+{{- $registryRootUrl := printf "https://registry-oci.%s" $clusterDomain -}}
+{{- $telemetryRootUrl := printf "https://observability-ui.%s" $clusterDomain -}}
+{{- $clusterMgmtRootUrl := printf "https://cluster-management.%s" $clusterDomain -}}
+{{- $webuiRedirects := list (printf "https://web-ui.%s" $clusterDomain) (printf "https://app-service-proxy.%s/app-service-proxy-index.html*" $clusterDomain) (printf "https://vnc.%s/*" $clusterDomain) (printf "https://%s" $clusterDomain) -}}
+{{- if $extraUiRedirects -}}
+ {{- $webuiRedirects = append $webuiRedirects $extraUiRedirects -}}
+{{- end -}}
+{{- $docsuiRedirects := list (printf "https://docs-ui.%s" $clusterDomain) (printf "https://docs-ui.%s/" $clusterDomain) -}}
+{{- $telemetryRedirects := list (printf "https://observability-admin.%s/login/generic_oauth" $clusterDomain) (printf "https://observability-ui.%s/login/generic_oauth" $clusterDomain) -}}
+{{- $clusterMgmtRedirects := list (printf "https://cluster-management.%s" $clusterDomain) (printf "https://cluster-management.%s/" $clusterDomain) -}}
+
+# Override Keycloak Config CLI resources if specified
+{{- if and .Values.argo .Values.argo.resources .Values.argo.resources.keycloakConfigCli }}
+keycloakConfigCli:
+ job:
+ container:
+ resources:
+ {{- toYaml .Values.argo.resources.keycloakConfigCli | nindent 8 }}
+{{- end }}
+
+# Override cluster domain if specified (for URL generation)
+{{- if and .Values.argo .Values.argo.clusterDomain }}
+argo:
+ clusterDomain: {{ .Values.argo.clusterDomain | quote }}
+{{- end }}
+
+# Override Keycloak Config CLI environment variables to include proxy settings
+keycloakConfigCli:
+ job:
+ container:
+ env:
+ - name: KEYCLOAK_URL
+ value: "http://platform-keycloak.keycloak-system.svc.cluster.local/"
+ - name: KEYCLOAK_USER
+ value: "admin"
+ - name: KEYCLOAK_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: platform-keycloak
+ key: password
+ - name: KEYCLOAK_AVAILABILITYCHECK_ENABLED
+ value: "true"
+ - name: KEYCLOAK_AVAILABILITYCHECK_TIMEOUT
+ value: "120s"
+ - name: IMPORT_VARSUBSTITUTION_ENABLED
+ value: "true"
+ - name: IMPORT_FILES_LOCATIONS
+ value: "/config/*"
+ - name: IMPORT_MANAGED_GROUP
+ value: "no-delete"
+ - name: IMPORT_MANAGED_REQUIRED_ACTION
+ value: "no-delete"
+ - name: IMPORT_MANAGED_ROLE
+ value: "no-delete"
+ - name: IMPORT_MANAGED_CLIENT
+ value: "no-delete"
+ - name: IMPORT_REMOTE_STATE_ENABLED
+ value: "true"
+ - name: LOGGING_LEVEL_ROOT
+ value: "INFO"
+ - name: LOGGING_LEVEL_KEYCLOAKCONFIGCLI
+ value: "DEBUG"
+ {{- if .Values.argo.proxy.httpsProxy }}
+ - name: HTTPS_PROXY
+ value: {{ .Values.argo.proxy.httpsProxy | quote }}
+ {{- end }}
+ {{- if .Values.argo.proxy.httpProxy }}
+ - name: HTTP_PROXY
+ value: {{ .Values.argo.proxy.httpProxy | quote }}
+ {{- end }}
+ {{- if .Values.argo.proxy.noProxy }}
+ - name: NO_PROXY
+ value: {{ .Values.argo.proxy.noProxy | quote }}
+ {{- end }}
+
+# Override realmMaster configuration with properly resolved clusterSpecific values
+# This overrides the base config's realmMaster so template variables get resolved
+realmMaster: |
+ {
+ "realm": "master",
+ "accountTheme": "keycloak",
+ "displayName": "Keycloak",
+ "displayNameHtml": "
",
+ "defaultSignatureAlgorithm": "PS512",
+ "accessTokenLifespan": 3600,
+ "ssoSessionIdleTimeout": 5400,
+ "ssoSessionMaxLifespan": 43200,
+ "passwordPolicy": "length(14) and digits(1) and specialChars(1) and upperCase(1) and lowerCase(1)",
+ "bruteForceProtected": true,
+ "permanentLockout": false,
+ "maxFailureWaitSeconds": 900,
+ "minimumQuickLoginWaitSeconds": 60,
+ "waitIncrementSeconds": 300,
+ "quickLoginCheckMilliSeconds": 200,
+ "maxDeltaTimeSeconds": 43200,
+ "failureFactor": 5,
+ "roles": {
+ "realm": [
+ {
+ "name": "en-agent-rw"
+ },
+ {
+ "name": "secrets-root-role"
+ },
+ {
+ "name": "rs-access-r"
+ },
+ {
+ "name": "rs-proxy-r"
+ },
+ {
+ "name": "app-service-proxy-read-role"
+ },
+ {
+ "name": "app-service-proxy-write-role"
+ },
+ {
+ "name": "app-deployment-manager-read-role"
+ },
+ {
+ "name": "app-deployment-manager-write-role"
+ },
+ {
+ "name": "app-resource-manager-read-role"
+ },
+ {
+ "name": "app-resource-manager-write-role"
+ },
+ {
+ "name": "app-vm-console-write-role"
+ },
+ {
+ "name": "catalog-publisher-read-role"
+ },
+ {
+ "name": "catalog-publisher-write-role"
+ },
+ {
+ "name": "catalog-other-read-role"
+ },
+ {
+ "name": "catalog-other-write-role"
+ },
+ {
+ "name": "catalog-restricted-read-role"
+ },
+ {
+ "name": "catalog-restricted-write-role"
+ },
+ {
+ "name": "clusters-read-role"
+ },
+ {
+ "name": "clusters-write-role"
+ },
+ {
+ "name": "cluster-templates-read-role"
+ },
+ {
+ "name": "cluster-templates-write-role"
+ },
+ {
+ "name": "cluster-artifacts-read-role"
+ },
+ {
+ "name": "cluster-artifacts-write-role"
+ },
+ {
+ "name": "infra-manager-core-read-role"
+ },
+ {
+ "name": "infra-manager-core-write-role"
+ },
+ {
+ "name": "alrt-r"
+ },
+ {
+ "name": "alrt-rw"
+ },
+ {
+ "name": "alrt-rx-rw"
+ },
+ {
+ "name": "ao-m2m-rw"
+ },
+ {
+ "name": "co-m2m-rw"
+ },
+ {
+ "name": "org-read-role"
+ },
+ {
+ "name": "org-write-role"
+ },
+ {
+ "name": "org-update-role"
+ },
+ {
+ "name": "org-delete-role"
+ }
+ ],
+ "client": {
+ "alerts-m2m-client": [],
+ "host-manager-m2m-client": [],
+ "co-manager-m2m-client": [],
+ "ktc-m2m-client": [],
+ "3rd-party-host-manager-m2m-client": [],
+ "edge-manager-m2m-client": [],
+ "en-m2m-template-client": [],
+ "webui-client": [],
+ "docsui-client": [],
+ "account": [
+ {
+ "name": "view-profile",
+ "clientRole": true
+ },
+ {
+ "name": "manage-account",
+ "clientRole": true
+ }
+ ],
+ "telemetry-client": [
+ {
+ "name": "admin",
+ "clientRole": true
+ },
+ {
+ "name": "viewer",
+ "clientRole": true
+ }
+ ],
+ "cluster-management-client": [
+ {
+ "name": "restricted-role",
+ "clientRole": true
+ },
+ {
+ "name": "standard-role",
+ "clientRole": true
+ },
+ {
+ "name": "base-role",
+ "clientRole": true
+ }
+ ],
+ "registry-client": [
+ {
+ "name": "registry-admin-role",
+ "clientRole": true
+ },
+ {
+ "name": "registry-editor-role",
+ "clientRole": true
+ },
+ {
+ "name": "registry-viewer-role",
+ "clientRole": true
+ }
+ ]
+ }
+ },
+ "clients": [
+ {
+ "clientId": "alerts-m2m-client",
+ "name": "Alerts M2M Client",
+ "description": "Client for Alerts",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "clientId": "host-manager-m2m-client",
+ "name": "Host Manager Client",
+ "description": "Client for the EN Host Manager to use in creating edgenode m2m clients",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "clientId": "co-manager-m2m-client",
+ "name": "Cluster Orchestrator Manager M2M Client",
+ "description": "Client for cluster-manager to access Keycloak for JWT TTL management",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email",
+ "basic",
+ "groups"
+ ],
+ "optionalClientScopes": [
+ "offline_access"
+ ]
+ },
+ {
+ "clientId": "ktc-m2m-client",
+ "name": "Keycloak Tenant Controller client",
+ "description": "Client for the Keycloak Tenant Controller to use in creating Tenant specific roles and groups in Keycloak",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "groups",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "clientId": "3rd-party-host-manager-m2m-client",
+ "name": "3rd Party Host Manager Client",
+ "description": "Client for the 3rd party Host Manager to use in creating edgenode m2m clients",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "clientId": "edge-manager-m2m-client",
+ "name": "Edge Manager M2M Client",
+ "description": "Client for the accessing Orchestrator with Edge-Manager persona",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "roles",
+ "email",
+ "groups",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "offline_access",
+ ]
+ },
+ {
+ "clientId": "en-m2m-template-client",
+ "name": "Edge Node M2M Template Client",
+ "description": "Client to use as basis for Roles to assign to new Edge Node M2M clients",
+ "surrogateAuthRequired": false,
+ "enabled": false,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "clientId": "telemetry-client",
+ "name": "Telemetry Client",
+ "rootUrl": "{{ $telemetryRootUrl }}",
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": {{ $telemetryRedirects | toJson }},
+ "webOrigins": [
+ "+"
+ ],
+ "protocol": "openid-connect",
+ "directAccessGrantsEnabled": true,
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "client.secret.creation.time": "1683218404",
+ "backchannel.logout.session.required": "true",
+ "post.logout.redirect.uris": "+",
+ "display.on.consent.screen": "false",
+ "use.jwks.url": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "roles",
+ "profile",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "groups",
+ "offline_access"
+ ]
+ },
+ {
+ "clientId": "cluster-management-client",
+ "name": "Cluster Management Client",
+ "rootUrl": "{{ $clusterMgmtRootUrl }}",
+ "adminUrl": "{{ $clusterMgmtRootUrl }}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": {{ $clusterMgmtRedirects | toJson }},
+ "webOrigins": [
+ "+"
+ ],
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false",
+ "use.refresh.tokens": "true",
+ "oidc.ciba.grant.enabled": "false",
+ "backchannel.logout.session.required": "true",
+ "client_credentials.use_refresh_token": "false",
+ "require.pushed.authorization.requests": "false",
+ "tls.client.certificate.bound.access.tokens": "false",
+ "display.on.consent.screen": "false",
+ "token.response.type.bearer.lower-case": "false",
+ },
+ "fullScopeAllowed": true,
+ "protocolMappers": [
+ {
+ "name": "Group Path",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-group-membership-mapper",
+ "consentRequired": false,
+ "config": {
+ "full.path": "true",
+ "id.token.claim": "false",
+ "access.token.claim": "false",
+ "claim.name": "full_group_path",
+ "userinfo.token.claim": "true"
+ }
+ },
+ {
+ "name": "Groups Mapper",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-group-membership-mapper",
+ "consentRequired": false,
+ "config": {
+ "full.path": "false",
+ "id.token.claim": "false",
+ "access.token.claim": "false",
+ "claim.name": "groups",
+ "userinfo.token.claim": "true"
+ }
+ },
+ {
+ "name": "Client Audience",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-mapper",
+ "consentRequired": false,
+ "config": {
+ "included.client.audience": "cluster-management-client",
+ "id.token.claim": "false",
+ "access.token.claim": "true"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "profile",
+ "roles",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "groups",
+ "offline_access",
+ ],
+ "authorizationServicesEnabled": false
+ },
+ {
+ "clientId": "webui-client",
+ "name": "WebUI Client",
+ "rootUrl": "{{ $webuiRootUrl }}",
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": {{ $webuiRedirects | toJson }},
+ "webOrigins": [
+ "+"
+ ],
+ "protocol": "openid-connect",
+ "directAccessGrantsEnabled": false,
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "client.secret.creation.time": "1683218404",
+ "backchannel.logout.session.required": "true",
+ "post.logout.redirect.uris": "+",
+ "display.on.consent.screen": "false",
+ "oauth2.device.authorization.grant.enabled": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "roles",
+ "profile",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "groups",
+ "offline_access"
+ ]
+ },
+ {
+ "clientId": "docsui-client",
+ "name": "DocsUI Client",
+ "rootUrl": "{{ $docsuiRootUrl }}",
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": {{ $docsuiRedirects | toJson }},
+ "webOrigins": [
+ "+"
+ ],
+ "protocol": "openid-connect",
+ "directAccessGrantsEnabled": false,
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "client.secret.creation.time": "1683218404",
+ "backchannel.logout.session.required": "true",
+ "post.logout.redirect.uris": "+",
+ "display.on.consent.screen": "false",
+ "oauth2.device.authorization.grant.enabled": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "roles",
+ "profile",
+ "email",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "groups",
+ "offline_access"
+ ]
+ },
+ {
+ "clientId": "system-client",
+ "name": "System Client",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [],
+ "webOrigins": [],
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "true",
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "openid",
+ "profile",
+ "email",
+ "groups",
+ "roles",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "offline_access"
+ ]
+ },
+ {
+ "frontchannelLogout": true,
+ "standardFlowEnabled": true,
+ "clientId": "registry-client",
+ "name": "Registry Client",
+ "rootUrl": "{{ $registryRootUrl }}",
+ "enabled": true,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "/c/oidc/callback"
+ ],
+ "webOrigins": [
+ "+"
+ ],
+ "protocol": "openid-connect",
+ "directAccessGrantsEnabled": true,
+ "attributes": {
+ "oidc.ciba.grant.enabled": "false",
+ "client.secret.creation.time": "1683218404",
+ "backchannel.logout.session.required": "true",
+ "post.logout.redirect.uris": "+",
+ "display.on.consent.screen": "false",
+ "use.jwks.url": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "fullScopeAllowed": true,
+ "defaultClientScopes": [
+ "roles",
+ "profile",
+ "email",
+ "groups",
+ "basic"
+ ],
+ "optionalClientScopes": [
+ "offline_access"
+ ]
+ }
+ ],
+ "clientScopes": [
+ {
+ "name": "openid",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true"
+ }
+ },
+ {
+ "name": "profile",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true"
+ }
+ },
+ {
+ "name": "email",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true"
+ }
+ },
+ {
+ "name": "basic",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true"
+ }
+ },
+ {
+ "name": "offline_access",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true"
+ }
+ },
+ {
+ "name": "groups",
+ "description": "Groups scope",
+ "type": "Optional",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "name": "groups",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-group-membership-mapper",
+ "consentRequired": false,
+ "config": {
+ "multivalued": "true",
+ "full.path": "false",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "groups",
+ "userinfo.token.claim": "true",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "name": "roles",
+ "description": "OpenID Connect scope for add user roles to the access token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true",
+ "gui.order": "",
+ "consent.screen.text": '{{"$"}}{{"{"}}roleScopeConsentText{{"}"}}'
+ },
+ "protocolMappers": [
+ {
+ "name": "realm roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-realm-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "multivalued": "true",
+ "userinfo.token.claim": "true",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "realm_access.roles",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "name": "client roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-client-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "multivalued": "true",
+ "userinfo.token.claim": "true",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "resource_access.{{"$"}}{{"{"}}client_id{{"}"}}.roles",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ }
+ ],
+ "groups": [
+ {
+ "name": "registry-app-admin-group",
+ "path": "/registry-app-admin-group",
+ },
+ {
+ "name": "registry-app-editor-group",
+ "path": "/registry-app-editor-group",
+ },
+ {
+ "name": "registry-app-viewer-group",
+ "path": "/registry-app-viewer-group",
+ },
+ {
+ "name": "apps-m2m-service-account",
+ "path": "/apps-m2m-service-account",
+ "realmRoles": [
+ "ao-m2m-rw",
+ "co-m2m-rw"
+ ]
+ },
+ {
+ "name": "org-admin-group",
+ "path": "/org-admin-group",
+ "realmRoles": [
+ "org-read-role",
+ "org-update-role",
+ "org-delete-role",
+ "org-write-role"
+ ]
+ },
+ {
+ "name": "sre-admin-group",
+ "path": "/sre-admin-group",
+ "realmRoles": [
+ "alrt-r"
+ ],
+ "clientRoles": {
+ "account": [
+ "view-profile",
+ "manage-account"
+ ],
+ "telemetry-client": [
+ "viewer"
+ ]
+ }
+ },
+ {
+ "name": "iam-admin-group",
+ "path": "/iam-admin-group",
+ "realmRoles": [
+ "admin",
+ "secrets-root-role"
+ ],
+ "clientRoles": {
+ "account": [
+ "view-profile",
+ "manage-account"
+ ],
+ "master-realm": [
+ "view-users",
+ "query-users",
+ "manage-clients"
+ ]
+ }
+ },
+ {
+ "name": "service-admin-group",
+ "path": "/service-admin-group",
+ "realmRoles": [
+ "alrt-rx-rw",
+ "rs-access-r",
+ "infra-manager-core-read-role",
+ "infra-manager-core-write-role",
+ "alrt-rw"
+ ],
+ "clientRoles": {
+ "account": [
+ "view-profile",
+ "manage-account"
+ ],
+ "master-realm": [
+ "view-users",
+ "query-users",
+ "manage-clients"
+ ],
+ "telemetry-client": [
+ "admin"
+ ],
+ "cluster-management-client": [
+ "restricted-role",
+ "standard-role",
+ "base-role"
+ ],
+ "registry-client": [
+ "registry-admin-role"
+ ]
+ }
+ },
+ {
+ "name": "edge-manager-group",
+ "path": "/edge-manager-group",
+ "realmRoles": [
+ "app-service-proxy-read-role",
+ "app-service-proxy-write-role",
+ "app-deployment-manager-read-role",
+ "app-deployment-manager-write-role",
+ "app-resource-manager-read-role",
+ "app-resource-manager-write-role",
+ "app-vm-console-write-role",
+ "catalog-publisher-read-role",
+ "catalog-publisher-write-role",
+ "catalog-other-read-role",
+ "catalog-other-write-role",
+ "catalog-restricted-read-role",
+ "catalog-restricted-write-role",
+ "clusters-read-role",
+ "clusters-write-role",
+ "cluster-templates-read-role",
+ "cluster-templates-write-role",
+ "cluster-artifacts-read-role",
+ "cluster-artifacts-write-role",
+ "infra-manager-core-read-role",
+ "alrt-rw"
+ ],
+ "clientRoles": {
+ "telemetry-client": [
+ "viewer"
+ ],
+ "cluster-management-client": [
+ "standard-role",
+ "base-role"
+ ],
+ "registry-client": [
+ "registry-editor-role"
+ ]
+ }
+ },
+ {
+ "name": "edge-operator-group",
+ "path": "/edge-operator-group",
+ "realmRoles": [
+ "app-service-proxy-read-role",
+ "app-service-proxy-write-role",
+ "app-deployment-manager-read-role",
+ "app-deployment-manager-write-role",
+ "app-resource-manager-read-role",
+ "app-resource-manager-write-role",
+ "app-vm-console-write-role",
+ "catalog-publisher-read-role",
+ "catalog-other-read-role",
+ "clusters-read-role",
+ "clusters-write-role",
+ "cluster-templates-read-role",
+ "cluster-artifacts-read-role",
+ "cluster-artifacts-write-role",
+ "infra-manager-core-read-role",
+ "alrt-r"
+ ],
+ "clientRoles": {
+ "telemetry-client": [
+ "viewer"
+ ],
+ "registry-client": [
+ "registry-viewer-role"
+ ]
+ }
+ },
+ {
+ "name": "host-manager-group",
+ "path": "/host-manager-group",
+ "realmRoles": [
+ "infra-manager-core-read-role",
+ "infra-manager-core-write-role"
+ ],
+ "clientRoles": {
+ "telemetry-client": [
+ "viewer"
+ ]
+ }
+ },
+ {
+ "name": "sre-group",
+ "path": "/sre-group",
+ "realmRoles": [
+ "alrt-r",
+ "clusters-read-role",
+ "clusters-write-role",
+ "cluster-templates-read-role",
+ "infra-manager-core-read-role"
+ ],
+ "clientRoles": {
+ "telemetry-client": [
+ "viewer"
+ ],
+ "cluster-management-client": [
+ "base-role",
+ "restricted-role"
+ ]
+ }
+ }
+ ],
+ "users": [
+ {
+ "username": "service-account-alerts-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "alerts-m2m-client",
+ "realmRoles": [
+ "default-roles-master"
+ ],
+ "clientRoles": {
+ "alerts-m2m-client": [
+ "uma_protection"
+ ],
+ "master-realm": [
+ "view-users"
+ ]
+ },
+ "notBefore": 0
+ },
+ {
+ "username": "service-account-host-manager-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "host-manager-m2m-client",
+ "realmRoles": [
+ "default-roles-master",
+ "rs-access-r"
+ ],
+ "clientRoles": {
+ "host-manager-m2m-client": [
+ "uma_protection"
+ ],
+ "master-realm": [
+ "query-clients",
+ "manage-authorization",
+ "view-clients",
+ "view-users",
+ "create-client",
+ "manage-users",
+ "manage-clients",
+ "view-realm"
+ ]
+ },
+ "notBefore": 0
+ },
+ {
+ "username": "service-account-co-manager-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "co-manager-m2m-client",
+ "realmRoles": [
+ "default-roles-master"
+ ],
+ "clientRoles": {
+ "co-manager-m2m-client": [
+ "uma_protection"
+ ],
+ "master-realm": [
+ "view-clients",
+ "manage-clients"
+ ]
+ },
+ "notBefore": 0,
+ "groups": [
+ "/edge-manager-group",
+ "/apps-m2m-service-account"
+ ]
+ },
+ {
+ "username": "service-account-ktc-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "ktc-m2m-client",
+ "realmRoles": [
+ "admin",
+ "create-realm",
+ "default-roles-master",
+ "rs-access-r"
+ ],
+ "clientRoles": {
+ "ktc-m2m-client": [
+ "uma_protection"
+ ],
+ "master-realm": [
+ "query-clients",
+ "manage-authorization",
+ "view-clients",
+ "view-users",
+ "create-client",
+ "manage-users",
+ "manage-clients"
+ ]
+ },
+ "notBefore": 0
+ },
+ {
+ "username": "service-account-3rd-party-host-manager-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "3rd-party-host-manager-m2m-client",
+ "realmRoles": [
+ "default-roles-master",
+ "rs-access-r"
+ ],
+ "clientRoles": {
+ "3rd-party-host-manager-m2m-client": [
+ "uma_protection"
+ ],
+ "master-realm": [
+ "query-clients",
+ "manage-authorization",
+ "view-clients",
+ "view-users",
+ "create-client",
+ "manage-users",
+ "manage-clients",
+ "view-realm",
+ ]
+ },
+ "notBefore": 0
+ },
+ {
+ "username": "service-account-en-m2m-template-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "en-m2m-template-client",
+ "realmRoles": [
+ "default-roles-master",
+ "rs-access-r",
+ "en-agent-rw"
+ ],
+ "clientRoles": {
+ "en-m2m-template-client": [
+ "uma_protection"
+ ]
+ },
+ "notBefore": 0
+ },
+ {
+ "username": "service-account-edge-manager-m2m-client",
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "edge-manager-m2m-client",
+ "realmRoles": [
+ "default-roles-master"
+ ],
+ "clientRoles": {
+ "edge-manager-m2m-client": [
+ "uma_protection"
+ ]
+ },
+ "notBefore": 0,
+ "groups": [
+ "/edge-manager-group",
+ "/apps-m2m-service-account"
+ ]
+ },
+ ],
+ "components": {
+ "org.keycloak.keys.KeyProvider": [
+ {
+ "name": "fallback-PS512",
+ "providerId": "rsa-generated",
+ "subComponents": {},
+ "config": {
+ "keySize": [
+ "4096"
+ ],
+ "active": [
+ "true"
+ ],
+ "priority": [
+ "-100"
+ ],
+ "enabled": [
+ "true"
+ ],
+ "algorithm": [
+ "PS512"
+ ]
+ }
+ }
+ ]
+ }
+ }
diff --git a/argocd/applications/custom/self-signed-cert.tpl b/argocd/applications/custom/self-signed-cert.tpl
index edec2c38d..846b11504 100644
--- a/argocd/applications/custom/self-signed-cert.tpl
+++ b/argocd/applications/custom/self-signed-cert.tpl
@@ -4,6 +4,12 @@
certDomain: {{ required "A valid clusterDomain entry required!" .Values.argo.clusterDomain }}
+# DNS names for the TLS certificate (including wildcards for all subdomains)
+# This allows Traefik to serve HTTPS for all services under the cluster domain
+dnsNames:
+ - "keycloak.{{ .Values.argo.clusterDomain }}"
+ - "*.{{ .Values.argo.clusterDomain }}"
+
{{- if index .Values.argo "self-signed-cert"}}
generateOrchCert: {{index .Values.argo "self-signed-cert" "generateOrchCert"}}
{{- end}}
diff --git a/argocd/applications/custom/tenancy-init.tpl b/argocd/applications/custom/tenancy-init.tpl
index 794a39d8f..053262deb 100644
--- a/argocd/applications/custom/tenancy-init.tpl
+++ b/argocd/applications/custom/tenancy-init.tpl
@@ -9,3 +9,14 @@ imagePullSecrets:
{{- with .Values.argo.imagePullSecrets }}
{{- toYaml . | nindent 2 }}
{{- end }}
+
+keycloak:
+ service:
+ name: "platform-keycloak"
+ port: "8080"
+ namespace: "keycloak-system"
+ roles:
+ admin:
+ groups: "Project-Manager-Group"
+ edge:
+ groups: "Edge-Manager-Group,Edge-Onboarding-Group,Edge-Operator-Group,Host-Manager-Group"
diff --git a/argocd/applications/custom/traefik-extra-objects.tpl b/argocd/applications/custom/traefik-extra-objects.tpl
index 084effd48..05bf615d9 100644
--- a/argocd/applications/custom/traefik-extra-objects.tpl
+++ b/argocd/applications/custom/traefik-extra-objects.tpl
@@ -6,10 +6,13 @@
# Revisit this once the porting is done.
orchSecretName: tls-orch
# internal keycloak JWKS URL should be static but providing a way to modify it here
-keycloakJwksUrl: http://platform-keycloak.orch-platform.svc
+keycloakJwksUrl: http://platform-keycloak.keycloak-system.svc
# internal keycloak JWKS Path should be static but providing a way to modify it here
keycloakJwksPath: /realms/master/protocol/openid-connect/certs
keycloakServicePort: 8080
+# Keycloak service configuration for traefik-extra-objects IngressRoute
+keycloakServiceName: platform-keycloak
+keycloakServiceNamespace: keycloak-system
fleetMatchHost: Host(`fleet.{{ .Values.argo.clusterDomain }}`)
harborOciMatchHost: Host(`registry-oci.{{ .Values.argo.clusterDomain }}`)
observabilityMatchHost: Host(`observability-ui.{{ .Values.argo.clusterDomain }}`)
diff --git a/argocd/applications/templates/copy-db-to-keycloak-ns.yaml b/argocd/applications/templates/copy-db-to-keycloak-ns.yaml
new file mode 100644
index 000000000..825d26420
--- /dev/null
+++ b/argocd/applications/templates/copy-db-to-keycloak-ns.yaml
@@ -0,0 +1,53 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+{{- $appName := "copy-db-to-keycloak-ns" }}
+{{- $chartName := "copy-secret" }}
+{{- $namespace := "keycloak-system" }}
+{{- $syncWave := "145" }}
+---
+{{- if (index .Values.argo.enabled $appName) }}
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ annotations:
+ argocd.argoproj.io/sync-wave: "{{ $syncWave }}"
+ name: {{$appName}}
+ namespace: {{ required "A valid namespace entry required!" .Values.argo.namespace }}
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: {{ required "A valid projectName entry required!" .Values.argo.project }}
+ sources:
+ - repoURL: {{ required "A valid chartRepoURL" .Values.argo.chartRepoURL }}
+ chart: common/charts/{{$chartName}}
+ targetRevision: 25.2.1
+ helm:
+ releaseName: {{$appName}}
+ valuesObject:
+ {{- $customFile := printf "custom/%s.tpl" $appName }}
+ {{- $customConfig := tpl (.Files.Get $customFile) . | fromYaml }}
+ {{- $baseFile := printf "configs/%s.yaml" $appName }}
+ {{- $baseConfig := .Files.Get $baseFile|fromYaml}}
+ {{- $overwrite := (get .Values.postCustomTemplateOverwrite $appName ) | default dict }}
+ {{- mergeOverwrite $baseConfig $customConfig $overwrite | toYaml | nindent 10 }}
+ destination:
+ namespace: {{$namespace}}
+ server: {{ required "A valid targetServer entry required!" .Values.argo.targetServer }}
+ syncPolicy:
+ {{- if .Values.argo.autosync }}
+ automated:
+ prune: true
+ selfHeal: true
+ retry:
+ limit: 5
+ backoff:
+ duration: 5s
+ maxDuration: 3m0s
+ factor: 2
+ {{- end }}
+ syncOptions:
+ - CreateNamespace=true
+ - ApplyOutOfSyncOnly=true
+{{- end }}
diff --git a/argocd/applications/templates/copy-keycloak-admin-to-platform.yaml b/argocd/applications/templates/copy-keycloak-admin-to-platform.yaml
new file mode 100644
index 000000000..ee8ac24dc
--- /dev/null
+++ b/argocd/applications/templates/copy-keycloak-admin-to-platform.yaml
@@ -0,0 +1,53 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+{{- $appName := "copy-keycloak-admin-to-platform" }}
+{{- $chartName := "copy-secret" }}
+{{- $namespace := "orch-platform" }}
+{{- $syncWave := "160" }}
+---
+{{- if (index .Values.argo.enabled $appName) }}
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ annotations:
+ argocd.argoproj.io/sync-wave: "{{ $syncWave }}"
+ name: {{$appName}}
+ namespace: {{ required "A valid namespace entry required!" .Values.argo.namespace }}
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: {{ required "A valid projectName entry required!" .Values.argo.project }}
+ sources:
+ - repoURL: {{ required "A valid chartRepoURL" .Values.argo.chartRepoURL }}
+ chart: common/charts/{{$chartName}}
+ targetRevision: 25.2.1
+ helm:
+ releaseName: {{$appName}}
+ valuesObject:
+ {{- $customFile := printf "custom/%s.tpl" $appName }}
+ {{- $customConfig := tpl (.Files.Get $customFile) . | fromYaml }}
+ {{- $baseFile := printf "configs/%s.yaml" $appName }}
+ {{- $baseConfig := .Files.Get $baseFile|fromYaml}}
+ {{- $overwrite := (get .Values.postCustomTemplateOverwrite $appName ) | default dict }}
+ {{- mergeOverwrite $baseConfig $customConfig $overwrite | toYaml | nindent 10 }}
+ destination:
+ namespace: {{$namespace}}
+ server: {{ required "A valid targetServer entry required!" .Values.argo.targetServer }}
+ syncPolicy:
+ {{- if .Values.argo.autosync }}
+ automated:
+ prune: true
+ selfHeal: true
+ retry:
+ limit: 5
+ backoff:
+ duration: 5s
+ maxDuration: 3m0s
+ factor: 2
+ {{- end }}
+ syncOptions:
+ - CreateNamespace=true
+ - ApplyOutOfSyncOnly=true
+{{- end }}
diff --git a/argocd/applications/templates/keycloak-operator.yaml b/argocd/applications/templates/keycloak-operator.yaml
new file mode 100644
index 000000000..7336521e3
--- /dev/null
+++ b/argocd/applications/templates/keycloak-operator.yaml
@@ -0,0 +1,53 @@
+# SPDX-FileCopyrightText: 2025 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+{{- $appName := "keycloak-operator" }}
+{{- $namespace := "keycloak-system" }}
+{{- $syncWave := "1" }}
+---
+{{- if (index .Values.argo.enabled $appName) }}
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ annotations:
+ argocd.argoproj.io/sync-wave: "{{ $syncWave }}"
+ description: "Keycloak Operator for managing Keycloak instances via CRDs"
+ name: {{$appName}}
+ namespace: {{ required "A valid namespace entry required!" .Values.argo.namespace }}
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: {{ required "A valid projectName entry required!" .Values.argo.project }}
+ sources:
+ - repoURL: {{ required "A valid chartRepoURL entry required!" .Values.argo.chartRepoURL }}
+ chart: common/charts/keycloak-operator
+ targetRevision: 25.2.0
+ helm:
+ releaseName: {{$appName}}
+ valuesObject:
+ {{- $customFile := printf "custom/%s.tpl" $appName }}
+ {{- $customConfig := tpl (.Files.Get $customFile) . | fromYaml }}
+ {{- $baseFile := printf "configs/%s.yaml" $appName }}
+ {{- $baseConfig := .Files.Get $baseFile|fromYaml}}
+ {{- $overwrite := (get .Values.postCustomTemplateOverwrite $appName ) | default dict }}
+ {{- mergeOverwrite $baseConfig $customConfig $overwrite | toYaml | nindent 10 }}
+ destination:
+ namespace: {{$namespace}}
+ server: {{ required "A valid targetServer entry required!" .Values.argo.targetServer }}
+ syncPolicy:
+ {{- if .Values.argo.autosync }}
+ automated:
+ prune: true
+ selfHeal: true
+ retry:
+ limit: 5
+ backoff:
+ duration: 5s
+ maxDuration: 3m0s
+ factor: 2
+ {{- end }}
+ syncOptions:
+ - CreateNamespace=true
+ - RespectIgnoreDifferences=true
+{{- end }}
diff --git a/argocd/applications/templates/keycloak-tenant-controller.yaml b/argocd/applications/templates/keycloak-tenant-controller.yaml
index 714b5becc..46a78d8d3 100644
--- a/argocd/applications/templates/keycloak-tenant-controller.yaml
+++ b/argocd/applications/templates/keycloak-tenant-controller.yaml
@@ -21,7 +21,7 @@ spec:
sources:
- repoURL: {{ required "A valid chartRepoURL entry required!" .Values.argo.chartRepoURL }}
chart: common/charts/keycloak-tenant-controller
- targetRevision: 25.2.5
+ targetRevision: 25.2.6
helm:
releaseName: {{$appName}}
valuesObject:
diff --git a/argocd/applications/templates/platform-keycloak.yaml b/argocd/applications/templates/platform-keycloak.yaml
index fbf98e61c..90de74195 100644
--- a/argocd/applications/templates/platform-keycloak.yaml
+++ b/argocd/applications/templates/platform-keycloak.yaml
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
{{- $appName := "platform-keycloak" }}
-{{- $namespace := "orch-platform" }}
+{{- $namespace := "keycloak-system" }}
{{- $syncWave := "150" }}
---
{{- if (index .Values.argo.enabled $appName) }}
@@ -12,6 +12,7 @@ kind: Application
metadata:
annotations:
argocd.argoproj.io/sync-wave: "{{ $syncWave }}"
+ description: "Keycloak instance deployed via Operator"
name: {{$appName}}
namespace: {{ required "A valid namespace entry required!" .Values.argo.namespace }}
finalizers:
@@ -19,9 +20,9 @@ metadata:
spec:
project: {{ required "A valid projectName entry required!" .Values.argo.project }}
sources:
- - repoURL: "registry-1.docker.io/bitnamicharts"
- chart: keycloak
- targetRevision: 24.4.12
+ - repoURL: {{ required "A valid chartRepoURL entry required!" .Values.argo.chartRepoURL }}
+ chart: common/charts/keycloak-instance
+ targetRevision: 25.2.0
helm:
releaseName: {{$appName}}
valuesObject:
diff --git a/argocd/applications/templates/traefik-extra-objects.yaml b/argocd/applications/templates/traefik-extra-objects.yaml
index 8b4cad24d..ac6d52796 100644
--- a/argocd/applications/templates/traefik-extra-objects.yaml
+++ b/argocd/applications/templates/traefik-extra-objects.yaml
@@ -21,7 +21,7 @@ spec:
sources:
- repoURL: {{ required "A valid chartRepoURL entry required!" .Values.argo.chartRepoURL }}
chart: common/charts/{{$appName}}
- targetRevision: 25.2.1
+ targetRevision: 25.2.2
helm:
releaseName: {{$appName}}
valuesObject:
diff --git a/argocd/applications/values.yaml b/argocd/applications/values.yaml
index b839a4aa7..349a4dd9b 100644
--- a/argocd/applications/values.yaml
+++ b/argocd/applications/values.yaml
@@ -8,7 +8,7 @@ argo:
databases:
- namespace: orch-app
name: app-orch-catalog
- - namespace: orch-platform
+ - namespace: keycloak-system
name: platform-keycloak
- namespace: orch-platform
name: vault
diff --git a/installer/Makefile b/installer/Makefile
index 791baec68..57f97e041 100644
--- a/installer/Makefile
+++ b/installer/Makefile
@@ -25,7 +25,7 @@ INTEL_HARBOR_CACERT := ${EDGE_MANAGEABILITY_FRAMEWORK_DIR}/mage/intel-harbor-ca.
SAVE_DIR := ${HOME}/pod-configs/SAVEME
-ORCH_ISTIO_NAMESPACES := orch-infra orch-iam orch-app orch-cluster orch-ui orch-platform orch-harbor orch-gateway orch-sre orch-database
+ORCH_ISTIO_NAMESPACES := orch-infra orch-iam orch-app orch-cluster orch-ui orch-platform orch-harbor orch-gateway orch-sre orch-database keycloak-system
ORCH_NAMESPACES := cattle-system
ARGO_NAMESPACES := dev
@@ -99,8 +99,19 @@ ${M}/release-secrets: | ${M}/create-namespaces
touch $@
${M}/keycloak-secret: | ${M}/create-namespaces
- @if ! kubectl get secret platform-keycloak -n orch-platform > /dev/null 2>&1; then \
- kubectl create secret generic -n orch-platform platform-keycloak --from-literal=admin-password="$(KEYCLOAK_PASSWORD)" --dry-run=client -o yaml | kubectl apply -f - ;\
+ # if statement for upgrade from 3.1
+ @if kubectl get secret platform-keycloak -n orch-platform > /dev/null 2>&1; then \
+ keycloak_password=$$(kubectl get secret -n orch-platform platform-keycloak -o jsonpath='{.data.admin-password}' | base64 --decode); \
+ kubectl create secret generic -n keycloak-system platform-keycloak \
+ --from-literal=username="admin" \
+ --from-literal=password="$$keycloak_password" \
+ --dry-run=client -o yaml | kubectl apply -f - ;\
+ fi
+ @if ! kubectl get secret platform-keycloak -n keycloak-system > /dev/null 2>&1; then \
+ kubectl create secret generic -n keycloak-system platform-keycloak \
+ --from-literal=username="admin" \
+ --from-literal=password="$(KEYCLOAK_PASSWORD)" \
+ --dry-run=client -o yaml | kubectl apply -f - ;\
fi
touch $@
diff --git a/mage/Magefile.go b/mage/Magefile.go
index 2c2784144..2f39baa16 100644
--- a/mage/Magefile.go
+++ b/mage/Magefile.go
@@ -49,10 +49,11 @@ var argoNamespaces = []string{
"dev",
"argocd",
"gitea",
- "orch-platform", // used when creating a secret for gitea
- "orch-sre", // used when creating a secret for kindAll
- "orch-harbor", // used when creating a secret for integration
- "orch-infra", // used when creating a secret for mailpit
+ "orch-platform", // used when creating a secret for gitea
+ "orch-sre", // used when creating a secret for kindAll
+ "orch-harbor", // used when creating a secret for integration
+ "orch-infra", // used when creating a secret for mailpit
+ "keycloak-system", // where Keycloak Operator and instances are deployed
}
// FIXME: Ideally this could be extracted from the cluster configuration and aligned with auth secrets - out of scope for now
diff --git a/mage/deploy.go b/mage/deploy.go
index f8c54a91f..a617143eb 100644
--- a/mage/deploy.go
+++ b/mage/deploy.go
@@ -270,6 +270,11 @@ spec:
- resources:
kinds:
- Pod
+ exclude:
+ any:
+ - resources:
+ namespaces:
+ - keycloak-system
validate:
message: "Root filesystem must be read-only."
pattern:
@@ -447,8 +452,10 @@ func localSecret(targetEnv string, createRSToken bool) error {
}
// creating platform-keycloak secret that contains the randomly generated keycloak admin password
- if err := kubectlCreateAndApply("secret", "generic", "-n", "orch-platform", "platform-keycloak",
- "--from-literal=admin-password="+keycloakPassword); err != nil {
+ // Secret must be in keycloak-system namespace where the Keycloak Operator watches
+ if err := kubectlCreateAndApply("secret", "generic", "-n", "keycloak-system", "platform-keycloak",
+ "--from-literal=username=admin",
+ "--from-literal=password="+keycloakPassword); err != nil {
return err
}
if err := kubectlCreateAndApply("namespace", "orch-database"); err != nil {
diff --git a/mage/keycloak_utils.go b/mage/keycloak_utils.go
index e49277c52..4890786bc 100644
--- a/mage/keycloak_utils.go
+++ b/mage/keycloak_utils.go
@@ -18,7 +18,7 @@ import (
)
var (
- keycloakNamespace = "orch-platform"
+ keycloakNamespace = "keycloak-system"
minPasswordLength = 10
)
@@ -26,7 +26,7 @@ type Keycloak mg.Namespace
// GetPassword retrieves the admin keycloak password
func (k Keycloak) GetPassword() {
- command := "kubectl get secret -n " + keycloakNamespace + " platform-keycloak -o jsonpath='{.data.admin-password}' | base64 --decode"
+ command := "kubectl get secret -n " + keycloakNamespace + " platform-keycloak -o jsonpath='{.data.password}' | base64 --decode"
out, err := exec.Command("bash", "-c", command).CombinedOutput()
if err != nil {
fmt.Println("Error executing command:", err)
@@ -101,7 +101,7 @@ func clean_up_psql_pod() {
}
func set_keycloak_password(encoded_password string) {
- command := "kubectl -n " + keycloakNamespace + " get secret platform-keycloak -o yaml | yq e '.data.admin-password = \"" + encoded_password + "\"' | kubectl apply --force -f -"
+ command := "kubectl -n " + keycloakNamespace + " get secret platform-keycloak -o yaml | yq e '.data.password = \"" + encoded_password + "\"' | kubectl apply --force -f -"
_, err := exec.Command("bash", "-c", command).CombinedOutput()
if err != nil {
fmt.Println("Error executing command:", err.Error())
diff --git a/mage/tenant_utils.go b/mage/tenant_utils.go
index 29310055b..612fda031 100644
--- a/mage/tenant_utils.go
+++ b/mage/tenant_utils.go
@@ -400,8 +400,8 @@ func GetDefaultOrchPassword() (string, error) {
"get",
"secret",
"platform-keycloak",
- "-n", "orch-platform",
- "-o", "jsonpath={.data.admin-password}",
+ "-n", "keycloak-system",
+ "-o", "jsonpath={.data.password}",
).CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to get password from kubectl command: %w\noutput: %s", err, string(output))
@@ -455,7 +455,7 @@ func GetDefaultOrchPassword() (string, error) {
}
func GetKeycloakSecret() (string, error) {
- kubecmd := fmt.Sprintf("kubectl get secret -n %s platform-keycloak -o jsonpath='{.data.admin-password}' ", "orch-platform")
+ kubecmd := fmt.Sprintf("kubectl get secret -n %s platform-keycloak -o jsonpath='{.data.password}' ", "keycloak-system")
pass, err := script.Exec(kubecmd).String()
if err != nil {
return "", err
diff --git a/on-prem-installers/onprem/functions.sh b/on-prem-installers/onprem/functions.sh
index 782708fbc..50d71cf42 100755
--- a/on-prem-installers/onprem/functions.sh
+++ b/on-prem-installers/onprem/functions.sh
@@ -42,11 +42,13 @@ create_keycloak_password() {
kubectl apply -f - <