Keycloak
What you’ll accomplish
Section titled “What you’ll accomplish”You’ll configure Keycloak for production high availability: connecting it to an external PostgreSQL database, enabling horizontal pod autoscaling, and scaling the Istio waypoint proxy.
Prerequisites
Section titled “Prerequisites”- UDS CLI installed
- UDS Registry account created and authenticated locally with a read token
- Access to a Kubernetes cluster (multi-node, multi-AZ recommended)
- An external PostgreSQL instance accessible from the cluster
- Familiarity with UDS bundle overrides
Before you begin
Section titled “Before you begin”Keycloak is the identity provider for the entire platform; if it becomes unavailable, users cannot authenticate and applications that depend on SSO will reject new sessions.
-
Connect Keycloak to an external PostgreSQL database
Choose the credential approach that fits your environment:
Set known values directly in the bundle and use variables for environment-specific settings (e.g., values from Terraform outputs):
uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:# Disable embedded dev database- path: devModevalue: falsevariables:# PostgreSQL hostname- name: KEYCLOAK_DB_HOSTpath: postgresql.host# Database user- name: KEYCLOAK_DB_USERNAMEpath: postgresql.username# Database name- name: KEYCLOAK_DB_DATABASEpath: postgresql.database# Database password- name: KEYCLOAK_DB_PASSWORDpath: postgresql.passwordsensitive: trueuds-config.yaml variables:core:KEYCLOAK_DB_HOST: "postgres.example.com"KEYCLOAK_DB_USERNAME: "keycloak"KEYCLOAK_DB_DATABASE: "keycloak"KEYCLOAK_DB_PASSWORD: "your-password"Reference pre-existing Kubernetes secrets, useful for external secret managers or shared credential stores. Set non-secret values directly in the bundle:
uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:- path: devModevalue: false# Database name to connect to- path: postgresql.databasevalue: "keycloak"# Name of the K8s Secret containing the DB host- path: postgresql.secretRef.host.namevalue: "keycloak-db-creds"# Key within that Secret holding the host value- path: postgresql.secretRef.host.keyvalue: "host"# Name of the K8s Secret containing the DB username- path: postgresql.secretRef.username.namevalue: "keycloak-db-creds"# Key within that Secret holding the username value- path: postgresql.secretRef.username.keyvalue: "username"# Name of the K8s Secret containing the DB password- path: postgresql.secretRef.password.namevalue: "keycloak-db-creds"# Key within that Secret holding the password value- path: postgresql.secretRef.password.keyvalue: "password" -
Enable HPA autoscaling
With an external database connected, enable the HorizontalPodAutoscaler to automatically scale Keycloak between 2 and 5 replicas based on CPU utilization:
uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:# Disable embedded dev database- path: devModevalue: false# Enable HorizontalPodAutoscaler- path: autoscaling.enabledvalue: trueThe default HPA configuration:
Setting Default Override Path Minimum replicas 2 autoscaling.minReplicasMaximum replicas 5 autoscaling.maxReplicasCPU target utilization 80% autoscaling.metrics[0].resource.target.averageUtilizationScale-up stabilization 600 seconds autoscaling.behavior.scaleUp.stabilizationWindowSecondsScale-down stabilization 300 seconds autoscaling.behavior.scaleDown.stabilizationWindowSecondsScale-down rate 1 pod per 300 seconds autoscaling.behavior.scaleDown.policies[0] -
Configure waypoint proxy autoscaling
Keycloak’s Istio waypoint proxy has an HPA enabled by default. For HA deployments, ensure the minimum replica count prevents downtime during pod rescheduling:
uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:# Minimum waypoint replicas- path: waypoint.horizontalPodAutoscaler.minReplicasvalue: 2# Maximum waypoint replicas- path: waypoint.horizontalPodAutoscaler.maxReplicasvalue: 5# Scaling metric configuration- path: waypoint.horizontalPodAutoscaler.metricsvalue:- type: Resourceresource:name: cputarget:type: UtilizationaverageUtilization: 90# Waypoint proxy CPU request (adjust for your environment)- path: waypoint.deployment.requests.cpuvalue: 250m# Waypoint proxy memory request (adjust for your environment)- path: waypoint.deployment.requests.memoryvalue: 256MiTo distribute waypoint replicas across nodes, add pod anti-affinity:
uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:- path: waypoint.deployment.affinityvalue:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchLabels:gateway.networking.k8s.io/gateway-name: keycloak-waypointtopologyKey: kubernetes.io/hostname -
Create and deploy your bundle
Terminal window uds create <path-to-bundle-dir>uds deploy uds-bundle-<name>-<arch>-<version>.tar.zst
Verification
Section titled “Verification”Confirm Keycloak HA is active:
# Check HPA statusuds zarf tools kubectl get hpa -n keycloak
# Confirm multiple replicas are runninguds zarf tools kubectl get pods -n keycloak -l app.kubernetes.io/name=keycloak
# Check waypoint proxy HPAuds zarf tools kubectl get hpa -n keycloak -l gateway.networking.k8s.io/gateway-nameSuccess criteria:
- HPA shows
MINPODS: 2and current replicas >= 2 - All Keycloak pods are
RunningandReady - Waypoint HPA shows desired replicas >= configured minimum
Troubleshooting
Section titled “Troubleshooting”Problem: Keycloak pods crash-looping after disabling devMode
Section titled “Problem: Keycloak pods crash-looping after disabling devMode”Symptoms: Pods in CrashLoopBackOff, logs show database connection errors.
Solution: Verify that the external PostgreSQL is reachable from the cluster and that credentials are correct. Check the pod logs:
uds zarf tools kubectl logs -n keycloak -l app.kubernetes.io/name=keycloak --tail=50Problem: Users are signed out shortly after logging in
Section titled “Problem: Users are signed out shortly after logging in”Symptoms: Users can reach sso.<domain> and authenticate, but their session is terminated again within seconds.
Solution: Check host clock sync on the nodes running keycloak pods. Keycloak token and session validation is sensitive to clock skew. If the affected nodes disagree on time, fix NTP on the hosts first, then restart all keycloak pods only if the issue persists.
Reference Prerequisites for the node time sync requirement.
Problem: HPA not scaling up under load
Section titled “Problem: HPA not scaling up under load”Symptoms: HPA shows <unknown> for current metrics.
Solution: Ensure metrics-server is deployed and healthy. UDS Core includes it as an optional component:
uds zarf tools kubectl get deployment -n kube-system metrics-serverRelated documentation
Section titled “Related documentation”- Keycloak: Horizontal Scaling - upstream guidance on scaling Keycloak instances
- Keycloak: Configuring the Database - database connection options and tuning
- Keycloak: Caching and Cache Configuration - distributed cache behavior across replicas
- PostgreSQL: High Availability - HA patterns for the backing database
- Configure HA for Authservice - Authservice handles SSO for applications without native OIDC support and also requires HA configuration.
- Identity & Authorization concepts - Background on how Keycloak and Authservice work together in UDS Core.