Files
service-catalog/manifests/helm/keycloakx/7.2.2/README.md
T
wbsong111 611e971295 add-keycloakx/7.2.2: keycloakx 7.2.2 추가, keycloak/18.4.0 제거 (이슈 #1)
codecentric/keycloak(18.4.0, WildFly 기반, appVersion 17.0.1-legacy)이
bitnami/postgresql 서브차트를 조건부 의존성으로 포함해 bitnami 무료 배포
정책 변경 문제가 그대로 전이됐다. codecentric은 이 WildFly 차트를 더 이상
갱신하지 않고 Quarkus 기반 Keycloak(17+)용 별도 차트 keycloakx를 제공하며,
keycloakx는 서브차트 의존성이 전혀 없어(Chart.yaml에 dependencies 없음)
문제가 근본적으로 해소된다.

실제 소비자가 없어(문서 예시 표 한 줄 외 참조 없음) phased 전환 없이
keycloak/18.4.0을 같은 커밋에서 제거했다.

custom-values.yaml 작성 시 확인한 핵심 사항 — 이 차트의 http.relativePath
기본값이 구버전 WildFly Keycloak 호환용 "/auth"라, 명시적으로 "/"로
오버라이드해야 한다(안 하면 OIDC issuer/admin API 경로가 소비 앱들의
경로 접미사 없음 가정과 어긋난다). database.existingSecret/existingSecretKey
로 kubernetes.io/basic-auth 시크릿을 그대로 참조 가능함도 helm template로
확인했다.

Closes #1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 16:09:51 +09:00

104 KiB

Keycloak-X

Keycloak-X is an open source identity and access management for modern applications and services.

Note that this chart is the logical successor of the Wildfly based codecentric/keycloak chart.

TL;DR;

$ cat << EOF > values.yaml
command:
  - "/opt/keycloak/bin/kc.sh"
  - "start"
  - "--http-port=8080"
  - "--hostname-strict=false"
extraEnv: |
  - name: KEYCLOAK_ADMIN
    value: admin
  - name: KEYCLOAK_ADMIN_PASSWORD
    value: admin
  - name: JAVA_OPTS_APPEND
    value: >-
      -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless
EOF

$ helm install keycloak codecentric/keycloakx --values ./values.yaml

Note that the default configuration is not suitable for production since it uses a h2 file database by default. It is strongly recommended to use a dedicated database with Keycloak.

For more examples see the examples folder.

Introduction

This chart bootstraps a Keycloak StatefulSet on a Kubernetes cluster using the Helm package manager. It provisions a fully featured Keycloak installation. For more information on Keycloak and its capabilities, see its documentation.

Installing the Chart

To install the chart with the release name keycloakx:

$ helm install keycloak codecentric/keycloakx

or via GitHub Container Registry:

$ helm install keycloak oci://ghcr.io/codecentric/helm-charts/keycloakx --version <version>

Uninstalling the Chart

To uninstall the keycloakx deployment:

$ helm uninstall keycloakx

Configuration

The following table lists the configurable parameters of the Keycloak-X chart and their default values.

Parameter Description Default
fullnameOverride Optionally override the fully qualified name ""
nameOverride Optionally override the name ""
namespaceOverride Optionally override the namespace for all resources. Useful for umbrella charts that deploy multiple aliased keycloak instances each into their own namespace. ""
replicas The number of replicas to create 1
image.repository The Keycloak image repository quay.io/keycloak/keycloak
image.tag Overrides the Keycloak image tag whose default is the chart version ""
image.digest Overrides the Keycloak image tag with a digest ""
image.pullPolicy The Keycloak image pull policy IfNotPresent
imagePullSecrets Image pull secrets for the Pod []
hostAliases Mapping between IPs and hostnames that will be injected as entries in the Pod's hosts files []
enableServiceLinks Indicates whether information about services should be injected into Pod's environment variables, matching the syntax of Docker links true
updateStrategy StatefulSet update strategy. One of RollingUpdate or OnDelete RollingUpdate
podManagementPolicy Pod management policy. One of Parallel or OrderedReady OrderedReady
revisionHistoryLimit Number of old ReplicaSets to retain for rollback. Defaults to Kubernetes default (10) if not set ""
restartPolicy Pod restart policy. One of Always, OnFailure, or Never Always
serviceAccount.create Specifies whether a ServiceAccount should be created true
serviceAccount.allowReadPods Specifies whether the ServiceAccount can get or list pods false
serviceAccount.name The name of the service account to use. If not set and create is true, a name is generated using the fullname template ""
serviceAccount.annotations Additional annotations for the ServiceAccount {}
serviceAccount.labels Additional labels for the ServiceAccount {}
serviceAccount.imagePullSecrets Image pull secrets that are attached to the ServiceAccount []
serviceAccount.automountServiceAccountToken Automount API credentials for the Service Account true
rbac.create Specifies whether RBAC resources are to be created false
rbac.rules Custom RBAC rules, e. g. for KUBE_PING []
podSecurityContext SecurityContext for the entire Pod. Every container running in the Pod will inherit this SecurityContext. This might be relevant when other components of the environment inject additional containers into running Pods (service meshes are the most prominent example for this) {"fsGroup":1000}
securityContext SecurityContext for the Keycloak container {"runAsNonRoot":true,"runAsUser":1000}
extraInitContainers Additional init containers, e. g. for providing custom themes []
skipInitContainers Skip all init containers (to avoid issues with service meshes which require sidecar proxies for connectivity) false
extraContainers Additional sidecar containers, e. g. for a database proxy, such as Google's cloudsql-proxy []
lifecycleHooks Lifecycle hooks for the Keycloak container {}
terminationGracePeriodSeconds Termination grace period in seconds for Keycloak shutdown. Clusters with a large cache might need to extend this to give Infinispan more time to rebalance 60
clusterDomain The internal Kubernetes cluster domain cluster.local
command Overrides the default entrypoint of the Keycloak container []
args Overrides the default args for the Keycloak container []
extraEnv Additional environment variables for Keycloak ""
extraEnvFrom Additional environment variables for Keycloak mapped from a Secret or ConfigMap ""
priorityClassName Pod priority class name ""
affinity Pod affinity Hard node and soft zone anti-affinity
topologySpreadConstraints Topology spread constraints Constraints used to spread pods
nodeSelector Node labels for Pod assignment {}
tolerations Node taints to tolerate []
podLabels Additional Pod labels {}
podAnnotations Additional Pod annotations {}
livenessProbe Liveness probe configuration {"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/health/live","port":"http-internal","scheme":"HTTP"},"initialDelaySeconds":0,"timeoutSeconds":5}
readinessProbe Readiness probe configuration {"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/health/ready","port":"http-internal","scheme":"HTTP"},"initialDelaySeconds":10,"timeoutSeconds":1}
startupProbe Startup probe configuration {"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/health","port":"http-internal","scheme":"HTTP"},"initialDelaySeconds":15,"timeoutSeconds":1,"failureThreshold":60,"periodSeconds":5}
resources Pod resource requests and limits {}
extraVolumes Add additional volumes, e. g. for custom themes ""
volumeClaimTemplates Add volume claim templates to the StatefulSet, e. g. for dynamic provisioning ""
extraVolumeMounts Add additional volumes mounts, e. g. for custom themes ""
extraPorts Add additional ports, e. g. for admin console or exposing JGroups ports []
podDisruptionBudget Pod disruption budget {}
statefulsetAnnotations Annotations for the StatefulSet {}
statefulsetLabels Additional labels for the StatefulSet {}
secrets Configuration for secrets that should be created {}
service.annotations Annotations for HTTP service {}
service.labels Additional labels for headless and HTTP Services {}
service.type The Service type ClusterIP
service.loadBalancerIP Optional IP for the load balancer. Used for services of type LoadBalancer only ""
loadBalancerSourceRanges Optional List of allowed source ranges (CIDRs). Used for service of type LoadBalancer only []
service.externalTrafficPolicy Optional external traffic policy. Used for services of type LoadBalancer & NodePort only "Cluster"
service.internalTrafficPolicy Optional internal traffic policy. Valid values: Cluster, Local. ""
service.httpPort The http Service port 80
service.httpNodePort The HTTP Service node port if type is NodePort ""
service.httpsPort The HTTPS Service port 8443
service.httpsNodePort The HTTPS Service node port if type is NodePort ""
service.extraPorts Additional Service ports, e. g. for custom admin console []
service.sessionAffinity sessionAffinity for Service, e. g. "ClientIP" ""
service.sessionAffinityConfig sessionAffinityConfig for Service {}
serviceHeadless.annotations Annotations for headless service {}
serviceHeadless.extraPorts Add additional ports to the headless service, e. g. for admin console or exposing JGroups ports []
ingress.enabled If true, an Ingress is created false
ingress.rules List of Ingress Ingress rule see below
ingress.rules[0].host Host for the Ingress rule {{ .Release.Name }}.keycloak.example.com
ingress.rules[0].paths Paths for the Ingress rule see below
ingress.rules[0].paths[0].path Path for the Ingress rule /
ingress.rules[0].paths[0].pathType Path Type for the Ingress rule Prefix
ingress.rules[0].paths[0].serviceName Optional override for backend service name (useful for AWS ALB action annotations) ""
ingress.rules[0].paths[0].servicePort Optional override for backend service port name ""
ingress.servicePort The Service port targeted by the Ingress http
ingress.annotations Ingress annotations {}
ingress.ingressClassName The name of the Ingress Class associated with the ingress ""
ingress.labels Additional Ingress labels {}
ingress.tls TLS configuration see below
ingress.tls[0].hosts List of TLS hosts [keycloak.example.com]
ingress.tls[0].secretName Name of the TLS secret ""
ingress.console.enabled If true, an Ingress for the console is created false
ingress.console.rules List of Ingress Ingress rule for the console see below
ingress.console.rules[0].host Host for the Ingress rule for the console {{ .Release.Name }}.keycloak.example.com
ingress.console.rules[0].paths Paths for the Ingress rule for the console see below
ingress.console.rules[0].paths[0].path Path for the Ingress rule for the console [{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/admin]
ingress.console.rules[0].paths[0].pathType Path Type for the Ingress rule for the console Prefix
ingress.console.rules[0].paths[0].serviceName Optional override for backend service name (console ingress) ""
ingress.console.rules[0].paths[0].servicePort Optional override for backend service port name (console ingress) ""
ingress.console.labels Additional labels for the console ingress only {}
ingress.console.annotations Ingress annotations for the console {}
ingress.console.ingressClassName The name of the Ingress Class associated with the console ingress ""
ingress.console.tls TLS configuration see below
ingress.console.tls[0].hosts List of TLS hosts [keycloak.example.com]
ingress.console.tls[0].secretName Name of the TLS secret ""
networkPolicy.enabled If true, the ingress network policy is deployed false
networkPolicy.extraFrom Allows to define allowed external ingress traffic (see Kubernetes doc for network policy from format) []
networkPolicy.egress Allows to define allowed egress from Keycloak pods (see Kubernetes doc for network policy egress format) []
route.enabled If true, an OpenShift Route is created false
route.path Path for the Route /
route.annotations Route annotations {}
route.labels Additional Route labels {}
route.host Host name for the Route ""
route.tls.enabled If true, TLS is enabled for the Route true
route.tls.insecureEdgeTerminationPolicy Insecure edge termination policy of the Route. Can be None, Redirect, or Allow Redirect
route.tls.termination TLS termination of the route. Can be edge, passthrough, or reencrypt edge
dbchecker.enabled Enable database readiness check false
dbchecker.image.repository Docker image used to check database readiness at startup docker.io/busybox
dbchecker.image.tag Image tag for the dbchecker image 1.32
dbchecker.image.pullPolicy Image pull policy for the dbchecker image IfNotPresent
dbchecker.securityContext SecurityContext for the dbchecker container {"allowPrivilegeEscalation":false,"runAsGroup":1000,"runAsNonRoot":true,"runAsUser":1000}
dbchecker.resources Resource requests and limits for the dbchecker container {"limits":{"cpu":"20m","memory":"32Mi"},"requests":{"cpu":"20m","memory":"32Mi"}}
database.vendor Database vendor unset
database.hostname Database Hostname unset
database.port Database Port unset
database.username Database User unset
database.password Database Password unset
database.database Database unset
database.existingSecret Existing Secret containing database password (expects key password) ""
database.existingSecretKey Key in existing Secret containing database password ""
cache.stack Cache / Cluster Discovery, use custom to disable automatic configuration. default
proxy.enabled If true, the KC_PROXY env variable will be set to the configured mode true
proxy.mode The configured proxy mode forwarded
proxy.http.enabled If true, HTTP forwarding is enabled true
http.relativePath The relative http path (context-path) /auth
http.internalPort The port of the internal management interface http-internal
http.internalScheme The scheme of the internal management interface HTTP
metrics.enabled If true then the metrics endpoint is exposed true
health.enabled If true then the health endpoint is exposed. If the readinessProbe is is needed metrics.enable must be true. true
serviceMonitor.enabled If true, a ServiceMonitor resource for the prometheus-operator is created false
serviceMonitor.namespace Optionally sets a target namespace in which to deploy the ServiceMonitor resource ""
serviceMonitor.namespaceSelector Optionally sets a namespace selector for the ServiceMonitor {}
serviceMonitor.annotations Annotations for the ServiceMonitor {}
serviceMonitor.labels Additional labels for the ServiceMonitor {}
serviceMonitor.interval Interval at which Prometheus scrapes metrics 10s
serviceMonitor.scrapeTimeout Timeout for scraping 10s
serviceMonitor.relabelings Relabelings for the Servicemonitor []
serviceMonitor.metricRelabelings metricRelabelings for the Servicemonitor []
serviceMonitor.path The path at which metrics are served {{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/metrics
serviceMonitor.port The Service port at which metrics are served http-internal
serviceMonitor.scheme The scheme to use for scraping metrics ("http" or "https"); if not set, the http.internalScheme value is used ""
serviceMonitor.tlsConfig TLS configuration for the ServiceMonitor, set CA certificates or insecureSkipVerify if Keycloak uses https {}
extraServiceMonitor.enabled If true, an additional ServiceMonitor resource for the prometheus-operator is created. Could be used for additional metrics via Keycloak Metrics SPI false
extraServiceMonitor.namespace Optionally sets a target namespace in which to deploy the additional ServiceMonitor resource ""
extraServiceMonitor.namespaceSelector Optionally sets a namespace selector for the additional ServiceMonitor {}
extraServiceMonitor.annotations Annotations for the additional ServiceMonitor {}
extraServiceMonitor.labels Additional labels for the additional ServiceMonitor {}
extraServiceMonitor.interval Interval at which Prometheus scrapes metrics 10s
extraServiceMonitor.scrapeTimeout Timeout for scraping 10s
extraServiceMonitor.relabelings Relabelings for the additional ServiceMonitor []
extraServiceMonitor.metricRelabelings metricRelabelings for the additional ServiceMonitor []
extraServiceMonitor.path The path at which metrics are served {{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/metrics
extraServiceMonitor.port The Service port at which metrics are served http-internal
extraServiceMonitor.scheme The scheme to use for scraping metrics ("http" or "https"); if not set, the http.internalScheme value is used ""
prometheusRule.enabled If true, a PrometheusRule resource for the prometheus-operator is created false
prometheusRule.namespace Optionally sets a target namespace in which to deploy the PrometheusRule resource ""
prometheusRule.annotations Annotations for the PrometheusRule {}
prometheusRule.labels Additional labels for the PrometheusRule {}
prometheusRule.rules List of rules for Prometheus []
autoscaling.enabled Enable creation of a HorizontalPodAutoscaler resource false
autoscaling.labels Additional labels for the HorizontalPodAutoscaler resource {}
autoscaling.minReplicas The minimum number of Pods when autoscaling is enabled 3
autoscaling.maxReplicas The maximum number of Pods when autoscaling is enabled 10
autoscaling.metrics The metrics configuration for the HorizontalPodAutoscaler [{"resource":{"name":"cpu","target":{"averageUtilization":80,"type":"Utilization"}},"type":"Resource"}]
autoscaling.behavior The scaling policy configuration for the HorizontalPodAutoscaler {"scaleDown":{"policies":[{"periodSeconds":300,"type":"Pods","value":1}],"stabilizationWindowSeconds":300}
test.enabled If true, test resources are created false
test.image.repository The image for the test Pod docker.io/seleniarm/standalone-chromium
test.image.tag The tag for the test Pod image 117.0
test.image.pullPolicy The image pull policy for the test Pod image IfNotPresent
test.podSecurityContext SecurityContext for the entire test Pod {"fsGroup":1000}
test.securityContext SecurityContext for the test container {"runAsNonRoot":true,"runAsUser":1000}
test.deletionPolicy helm.sh/hook-delete-policy for the test Pod before-hook-creation

Specify each parameter using the --set key=value[,key=value] argument to helm install. For example:

$ helm install keycloak codecentric/keycloakx -n keycloak --set replicas=1

Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example:

$ helm install keycloak codecentric/keycloakx -n keycloak --values values.yaml

The chart offers great flexibility. It can be configured to work with the official Keycloak-X Docker image but any custom image can be used as well.

For the official Docker image, please check it's configuration at https://github.com/keycloak/keycloak/tree/main/quarkus/container.

Usage of the tpl Function

The tpl function allows us to pass string values from values.yaml through the templating engine. It is used for the following values:

  • extraInitContainers
  • extraContainers
  • extraEnv
  • extraEnvFrom
  • affinity
  • extraVolumeMounts
  • extraVolumes
  • livenessProbe
  • readinessProbe
  • startupProbe
  • topologySpreadConstraints

Additionally, custom labels and annotations can be set on various resources the values of which being passed through tpl as well.

It is important that these values be configured as strings. Otherwise, installation will fail. See example for Google Cloud Proxy or default affinity configuration in values.yaml.

JVM Settings

Keycloak sets the following system properties by default: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m

You can override these by setting the JAVA_OPTS environment variable. Make sure you configure container support. This allows you to only configure memory using Kubernetes resources and the JVM will automatically adapt.

extraEnv: |
  - name: JAVA_OPTS
    value: >-
      -XX:MaxRAMPercentage=50.0

Alternatively one can append custom JVM options by setting the JAVA_OPTS_APPEND environment variable.

The parameter -Djava.net.preferIPv4Stack=true is optional for Keycloak >= v22.

The parameter -XX:+UseContainerSupport is no longer required for Keycloak >= v21 based on JDK v17.

The parameter -Djava.awt.headless=true is no longer required for Quarkus based Keycloak as it is set by default.

Using an External Database

The Keycloak Docker image supports various database types. Configuration happens in a generic manner.

Using a Secret Managed by the Chart

The following examples uses a PostgreSQL database with a secret that is managed by the Helm chart.

dbchecker:
  enabled: true

database:
  vendor: postgres
  hostname: mypostgres
  port: 5432
  username: '{{ .Values.dbUser }}'
  password: '{{ .Values.dbPassword }}'
  database: mydb

dbUser and dbPassword are custom values you'd then specify on the commandline using --set-string.

Using an Existing Secret

The following examples uses a PostgreSQL database with an existing secret.

dbchecker:
  enabled: true

database:
  vendor: postgres
  hostname: mypostgres
  port: 5432
  database: mydb
  username: db-user
  existingSecret: byo-db-creds # Password is retrieved via .password

Creating a Keycloak Admin User

The Keycloak-X Docker image supports creating an initial admin user. It must be configured via environment variables:

  • KEYCLOAK_ADMIN
  • KEYCLOAK_ADMIN_PASSWORD

This can be done like so in the values.yaml, where the KEYCLOAK_ADMIN is an insecure example with the value in plaintext. The KEYCLOAK_ADMIN_PASSWORD is referenced from already existing secret but for testing it can be set with value too.

extraEnv: |
  - name: KEYCLOAK_ADMIN
    value: admin
  - name: KEYCLOAK_ADMIN_PASSWORD
    valueFrom:
      secretKeyRef:
        name: keycloak-admin-password
        key: password

High Availability and Clustering

For high availability, Keycloak must be run with multiple replicas (replicas > 1). The chart has a helper template (keycloak.serviceDnsName) that creates the DNS name based on the headless service.

Default Cache Stack

The default cache stack is now using jdbc-ping which leverages a table called jgroups_ping in the keycloak database to store the cache and significantly reduces network complexity. Keycloak has set this transport stack as the default starting in 26.1.0 and it is backwards compatible with all 26.X releases.

It is recommended to use the new default value as it works in kubernetes and across multiple cloud providers alike. Currently all other options have been marked as deprecated. However, if the original value of kubernetes is required in a given environment, it can still be set by using a custom stack:

cache:
  stack: custom

Addtionally, the following environment variables would need to be added for it to function properly:

extraEnv: |
  - name: KC_CACHE
    value: "ispn"
  - name: KC_CACHE_STACK
    value: "kubernetes"
  - name: JAVA_OPTS_APPEND
    value: >-
      -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless

Custom Service Discovery

If a custom JGroups discovery is needed, then you can configure:

cache:
  stack: custom

You can then reference your custom infinispan configuration file, e.g. cache-custom.xml via the KC_CACHE_CONFIG_FILE environment variable. Note that the cache-custom.xml must be available via /opt/keycloak/conf/cache-custom.xml.

extraEnv: |
  - name: KC_CACHE
    value: "ispn"
  - name: KC_CACHE_CONFIG_FILE
    value: cache-custom.xml

Autoscaling

Due to the caches in Keycloak only replicating to a few nodes (two in the example configuration above) and the limited controls around autoscaling built into Kubernetes, it has historically been problematic to autoscale Keycloak. However, in Kubernetes 1.18 additional controls were introduced which make it possible to scale down in a more controlled manner.

The example autoscaling configuration in the values file scales from three up to a maximum of ten Pods using CPU utilization as the metric. Scaling up is done as quickly as required but scaling down is done at a maximum rate of one Pod per five minutes.

Autoscaling can be enabled as follows:

autoscaling:
  enabled: true

KUBE_PING service discovery seems to be the most reliable mechanism to use when enabling autoscaling, due to being faster than DNS_PING at detecting changes in the cluster.

Running Keycloak Behind a Reverse Proxy

When running Keycloak behind a reverse proxy, which is the case when using an ingress controller, proxy address forwarding must be enabled as follows:

extraEnv: |
  - name: KC_PROXY
    value: "passthrough"

Providing a Custom Theme

One option is certainly to provide a custom Keycloak-X image that includes the theme. However, if you prefer to stick with the official Keycloak-X image, you can use an init container as theme provider.

Create your own theme and package it up into a Docker image.

FROM busybox
COPY mytheme /mytheme

In combination with an emptyDir that is shared with the Keycloak container, configure an init container that runs your theme image and copies the theme over to the right place where Keycloak will pick it up automatically.

extraInitContainers: |
  - name: theme-provider
    image: myuser/mytheme:1
    imagePullPolicy: IfNotPresent
    command:
      - sh
    args:
      - -c
      - |
        echo "Copying theme..."
        cp -R /mytheme/* /theme
    volumeMounts:
      - name: theme
        mountPath: /theme

extraVolumeMounts: |
  - name: theme
    mountPath: /opt/keycloak/themes/mytheme

extraVolumes: |
  - name: theme
    emptyDir: {}

Using Google Cloud SQL Proxy

Depending on your environment you may need a local proxy to connect to the database. This is, e. g., the case for Google Kubernetes Engine when using Google Cloud SQL. Create the secret for the credentials as documented here and configure the proxy as a sidecar.

Because extraContainers is a string that is passed through the tpl function, it is possible to create custom values and use them in the string.

database:
  vendor: postgres
  hostname: '127.0.0.1'
  port: 5432
  database: postgres
  username: myuser
  password: mypassword

# Custom values for Google Cloud SQL
cloudsql:
  project: my-project
  region: europe-west1
  instance: my-instance

extraContainers: |
  - name: cloudsql-proxy
    image: gcr.io/cloudsql-docker/gce-proxy:1.17
    command:
      - /cloud_sql_proxy
    args:
      - -instances={{ .Values.cloudsql.project }}:{{ .Values.cloudsql.region }}:{{ .Values.cloudsql.instance }}=tcp:5432
      - -credential_file=/secrets/cloudsql/credentials.json
    volumeMounts:
      - name: cloudsql-creds
        mountPath: /secrets/cloudsql
        readOnly: true

extraVolumes: |
  - name: cloudsql-creds
    secret:
      secretName: cloudsql-instance-credentials

Changing the Context Path

By default, Keycloak-X is served under context /auth. Trailing slash is removed from path. This can be changed to another context path like / as follows:

http:
  relativePath: '/'

Alternatively, you may supply it via CLI flag:

--set-string http.relativePath=/

Prometheus Metrics Support

Keycloak Metrics

Keycloak-X can expose metrics via /auth/metrics.

Metrics are enabled by default via:

metrics:
  enabled: true

Add a ServiceMonitor if using prometheus-operator:

serviceMonitor:
  # If `true`, a ServiceMonitor resource for the prometheus-operator is created
  enabled: true

Checkout values.yaml for customizing the ServiceMonitor and for adding custom Prometheus rules.

Add annotations if you don't use prometheus-operator:

service:
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"

Keycloak Metrics SPI

Optionally, it is possible to add Keycloak Metrics SPI via init container. Note that the keycloak-metrics-spi.jar needs to be added to the /opt/keycloak/providers directory.

A separate ServiceMonitor can be enabled to scrape metrics from the SPI:

extraServiceMonitor:
  # If `true`, an additional ServiceMonitor resource for the prometheus-operator is created
  enabled: true

Checkout values.yaml for customizing this ServiceMonitor.

Note that the metrics endpoint is exposed on the HTTP port. You may want to restrict access to it in your ingress controller configuration. For ingress-nginx, this could be done as follows:

annotations:
  nginx.ingress.kubernetes.io/server-snippet: |
    location ~* /auth/realms/[^/]+/metrics {
        return 403;
    }

Extra Kubernetes Manifests

It is possible to deploy extra Kubernetes resources (such as ConfigMaps, Secrets, Jobs, or any other Kubernetes objects) alongside the Keycloak chart by using the extraManifests value. This feature supports Helm templating, allowing you to use chart helpers like {{ include "keycloak.fullname" . }} within your manifests.

extraManifests:
  - |
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ include "keycloak.fullname" . }}-extra-config
      labels:
        {{- include "keycloak.labels" . | nindent 8 }}
    data:
      custom-key: custom-value
  - |
    apiVersion: v1
    kind: Secret
    metadata:
      name: {{ include "keycloak.fullname" . }}-extra-secret
    type: Opaque
    stringData:
      my-secret-key: my-secret-value

Why StatefulSet?

The headless service that governs the StatefulSet is used for DNS discovery via DNS_PING.

Bad Gateway and Proxy Buffer Size in Nginx

A common issue with Keycloak and nginx is that the proxy buffer may be too small for what Keycloak is trying to send. This will result in a Bad Gateway (502) error. There are many issues around the internet about this. The solution is to increase the buffer size of nginx. This can be done by creating an annotation in the ingress specification:

ingress:
  annotations:
    nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"

Upgrading

Notes for upgrading from previous Keycloak chart versions.

From chart < 18.0.0

  • Keycloak is updated to 18.0.0
  • Added new health.enabled option.

Keycloak 18.0.0 allows to enable the health endpoint independently of the metrics endpoint via the health-enabled setting. We reflect that via the new config option health.enabled.

Please read the additional notes about Migrating to 18.0.0 in the Keycloak documentation.