Skip to main content

Overview

Keycloak is an open-source identity and access management platform that provides single sign-on, OIDC/SAML, user federation, and fine-grained authorization. This template runs clustered Keycloak 26 in production mode with a highly available PostgreSQL backing store by default, delivering zero-downtime restarts and upgrades.

What Gets Created

  • Stateful Keycloak Workload — 2 replicas by default, clustered via embedded Infinispan (JGroups JDBC_PING through the shared database — no extra clustering infrastructure). Setting replicas: 1 runs a dev mode with clustering fully disabled.
  • Highly Available PostgreSQL Stack (default) — The PostgreSQL Highly Available template as a subchart: 3 Patroni PostgreSQL replicas, 3 etcd replicas, and an HAProxy leader-routing workload that Keycloak connects through.
  • Single-Instance PostgreSQL Workload (optional) — The PostgreSQL template instead, for lighter dev/test deployments.
  • Volume Sets — Persistent storage for the PostgreSQL (and etcd) data.
  • Backup Cron Workload (optional) — Created by the backing store subchart when its backup pass-through is enabled.
  • Secrets — A dictionary secret with the bootstrap admin credentials, an opaque startup script secret, and the database credentials secret created by the PostgreSQL subchart.
  • Identity & Policy — An identity bound to the Keycloak workload with a least-privilege policy granting reveal access to exactly the secrets it mounts.
All durable state — realms, users, and active sessions — lives in PostgreSQL; the Keycloak tier is stateless on disk.
This template does not create a GVC. You must deploy it into an existing GVC.

Prerequisites

None for a default install. If you enable the optional database backups, you need a cloud account and a bucket for the backing store’s backup job. The backup configuration is a pass-through to the backing PostgreSQL template — follow the PostgreSQL Highly Available backup prerequisites (default store) or the PostgreSQL backup prerequisites (dev/test store).

Installation

To install, follow the instructions for your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations
Pulumi Icon Streamline Icon: https://streamlinehq.com

Pulumi

Declare templates in your Pulumi programs

Configuration

The default values.yaml for this template:
image: quay.io/keycloak/keycloak:26.6.3

# Replica count. 2+ (default) forms an Infinispan cluster over JGroups JDBC_PING
# for zero-downtime restarts. 1 = dev mode: clustering fully disabled (local cache).
replicas: 2

resources: # per replica
  cpu: 1000m
  memory: 2Gi # JVM heap is sized to 70% of this limit; do not set below 1.5Gi
  minCpu: 500m
  minMemory: 1Gi

# ─── Admin Bootstrap ──────────────────────────────────────────────────────────
# Creates a temporary admin on first boot. Log in and create a permanent admin,
# then remove the temporary one (Keycloak warns until you do).
admin:
  username: admin
  password: change-me-keycloak-admin # change before installing

# ─── Backing Store: Highly Available PostgreSQL (default) ────────────────────
# Deploys the postgres-highly-available template: 3 Patroni replicas, 3 etcd
# replicas, and an HAProxy leader-routing endpoint Keycloak connects to.
postgresHA:
  enabled: true
  postgres:
    username: keycloak
    password: change-me-keycloak-db # change before installing
    database: keycloak
  replicas: 3
  volumeset:
    capacity: 10 # initial capacity in GiB per replica (minimum is 10)

  backup: # pass-through to the postgres-highly-available template's backup feature
    enabled: false
    mode: logical # logical or wal-g
    resources:
      cpu: 100m
      memory: 128Mi
    logical:
      image: ghcr.io/controlplane-com/backup-images/postgres-backup:17.1.0
      schedule: "0 2 * * *" # daily at 2am UTC
    walg:
      intervalSeconds: 21600 # every 6 hours
    provider: aws # Options: aws, gcp, or minio
    aws:
      bucket: my-backup-bucket
      region: us-east-1
      cloudAccountName: my-backup-cloudaccount
      policyName: my-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: my-backup-bucket
      cloudAccountName: my-backup-cloudaccount
      prefix: postgres/backups
    minio: # any S3-compatible endpoint, e.g. an internal MinIO template deployment
      endpoint: http://my-minio-workload:9000
      bucket: my-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups

# ─── Backing Store: Single-instance PostgreSQL (dev/test) ────────────────────
# Enable this and disable postgresHA for a lighter non-HA deployment.
postgres:
  enabled: false
  config:
    username: keycloak
    password: change-me-keycloak-db # change before installing
    database: keycloak
  volumeset:
    capacity: 10 # initial capacity in GiB (minimum is 10)

  backup: # pass-through to the postgres template's backup feature (Postgres 17+)
    enabled: false
    image: ghcr.io/controlplane-com/backup-images/postgres-backup:18.1.0
    schedule: "0 2 * * *" # daily at 2am UTC
    resources:
      cpu: 100m
      memory: 128Mi
    provider: aws # Options: aws, gcp, or minio
    aws:
      bucket: my-backup-bucket
      region: us-east-1
      cloudAccountName: my-backup-cloudaccount
      policyName: my-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: my-backup-bucket
      cloudAccountName: my-backup-cloudaccount
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: my-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups

