Skip to main content

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.
This template deploys into an existing GVC. It does not create or manage one. Every resource lands in the GVC you install into, so cpln workload exec, cpln logs and uninstalling all work against that GVC.

What Gets Created

Prerequisites

One dictionary secret must exist before you install. The bootstrap admin guards a login form on the public endpoint, so its credentials are a prerequisite secret rather than template values. The template creates no admin secret of its own; it references yours by name and grants the workload reveal on exactly that one secret.
1

Create the admin credentials secret

A dictionary secret holding exactly the keys username and password. Secrets are org-level, so no GVC flag is involved:
Set admin.secretName to this name.
2

Read the password back when you need it

-o yaml is required; without it the command prints only a summary table:
A missing prerequisite secret wedges the install silently. The install exits 0, every resource is created, and the Keycloak workload then never starts. Because the container never ran, cpln logs returns zero lines, which reads as a broken platform rather than a missing step.The only place the missing secret is named is status.versions[].message:
It is get-deployments — plain cpln workload get has no versions key. Once you create the secret the deployment recovers on its own; to skip the wait, force a redeployment:
The database password is not a prerequisite: this template creates the database credentials secret itself from postgres.credentials.*, so there is nothing to create — only a placeholder to change at install time. Optional database backups need a bucket plus a cloud account (AWS or GCP) or a MinIO credentials secret; see Backing Up.

Installation

Install from the marketplace registry, naming your admin secret and replacing the placeholder database password:
To install using another method, follow the instructions for your preferred tool:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Keycloak

  • replicas — 2 or 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. 1 runs with clustering disabled, for dev/test. Clustered replicas talk to each other on ports 7800 and 57800, so replicas above 1 needs an internalAccess.type other than none — the chart refuses the combination at render.
  • resources — Per-replica CPU and memory. The JVM heap is sized to 70% of maxMemory; keep it at 1.5Gi or 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

  • postgres.credentials.* — Username, password and database name for the bundled database. They feed whichever store is enabled, including the default HA store, even though the rest of the postgres block is off by default. The template writes them into the dictionary secret named by postgresHA.config.credentialsSecretName or postgres.config.credentialsSecretName, and both Keycloak and the database read that secret. Change the password before installing.

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:
Single-instance PostgreSQL (dev/test). One PostgreSQL replica from the PostgreSQL template:
  • postgresHA.config.credentialsSecretName / postgres.config.credentialsSecretName — Name of the database credentials secret this template creates. Secret names are organization-wide: a second release left on the default name is refused at install (see Troubleshooting).
  • postgresHA.proxy.enabled must stay true — 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.app endpoint. 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, or workload-list). With workload-list, list the allowed workloads in internalAccess.workloads.

Connecting

To verify the server is answering without depending on public access, forward its HTTP port and fetch the master realm’s discovery document:

First Run

1

Open the admin console

Browse to https://CANONICAL_ENDPOINT/admin. With publicAccess.enabled: false, forward the port as above and use http://localhost:8080/admin instead.
2

Sign in with the bootstrap admin

Use the username and password from your admin secret (cpln secret reveal ADMIN_SECRET_NAME -o yaml).
3

Create a permanent admin and remove the temporary one

The bootstrap account is temporary by design. In the 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.
4

Create a realm for your applications

Keep the 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 under postgresHA.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.
Provider setup. The bucket, cloud account and IAM policy for 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:
Like the admin secret, a MinIO credentials secret that does not exist at install time wedges the backup workload silently; the diagnostic is the same 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:
This restore path has not been verified end to end against a live Keycloak install. The database steps are the backing template’s, verified there; the Keycloak-specific part is only the restart above. Test a restore on a non-production release before relying on it.

Upgrading From 1.0.x

