Overview
Keycloak is an open-source identity and access management platform that provides single sign-on, OIDC and SAML identity federation, user federation (LDAP and Active Directory), social login, and fine-grained authorization. This template runs Keycloak 26 in production mode, clustered across two replicas by default, with a highly available PostgreSQL backing store so that restarts and upgrades do not interrupt sign-ins. A lighter single-instance PostgreSQL store is available for dev/test. All durable state — realms, users, and active sessions — lives in PostgreSQL. The Keycloak tier itself keeps nothing on disk, so it has no volume set of its own.cpln workload exec, cpln logs and uninstalling all work against that GVC.What Gets Created
Prerequisites
Two dictionary secrets must exist before you install. The database credentials and the bootstrap admin login (which guards a login form on the public endpoint) are prerequisite secrets rather than template values. The template creates neither; it references yours by name and grants the workloadreveal on exactly those secrets.
Create the database credentials secret
username, password and database. The bundled PostgreSQL initializes with them and Keycloak connects with them:postgresHA.config.credentialsSecretName (HA, the default) or postgres.config.credentialsSecretName (single-instance). Secret names are org-wide, so give each release its own. database must be URL-safe (letters, digits, _) because Keycloak’s JDBC URL is assembled from it at container start. PostgreSQL reads the secret only when its data is first initialized — see Rotating the Database Password.Create the admin credentials secret
username and password. Secrets are org-level, so no GVC flag is involved:admin.secretName to this name.Read the password back when you need it
-o yaml is required; without it the command prints only a summary table:Installation
Install from the marketplace registry, naming your two secrets:postgres.config.credentialsSecretName instead.
To install using another method, follow the instructions for your preferred tool:
UI
CLI
Terraform
Pulumi
Configuration
Keycloak
replicas—2or more runs Keycloak as a cluster: the replicas discover each other through the shared database, so a single replica restarting does not interrupt sign-ins.1runs with clustering disabled, for dev/test. Clustered replicas talk to each other on ports7800and57800, soreplicasabove1needs aninternalAccess.typeother thannone— the chart refuses the combination at render.resources— Per-replica CPU and memory. The JVM heap is sized to 70% ofmaxMemory; keep it at1.5Gior above. The block exposes both a reservation (minCpu,minMemory) and a limit (maxCpu,maxMemory).
Admin Bootstrap
admin.secretName— The dictionary secret you created in Prerequisites. Keycloak reads it on first boot only, to create a temporary bootstrap admin when no admin account exists yet. Editing the secret on a running install changes nothing; change the password in the admin console instead, and remove the temporary account once you have created a permanent one (see First Run).
Database Credentials
postgresHA.config.credentialsSecretName/postgres.config.credentialsSecretName— Name of the dictionary secret you created in Prerequisites, holdingusername,passwordanddatabase. Set it in the block of the store you enable; both Keycloak and the database read that secret.
Backing Store
Exactly one of the two stores must be enabled; the chart refuses both-on and both-off at render. Highly available PostgreSQL (default). Three Patroni-managed PostgreSQL replicas, three etcd replicas and an HAProxy endpoint that routes Keycloak’s connections to the current leader, from the PostgreSQL Highly Available template:postgresHA.config.credentialsSecretName/postgres.config.credentialsSecretName— Name of your database credentials secret (see Database Credentials). Secret names are organization-wide, so give each release its own.postgresHA.proxy.enabledmust staytrue— Keycloak writes through the HAProxy leader endpoint, and the chart refuses the install at render if it is disabled.- Any other setting of the backing template can be set under the same prefix (
postgresHA.pgbouncer.*,postgresHA.etcd.*,postgres.pgbouncer.*, volume-set autoscaling, and so on); see the backing template’s page for those keys.
Access
publicAccess.enabled— Exposes Keycloak over HTTPS at the automatically assigned canonical*.cpln.appendpoint. It is on by default because Keycloak is the identity provider your applications’ users sign in to: browsers must reach its login and OIDC endpoints for SSO to work at all. Disable it only for pure service-to-service deployments; internal access keeps working. An access change can take a couple of minutes to take effect, so re-test rather than trusting the first response.internalAccess.type— Which workloads can reach Keycloak inside Control Plane (none,same-gvc,same-org, orworkload-list). Withworkload-list, list the allowed workloads ininternalAccess.workloads.
Connecting
First Run
Open the admin console
https://CANONICAL_ENDPOINT/admin. With publicAccess.enabled: false, forward the port as above and use http://localhost:8080/admin instead.Sign in with the bootstrap admin
username and password from your admin secret (cpln secret reveal ADMIN_SECRET_NAME -o yaml).Create a permanent admin and remove the temporary one
master realm, create a permanent admin user with the admin role, sign in as that user, and delete the bootstrap account. Keycloak shows a warning in the console until the temporary account is gone.Create a realm for your applications
master realm for administration and register your applications as clients in a realm of their own. Their OIDC discovery URL is the one in the table above, with REALM_NAME replaced.Operations
Backing Up
Backups are a pass-through to the backing store’s backup feature: everything underpostgresHA.backup is handed to the PostgreSQL Highly Available template, and everything under postgres.backup to the PostgreSQL template. Set enabled: true and fill in the section for your provider.
aws and gcp are set up exactly as for the backing template — follow the PostgreSQL Highly Available backup prerequisites for the default store or the PostgreSQL backup prerequisites for the single-instance store, and use the key names shown above (prefixed with postgresHA. or postgres.). Backup modes and schedules are described under PostgreSQL Highly Available — Backup and PostgreSQL — Backup.
MinIO is the one provider with a prerequisite secret. Before enabling provider: minio, create a dictionary secret holding exactly the keys accessKey and secretKey, and set postgresHA.backup.minio.credentialsSecretName (or postgres.backup.minio.credentialsSecretName) to its name. For the MinIO template these are its admin.username and admin.password:
status.versions[].message described in Prerequisites.
Restoring a Backup
Keycloak keeps no state outside PostgreSQL, so restoring Keycloak means restoring its database. Follow the backing store’s restore procedure — PostgreSQL Highly Available — Restoring a Backup for the default store, PostgreSQL — Restoring a Backup for the single-instance store — against the database host and credentials listed under Connecting. Then restart Keycloak so every replica reloads from the restored database rather than from its in-memory caches:Rotating the Database Password
PostgreSQL keeps the password it was initialized with, and a running workload keeps the values it started with, so on the single-instance store a rotation takes three steps in order (on the HA store follow Rotating the Database Password in HA Mode instead):-
Change it in the database:
ALTER ROLE DB_USERNAME PASSWORD 'NEW_PASSWORD';(DB_USERNAMEis the secret’susername; connect as that user from inside the GVC). -
Update the secret — export it, change only
password, and apply it: -
Right away, redeploy Keycloak:
Rotating the Database Password in HA Mode
The HA store (postgresHA) needs its own order. The replication role repl shares the password, and a member that restarts with the old password can be promoted to leader, which splits the cluster. Move the leader to member -0 first, so it restarts last, after every other member already has the new password. pgx runs a command in one member (LOCATION is your GVC’s location, DB_USERNAME the secret’s username):
RELEASE_NAME-keycloak, which keeps the old password until it restarts. The database drops connections briefly at each switchover, and Keycloak cannot open new connections from the ALTER ROLE until its own redeploy finishes, so rotate in a quiet window. If a member stays starting, or running without streaming, re-copy it from the leader. This copies the whole database, so it costs network traffic in proportion to its size:
Upgrading From 1.0.x
Version1.1.0 moved the bootstrap admin login out of Helm values and into the prerequisite dictionary secret described in Prerequisites. Earlier versions shipped a username and a working default password as values.
keycloak: admin.password was REMOVED in 1.1.0. Put it in a dictionary secret (key: password) together with username, and set admin.secretName to that secret's name. Leaving admin.secretName empty is refused the same way. There is no compatibility fallback.
1.0.x default password (change-me-keycloak-admin), treat it as compromised and change it in the console now.1.0.0 with the default HA store also predate the etcd history compaction that the bundled PostgreSQL Highly Available template now turns on. Upgrading stops further growth of the etcd backend but cannot shrink one that has already grown; see that template’s page for the symptoms and recovery.
Upgrading From 1.1.0
Version1.2.0 adopted the postgres 3.4.1 template for the single-instance store, which no longer takes credentials as values:
postgres.config.credentialsSecretName to its name, and remove the old keys. The HA path was unchanged in 1.2.0.
Upgrading From 1.2.x and 1.3.0
Version1.3.0 adopted the postgres-highly-available 2.5.0 template for the default store, which likewise no longer takes credentials as values. The HA store reads the database credentials secret named by postgresHA.config.credentialsSecretName:
postgresHA.postgres.* into the database credentials secret under Prerequisites — the database volume was initialized with those credentials and keeps them — set postgresHA.config.credentialsSecretName to its name, and delete the postgresHA.postgres block. Do not change the database password as part of this upgrade.
Upgrading From 1.3.1
Version1.4.0 renamed the Keycloak resource limits so it is unambiguous which number is the ceiling. Rename the two keys in your values; nothing else changed.
resources.cpu or resources.memory is refused at render: keycloak: resources.cpu was RENAMED to resources.maxCpu. The reservation keys minCpu and minMemory are unchanged.
Upgrading From 1.4.0
Version1.5.0 removed postgres.credentials: the database credentials are now a prerequisite secret, the same one the database templates require on their own. Carrying the old key forward fails the render.
1.4.0 created the database secret itself, so this upgrade deletes it. Before upgrading, create a secret under a new name holding the values your database was initialized with — not new ones, or Keycloak loses its database connection:
postgres.credentials of the 1.4.0 release, and also in the old secret (cpln secret reveal my-keycloak-db-credentials -o yaml, or the name your release set in credentialsSecretName) until the upgrade deletes it. Then upgrade with postgresHA.config.credentialsSecretName (HA store) or postgres.config.credentialsSecretName (single-instance store) set to the new name, and postgres.credentials removed.
The upgrade restarts the bundled PostgreSQL too (it now reads the new secret), so Keycloak can briefly lose its database; it reconnects by itself. The new version of a workload can also wait several minutes with is not allowed to reveal the secret in get-deployments while access to the new secret propagates; the previous version keeps serving meanwhile, and it clears by itself.
Upgrading From 1.5.0
Version1.5.1 moves Keycloak from 26.6.3 to 26.8.1, which fixes an unauthenticated account-takeover vulnerability in the reset-credentials flow (CVE-2026-18963). No values change: upgrade with the values you already use. If your values set image (installs made through the Console wizard store it), change it to quay.io/keycloak/keycloak:26.8.1 or remove it; the chart refuses an official Keycloak image older than 26.7.2.
The first 26.8.1 server to start migrates the database schema, and Keycloak cannot run an older version against a migrated database, so this upgrade cannot be rolled back to 1.5.0: a rolled-back release reports healthy, but every login page fails with HTTP 500. Take a database backup before upgrading (see Backing Up); to recover from a rollback, upgrade to 1.5.1 again or restore the backup.
With 2 or more replicas Keycloak keeps serving throughout the upgrade, apart from the brief interruption of database writes in HA mode described below. With replicas: 1, Keycloak is unavailable while its single server restarts.
In HA mode, 1.5.1 also moves the database to controlplanecorporation/patroni-postgres:0.8, which carries pgvector 0.8.7 (CVE-2026-103484). The database members restart, so expect a brief interruption of writes while the leader changes, even with 2 or more Keycloak replicas. Upgrade in a quiet window. Keycloak does not use the vector extension; if you created it yourself in a database, run ALTER EXTENSION vector UPDATE; there after the upgrade. If your values set postgresHA.image, set it to the 0.8 tag: tags 0.1 to 0.7 are refused at render.
Scaling and Availability
- Keycloak replicas. Change
replicasand upgrade the release; there is deliberately no autoscaling, so cluster membership only changes when you change it. Clustered replicas (2or more) share realm, user and session state through the database, so one replica restarting does not interrupt sign-ins. Withreplicas: 1a restart is a short outage. - Rolling upgrades are not guaranteed to restart one replica at a time. Realms, users and sessions live in PostgreSQL and survive regardless, but plan for a brief gap in availability during a template upgrade rather than assuming a strictly serialized rollout.
- The first
helm upgradeafter an install can restart the bundled database even when none of its values changed; Keycloak waits for it and resumes. - Database tier. The default store runs three Patroni replicas with automatic leader failover; Keycloak always connects through the HAProxy leader endpoint, which is why
postgresHA.proxy.enabledmust staytrue. AdjustpostgresHA.replicasandpostgresHA.volumeset.capacityfor size; the single-instance store (postgres.enabled: true) trades failover for a smaller footprint. - Uninstalling deletes the database volume sets. The database volume set (and, in HA mode, etcd’s) is deleted with the release, so data does not survive a reinstall — enable backups.
Troubleshooting
The Keycloak workload never starts and cpln logs returns nothing
The Keycloak workload never starts and cpln logs returns nothing
admin.secretName, the database credentials secret named by postgresHA.config.credentialsSecretName or postgres.config.credentialsSecretName (or, with MinIO backups, the secret named by backup.minio.credentialsSecretName) does not exist. The container never ran, so there is nothing to log.Fix: read the message that names the missing secret, create it, then force a redeployment to skip the wait:The install or upgrade is refused at render
The install or upgrade is refused at render
Logs show Waiting for PostgreSQL for several minutes
Logs show Waiting for PostgreSQL for several minutes
I changed the admin secret but the old password still works
I changed the admin secret but the old password still works
The admin console is unreachable with publicAccess disabled
The admin console is unreachable with publicAccess disabled
publicAccess.enabled: false there is no canonical endpoint to browse to; only workloads inside Control Plane can reach Keycloak.Fix: forward the HTTP port and open http://localhost:8080/admin:Important Notes
- Create the admin and database credentials secrets before installing — a missing prerequisite secret wedges the deployment with zero log lines;
status.versions[].messageis the only diagnostic (see Prerequisites). - Rotating the database password needs
ALTER ROLEplus a forced redeployment of Keycloak (and a leader switchover first on the HA store) — see Rotating the Database Password. - Give each release its own database credentials secret — secret names are organization-wide.
- The bootstrap admin is temporary by design — sign in, create a permanent admin, then delete the bootstrap account. Its credentials are read on first boot only, so change the password in the console, not by editing the secret.
- Keep
publicAccessenabled 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 writes through the HAProxy leader endpoint; the chart refuses the install otherwise. replicasabove1needs internal access — setinternalAccess.typeto anything butnone, or the install is refused.- Scaling is operator-driven — change
replicasvia a template upgrade; there is deliberately no autoscaling. - Uninstalling deletes the database volume sets — the database (and, in HA mode, etcd) volume sets go with the release, so data does not survive a reinstall. Enable backups.