# ─── Access ───────────────────────────────────────────────────────────────────
publicAccess:
  enabled: true # HTTPS via the canonical *.cpln.app endpoint

internalAccess:
  type: same-gvc # options: none, same-gvc, same-org, workload-list
  workloads: [] # note: replicas > 1 requires type != none
  # workloads:
  #   - //gvc/GVC_NAME/workload/WORKLOAD_NAME

Replicas and Clustering

  • replicas2 or more (default) runs Keycloak in a cluster: the replicas form an Infinispan cluster over JGroups JDBC_PING through the shared database, so restarts and upgrades are zero-downtime and in-flight logins and sessions survive a replica restart. 1 runs a dev mode with clustering fully disabled (local cache only).
  • Clustered replicas must be able to reach each other on ports 7800/57800, so replicas > 1 requires internalAccess.type other than none — the chart enforces this at render.
  • Scaling is operator-driven: change replicas via a template upgrade. There is deliberately no autoscaling, so cluster membership only changes intentionally.

Keycloak Resources

  • resources — CPU and memory per replica. The JVM heap is sized to 70% of the memory limit; do not set memory below 1.5Gi.

Admin Bootstrap

  • admin.username / admin.password — Credentials for a temporary bootstrap admin created on first boot. Change the password before installing. After the first login, create a permanent admin account and remove the temporary one — Keycloak warns until you do.

Backing Store

Exactly one of the two stores must be enabled — the chart enforces this at render.
  • postgresHA (default) — A highly available PostgreSQL cluster from the PostgreSQL Highly Available template: 3 Patroni replicas, 3 etcd replicas, and an HAProxy endpoint that routes Keycloak’s connections to the current leader. Do not disable the HA proxy (postgresHA.proxy.enabled) — Keycloak writes through the HAProxy leader endpoint, and the chart enforces this at render.
  • postgres — A single-instance PostgreSQL from the PostgreSQL template, for lighter dev/test deployments. Set postgresHA.enabled: false and postgres.enabled: true.
  • postgresHA.postgres.* / postgres.config.* — Database credentials and database name. Change the password before installing.
  • postgresHA.volumeset.capacity / postgres.volumeset.capacity — Initial volume size in GiB (minimum 10, per replica for the HA store).

Access

  • publicAccess.enabled — Exposes Keycloak over HTTPS at the automatically assigned canonical *.cpln.app endpoint. Keep it enabled for browser-based SSO — end-user browsers must reach Keycloak’s login endpoints. Disable it only for pure service-to-service deployments; internal access keeps working.
  • internalAccess.type — Controls which workloads can reach Keycloak inside Control Plane (none, same-gvc, same-org, or workload-list). With workload-list, list the allowed workloads in internalAccess.workloads.

Backup

The postgresHA.backup and postgres.backup sections are pass-throughs to the backup feature of the corresponding backing store template. Set backup.enabled: true and fill in the provider section (aws, gcp, or minio) to schedule database backups to object storage. For provider setup, backup modes, and restore procedures, see the backing store’s documentation:

Connecting

WhatValue
Public URLstatus.canonicalEndpoint from cpln workload get {release}-keycloak -o yaml
Admin consolehttps://{canonical-endpoint}/admin
OIDC discoveryhttps://{canonical-endpoint}/realms/{realm}/.well-known/openid-configuration
In-GVC (internal)http://{release}-keycloak.{gvc}.cpln.local:8080
Admin credentialsadmin.username / admin.password values
On a first install of the default HA stack, the Keycloak container waits for the PostgreSQL cluster to come up (logging Waiting for PostgreSQL...) before starting. Expect the Keycloak workload to become ready roughly 4–5 minutes after install; the dev-mode store (postgres with replicas: 1) is ready in about 2 minutes.

Important Notes

  • Change both default passwords before installing — the admin bootstrap password and the database password. The bootstrap admin is temporary by design: log in, create a permanent admin, then remove it.
  • Keep publicAccess enabled for browser SSO — end-user browsers must reach Keycloak’s login endpoints; disable it only for pure service-to-service deployments.
  • Do not disable the HA proxy (postgresHA.proxy.enabled) — Keycloak connects through the HAProxy leader endpoint for writes; the chart enforces this at render.
  • Scaling is operator-driven — change replicas via a template upgrade; there is deliberately no autoscaling, so cluster membership only changes intentionally.
  • Database volumes survive reinstalls — uninstalling and reinstalling under the same release name reuses the persisted data unless the volume sets are deleted.

External References

Keycloak Documentation

Official Keycloak documentation

Server Configuration Reference

All Keycloak server configuration options

Caching and Clustering

How Keycloak’s Infinispan caching and clustering work

Cloud Accounts

Create a Control Plane Cloud Account for backup storage access

Keycloak Template

View the source files, default values, and chart definition