From 8d1dc190248c8362cd5db31d309985f33801620c Mon Sep 17 00:00:00 2001 From: Sandeep Sharma Date: Fri, 21 Nov 2025 09:16:14 +0530 Subject: [PATCH 1/6] Keycloak migration from bitnamilegacy to official operator & chart (#948) --- .../actions/collect_diagnostics/action.yaml | 2 + .github/workflows/virtual-integration.yml | 2 +- .../configs/app-deployment-manager.yaml | 4 +- .../configs/app-interconnect-manager.yaml | 2 +- .../configs/app-orch-catalog.yaml | 2 +- .../configs/app-orch-tenant-controller.yaml | 2 +- .../configs/app-resource-manager.yaml | 2 +- argocd/applications/configs/auth-service.yaml | 2 + .../configs/copy-database-to-keycloak.yaml | 18 + .../copy-keycloak-admin-to-platform.yaml | 17 + argocd/applications/configs/infra-core.yaml | 13 +- .../applications/configs/infra-external.yaml | 6 +- .../applications/configs/infra-managers.yaml | 10 +- .../configs/infra-onboarding.yaml | 6 +- .../configs/intel-infra-provider.yaml | 2 +- .../configs/keycloak-operator.yaml | 146 ++ .../configs/kyverno-extra-policies.yaml | 6 +- .../configs/kyverno-istio-policy.yaml | 1 + .../configs/kyverno-traefik-policy.yaml | 4 + .../applications/configs/metadata-broker.yaml | 2 +- argocd/applications/configs/nexus-api-gw.yaml | 3 +- .../configs/platform-keycloak.yaml | 1583 ++++------------- .../applications/configs/secrets-config.yaml | 4 +- argocd/applications/configs/token-fs.yaml | 2 + .../configs/traefik-extra-objects.yaml | 2 + argocd/applications/configs/traefik.yaml | 1 + .../applications/custom/cluster-manager.tpl | 33 +- .../applications/custom/keycloak-operator.tpl | 32 + .../custom/keycloak-tenant-controller.tpl | 2 + .../applications/custom/platform-keycloak.tpl | 1351 +++++++++++++- .../applications/custom/self-signed-cert.tpl | 6 + argocd/applications/custom/tenancy-init.tpl | 11 + .../custom/traefik-extra-objects.tpl | 5 +- .../templates/copy-database-to-keycloak.yaml | 53 + .../copy-keycloak-admin-to-platform.yaml | 53 + .../templates/keycloak-operator.yaml | 53 + .../templates/keycloak-tenant-controller.yaml | 2 +- .../templates/platform-keycloak.yaml | 9 +- .../templates/traefik-extra-objects.yaml | 2 +- argocd/applications/values.yaml | 2 +- installer/Makefile | 7 +- mage/Magefile.go | 9 +- mage/deploy.go | 11 +- mage/keycloak_utils.go | 6 +- mage/tenant_utils.go | 6 +- on-prem-installers/onprem/functions.sh | 4 +- .../onprem/onprem_orch_install.sh | 5 +- orch-configs/profiles/enable-platform.yaml | 3 + trivy.yaml | 13 + 49 files changed, 2150 insertions(+), 1372 deletions(-) create mode 100644 argocd/applications/configs/copy-database-to-keycloak.yaml create mode 100644 argocd/applications/configs/copy-keycloak-admin-to-platform.yaml create mode 100644 argocd/applications/configs/keycloak-operator.yaml create mode 100644 argocd/applications/custom/keycloak-operator.tpl create mode 100644 argocd/applications/templates/copy-database-to-keycloak.yaml create mode 100644 argocd/applications/templates/copy-keycloak-admin-to-platform.yaml create mode 100644 argocd/applications/templates/keycloak-operator.yaml 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 42177081a..ffc4a4498 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-database-to-keycloak.yaml b/argocd/applications/configs/copy-database-to-keycloak.yaml new file mode 100644 index 000000000..d0a537c60 --- /dev/null +++ b/argocd/applications/configs/copy-database-to-keycloak.yaml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +# Sync the Keycloak database credentials from orch-database namespace to keycloak-system +# Source: keycloak-system-platform-keycloak secret (created by PostgreSQL initdb) +# Target: keycloak-platform-db secret (used by Keycloak CRD) +remoteNamespace: orch-database +refreshInterval: "0m" +targetSecretName: keycloak-platform-db +sourceSecretName: keycloak-system-platform-keycloak +keyName: + - source: username + target: username + - 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 43a186693..0fcb64360 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" api: @@ -33,7 +33,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: @@ -60,7 +60,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 @@ -77,6 +77,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" @@ -86,7 +91,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 d5d527b62..ead12e668 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" amt: @@ -123,6 +123,6 @@ 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" 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 3ffec51e9..bb224763f 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.8" 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..65875db2c 100644 --- a/argocd/applications/configs/platform-keycloak.yaml +++ b/argocd/applications/configs/platform-keycloak.yaml @@ -2,1279 +2,338 @@ # # 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 +# Base configuration for keycloak-instance deployment +# This file provides default infrastructure and operational configuration +# Domain-specific URL configurations (clusterSpecific and realmMaster) are defined in custom/platform-keycloak.tpl +# and merged via mergeOverwrite in the ArgoCD Application template -containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" +# Keycloak instance configuration (Keycloak CRD) +keycloak: + # Container image (uses upstream version from Chart.yaml) + image: "quay.io/keycloak/keycloak:26.4.5" + imagePullPolicy: IfNotPresent -# disable network policy to avoid intermittent dns issues -networkPolicy: - enabled: false + # Bootstrap admin credentials + bootstrapAdmin: + secret: platform-keycloak -## 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 + # Database configuration + database: + vendor: postgres + host: postgresql-cluster-rw.orch-database.svc.cluster.local + port: 5432 + database: keycloak-system-platform-keycloak + usernameSecret: + name: keycloak-platform-db + key: username + passwordSecret: + name: keycloak-platform-db + key: password + # Connection pool settings + poolInitialSize: 5 + poolMinSize: 5 + poolMaxSize: 50 -## Service configuration -## -service: - ## @param service.type Kubernetes service type, default: LoadBalancer - ## - type: ClusterIP - ports: - http: 8080 + # HTTP configuration + http: + httpEnabled: true + httpPort: 8080 + relativeUrl: "/" -## 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: "" + # Proxy headers for reverse proxy + proxy: + headers: xforwarded - passwordSecretKey: admin-password - existingSecret: platform-keycloak + # Ingress configuration + ingress: + enabled: 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 + # Pod resource allocation + resources: + requests: + cpu: 500m + memory: 512Mi + limits: + cpu: 2000m + memory: 2Gi -## 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 + # Runtime configuration options + additionalOptions: + - 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 + +# NOTE: realmMaster realm configuration is defined in custom/platform-keycloak.tpl +# where it can access clusterSpecific values with templated domain names - ## @param keycloakConfigCli.enabled Whether to enable keycloak-config-cli job - ## +# Keycloak Config CLI job configuration +keycloakConfigCli: enabled: true - args: - - --import.managed.group="no-delete" - - --import.managed.required-action="no-delete" - - --import.managed.role="no-delete" - - --import.managed.client="no-delete" - ## @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" + 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" + + 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 + + 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" + + ttlSecondsAfterFinished: 3600 + backoffLimit: 5 + restartPolicy: Never + + podLabels: + sidecar.istio.io/inject: "false" + + securityContext: + runAsNonRoot: true + runAsUser: 65534 + runAsGroup: 65534 + seccompProfile: + type: RuntimeDefault + fsGroup: 65534 + + 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 + + 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 + + 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/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..7d8ce0b86 100644 --- a/argocd/applications/custom/platform-keycloak.tpl +++ b/argocd/applications/custom/platform-keycloak.tpl @@ -2,64 +2,1303 @@ # # 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"] +## These values are used to configure: +## 1. Realm import configuration (clients, redirect URIs, etc.) +## 2. Keycloak instance deployment parameters -## 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 +{{- $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) -}} -# 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}} +# Keycloak Operator configuration +{{- if and .Values.argo .Values.argo.resources .Values.argo.resources.platformKeycloak }} +keycloak: + resources: + {{- toYaml .Values.argo.resources.platformKeycloak | nindent 4 }} +{{- 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" +# 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 }} -{{- with .Values.argo.resources.platformKeycloak }} -resources: - {{- toYaml . | nindent 2}} +# 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-database-to-keycloak.yaml b/argocd/applications/templates/copy-database-to-keycloak.yaml new file mode 100644 index 000000000..c66892628 --- /dev/null +++ b/argocd/applications/templates/copy-database-to-keycloak.yaml @@ -0,0 +1,53 @@ +# SPDX-FileCopyrightText: 2025 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +{{- $appName := "copy-database-to-keycloak" }} +{{- $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 eadf1eecc..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.2 + 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 0917a530c..d99c7c4f1 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -99,8 +99,11 @@ ${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 ! 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 - < Date: Fri, 21 Nov 2025 21:13:10 +0530 Subject: [PATCH 2/6] Update Makefile | new ns creation --- installer/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/Makefile b/installer/Makefile index d99c7c4f1..12e3b33f7 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 From a90e0c7dc7abfcf47277c10e4eb66796b0683f5f Mon Sep 17 00:00:00 2001 From: Sandeep Sharma Date: Sat, 22 Nov 2025 02:59:59 +0530 Subject: [PATCH 3/6] refactor: remove deprecated Keycloak database sync configurations and update related templates --- .../configs/copy-database-to-keycloak.yaml | 18 -- .../configs/platform-keycloak.yaml | 163 --------------- .../applications/custom/platform-keycloak.tpl | 188 +++++++++++++++++- .../templates/copy-database-to-keycloak.yaml | 53 ----- orch-configs/profiles/enable-platform.yaml | 1 - 5 files changed, 181 insertions(+), 242 deletions(-) delete mode 100644 argocd/applications/configs/copy-database-to-keycloak.yaml delete mode 100644 argocd/applications/templates/copy-database-to-keycloak.yaml diff --git a/argocd/applications/configs/copy-database-to-keycloak.yaml b/argocd/applications/configs/copy-database-to-keycloak.yaml deleted file mode 100644 index d0a537c60..000000000 --- a/argocd/applications/configs/copy-database-to-keycloak.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-FileCopyrightText: 2025 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -# Sync the Keycloak database credentials from orch-database namespace to keycloak-system -# Source: keycloak-system-platform-keycloak secret (created by PostgreSQL initdb) -# Target: keycloak-platform-db secret (used by Keycloak CRD) -remoteNamespace: orch-database -refreshInterval: "0m" -targetSecretName: keycloak-platform-db -sourceSecretName: keycloak-system-platform-keycloak -keyName: - - source: username - target: username - - source: password - target: password - -externalSecretsApiGroup: external-secrets.io/v1 diff --git a/argocd/applications/configs/platform-keycloak.yaml b/argocd/applications/configs/platform-keycloak.yaml index 65875db2c..a6014c4f0 100644 --- a/argocd/applications/configs/platform-keycloak.yaml +++ b/argocd/applications/configs/platform-keycloak.yaml @@ -7,171 +7,8 @@ # Domain-specific URL configurations (clusterSpecific and realmMaster) are defined in custom/platform-keycloak.tpl # and merged via mergeOverwrite in the ArgoCD Application template -# 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 - host: postgresql-cluster-rw.orch-database.svc.cluster.local - port: 5432 - database: keycloak-system-platform-keycloak - usernameSecret: - name: keycloak-platform-db - key: username - passwordSecret: - name: keycloak-platform-db - key: password - # 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: - - 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 # NOTE: realmMaster realm configuration is defined in custom/platform-keycloak.tpl # where it can access clusterSpecific values with templated domain names diff --git a/argocd/applications/custom/platform-keycloak.tpl b/argocd/applications/custom/platform-keycloak.tpl index 7d8ce0b86..1e031304e 100644 --- a/argocd/applications/custom/platform-keycloak.tpl +++ b/argocd/applications/custom/platform-keycloak.tpl @@ -2,6 +2,187 @@ # # SPDX-License-Identifier: Apache-2.0 + +# 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 @@ -21,13 +202,6 @@ {{- $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) -}} -# Keycloak Operator configuration -{{- if and .Values.argo .Values.argo.resources .Values.argo.resources.platformKeycloak }} -keycloak: - resources: - {{- toYaml .Values.argo.resources.platformKeycloak | nindent 4 }} -{{- end }} - # Override Keycloak Config CLI resources if specified {{- if and .Values.argo .Values.argo.resources .Values.argo.resources.keycloakConfigCli }} keycloakConfigCli: diff --git a/argocd/applications/templates/copy-database-to-keycloak.yaml b/argocd/applications/templates/copy-database-to-keycloak.yaml deleted file mode 100644 index c66892628..000000000 --- a/argocd/applications/templates/copy-database-to-keycloak.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# SPDX-FileCopyrightText: 2025 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -{{- $appName := "copy-database-to-keycloak" }} -{{- $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/orch-configs/profiles/enable-platform.yaml b/orch-configs/profiles/enable-platform.yaml index 5e662aa08..81c5331e5 100644 --- a/orch-configs/profiles/enable-platform.yaml +++ b/orch-configs/profiles/enable-platform.yaml @@ -19,7 +19,6 @@ argo: copy-ca-cert-gitea-to-app: true copy-ca-cert-gitea-to-cluster: true copy-cluster-gitea-cred-to-fleet: true - copy-database-to-keycloak: true copy-keycloak-admin-to-platform: true external-secrets: true istio-base: true From 598e5e08c994f21c998af7ff914862faeae50b52 Mon Sep 17 00:00:00 2001 From: Sandeep Sharma Date: Fri, 21 Nov 2025 13:46:13 -0800 Subject: [PATCH 4/6] refactor: remove redundant comments from platform-keycloak.yaml --- argocd/applications/configs/platform-keycloak.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/argocd/applications/configs/platform-keycloak.yaml b/argocd/applications/configs/platform-keycloak.yaml index a6014c4f0..276d0f461 100644 --- a/argocd/applications/configs/platform-keycloak.yaml +++ b/argocd/applications/configs/platform-keycloak.yaml @@ -2,14 +2,6 @@ # # SPDX-License-Identifier: Apache-2.0 -# Base configuration for keycloak-instance deployment -# This file provides default infrastructure and operational configuration -# Domain-specific URL configurations (clusterSpecific and realmMaster) are defined in custom/platform-keycloak.tpl -# and merged via mergeOverwrite in the ArgoCD Application template - - - - # NOTE: realmMaster realm configuration is defined in custom/platform-keycloak.tpl # where it can access clusterSpecific values with templated domain names From 58e5cb89ec544474b7e6a3b4cc02f9475436e7ac Mon Sep 17 00:00:00 2001 From: Sandeep Sharma Date: Wed, 26 Nov 2025 00:32:57 -0800 Subject: [PATCH 5/6] feat: add AWS deployment configuration and Keycloak database sync --- .../configs/copy-db-to-keycloak-ns.yaml | 28 ++++++++++ .../custom/copy-db-to-keycloak-ns.tpl | 6 +++ .../templates/copy-db-to-keycloak-ns.yaml | 53 +++++++++++++++++++ orch-configs/profiles/enable-aws.yaml | 4 +- 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 argocd/applications/configs/copy-db-to-keycloak-ns.yaml create mode 100644 argocd/applications/custom/copy-db-to-keycloak-ns.tpl create mode 100644 argocd/applications/templates/copy-db-to-keycloak-ns.yaml 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/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/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/orch-configs/profiles/enable-aws.yaml b/orch-configs/profiles/enable-aws.yaml index 0f641a4d4..fda72ff56 100644 --- a/orch-configs/profiles/enable-aws.yaml +++ b/orch-configs/profiles/enable-aws.yaml @@ -6,4 +6,6 @@ # Use either this or enable-local argo: - enabled: {} + enabled: + copy-db-to-keycloak-ns: true + From 3b3fc284df8bc6aea254bca9ebf329ea37c59255 Mon Sep 17 00:00:00 2001 From: John O'Loughlin Date: Wed, 26 Nov 2025 14:04:25 +0000 Subject: [PATCH 6/6] Update Makefile (#1152) --- installer/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/installer/Makefile b/installer/Makefile index 12e3b33f7..b337fee4d 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -99,6 +99,14 @@ ${M}/release-secrets: | ${M}/create-namespaces touch $@ ${M}/keycloak-secret: | ${M}/create-namespaces + # 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" \