Version 1.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. An upgrade that still carries either removed key is refused at render, before anything is applied, with a message naming the replacement — for example 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.
Your existing admin password does not change on upgrade. Keycloak reads the bootstrap credentials only when no admin account exists yet, so the account already in the database is untouched by whatever the secret holds. Create the secret so the release renders, then change the password in the admin console. If the install still uses the published 1.0.x default password (change-me-keycloak-admin), treat it as compromised and change it in the console now.
Installs created on 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

Version 1.2.0 adopted the postgres 3.4.1 template for the single-instance store, which no longer takes credentials as values. This template absorbed that change rather than passing it on — there is no new prerequisite, only renames on the single-instance path: An upgrade carrying an old key is refused at render with the PostgreSQL template’s message, which tells you to create a credentials secret yourself. Ignore that part here: this template creates the database credentials secret from postgres.credentials.*. Move the keys and the upgrade proceeds. The HA path was unchanged in 1.2.0.

Upgrading From 1.2.x and 1.3.0

Version 1.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 now reads the same template-created credentials secret as the single-instance store, named by the new postgresHA.config.credentialsSecretName key: An upgrade carrying a removed key is refused at render with the PostgreSQL Highly Available template’s message, which tells you to create a credentials secret yourself; as above, ignore that part — this template creates it. Set postgres.credentials.username, password and database to the same values your install already uses under postgresHA.postgres.*: the database volume was initialised with those credentials and keeps them. Changing the database password as part of this upgrade has not been verified and is not recommended.

Upgrading From 1.3.1

Version 1.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. An upgrade that still carries a bare 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.

Scaling and Availability

  • Keycloak replicas. Change replicas and upgrade the release; there is deliberately no autoscaling, so cluster membership only changes when you change it. Clustered replicas (2 or more) share realm, user and session state through the database, so one replica restarting does not interrupt sign-ins. With replicas: 1 a 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 upgrade after 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.enabled must stay true. Adjust postgresHA.replicas and postgresHA.volumeset.capacity for 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

Cause: the admin secret named by admin.secretName (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:
Every refusal below happens before anything is applied, so a running release is untouched.
Cause: on a first install of the default HA store, the Keycloak container waits until the database actually answers as PostgreSQL — not merely accepts connections — before starting. That wait is normal while the Patroni and etcd replicas initialise, and the lines look like this:
Fix: none needed while the wait is progressing. If the container restarts repeatedly while waiting for the database, check the database tier itself:
Cause: the database credentials secret is named by a plain value (my-keycloak-db-credentials by default) and secret names are organization-wide, so a second Keycloak release on the same name tries to take over a secret the first release owns. Nothing is shared, overwritten or deleted; the second release simply does not install.Fix: give each release its own postgresHA.config.credentialsSecretName (and postgres.config.credentialsSecretName) and install again.
Cause: the bootstrap credentials are read on first boot only, when no admin account exists yet. Afterwards the account lives in the database, and neither editing the secret nor redeploying the workload changes it.Fix: sign in with the current password and change it in the admin console. If you have lost it, use Keycloak’s own bootstrap admin recovery procedure.
Cause: with 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:
Browser SSO for end users still needs a reachable login endpoint, so re-enable public access (or put Keycloak behind a domain you control) before pointing applications at it.

Important Notes

  • Create the admin secret before installing — a missing prerequisite secret wedges the deployment with zero log lines; status.versions[].message is the only diagnostic (see Prerequisites).
  • Change the database password before installing (postgres.credentials.password) — it is used exactly as given and feeds whichever store is enabled.
  • Give each release its own credentialsSecretName (postgresHA.config. and postgres.config.) — secret names are organization-wide, and a second release on the default name is refused at install.
  • 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 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 writes through the HAProxy leader endpoint; the chart refuses the install otherwise.
  • replicas above 1 needs internal access — set internalAccess.type to anything but none, or the install is refused.
  • Scaling is operator-driven — change replicas via 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.

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

Bootstrap Admin Recovery

Recovering access when the admin password is lost

Keycloak Template

View the source files, default values, and chart definition