Skip to content

Keycloak Operator

A Kubernetes operator that manages Keycloak instances declaratively via Custom Resource Definitions. Describe the instance you want in YAML, and the operator renders and owns the StatefulSet, Services, Ingresses, and Secrets — there is no Helm chart or Flux HelmRelease in the loop.

Who this is for

Platform Engineers

You run Kubernetes and want to offer managed Keycloak as a self-service product to internal teams or external customers. Start with Installation, then the KeycloakInstance Guide to understand the full configuration surface.

Managed-Service Operators

You operate Keycloak for multiple tenants and need declarative provisioning, custom themes/SPI providers, and safe version upgrades without handwriting StatefulSet manifests per customer. Start with the Quick Start, then Upgrades & Version Management.

Single-Instance Administrators

You administer one Keycloak for your organisation and want declarative version management and reproducible configuration instead of manual rollouts. Start with the Quick Start.

Not sure yet?

Follow the Quick Start — it deploys a working Keycloak instance with BYO Postgres in a few minutes and introduces both CRDs.

Architecture at a glance

flowchart LR
    HQ([hq / user\nkubectl apply]) -->|KeycloakInstance CR| K8s[(Kubernetes API)]
    K8s --> Op[bnerd-keycloak-operator\nreconcile loop]

    Op -->|renders + owns| STS[StatefulSet\nKeycloak pods]
    Op -->|renders + owns| Svc[Services\nclient + headless discovery]
    Op -->|renders + owns| Ing[Ingresses\npublic + admin]
    Op -->|creates/owns| Sec[Operator Secrets\nadmin bootstrap]
    Op -->|optional, capability-gated| PG[PerconaPGCluster\nPercona PG Operator]

    STS --> Pods[Keycloak Pods]
    Svc --> Pods
    Ing --> Pods
    Sec --> Pods
    PG --> Pods

    style Op fill:#6366f1,stroke:#4f46e5,color:#fff
    style STS fill:#16a34a,stroke:#15803d,color:#fff

Unlike bnerd-gitlab-operator, this operator is a raw-resource engine: it renders and owns the Keycloak StatefulSet, Services, Ingresses, and Secrets directly, with no Helm/Flux indirection. See the KeycloakInstance Guide for the full reconcile picture.

Why this operator instead of plain manifests?

Concern Plain manifests This Operator
Backend provisioning Manual PerconaPGCluster setup postgres.managed: true auto-provisions, capability-gated on the Percona CRD
Credential management Inline or manually-created Secrets Admin bootstrap credentials always via Secret — generated once, or bring-your-own
Theme / SPI providers Custom image builds baking JARs into the Keycloak image spec.providers injects JARs via initContainers — no custom Keycloak image needed
Version upgrades Manual rolling update, no cross-minor safety Bump spec.version; same-minor rolls in place, cross-minor is a supervised drain-first recreate
Downgrade safety Your responsibility Downgrades are refused by default (break-glass annotation to override)
Status observability kubectl get pods + logs CRD status subresource: phase, host, observedVersion, conditions

CRDs at a glance

CRD Scope Short name Purpose
KeycloakInstance Namespaced kci One CR = one Keycloak deployment. The primary workload resource.
KeycloakVersionMap Cluster kcvm Maps Keycloak version strings/aliases to container images.

API version: k8s.bnerd.com/v1alpha1.