Skip to content

ADR-011: Switch Keycloak to Official quay.io Image

Status

Accepted

Date

2026-03-21

Supersedes

Parts of ADR-009 — the deployment mechanism and database choice. The core decision to use Keycloak as the identity provider remains unchanged.

Context

ADR-009 chose the Bitnami Helm chart for Keycloak with a bundled PostgreSQL database. Thirteen days after deployment, both pods entered ImagePullBackOff with the error:

manifest for bitnami/keycloak:26.3.2-debian-12-r0 not found: manifest unknown
manifest for bitnami/postgresql:17.4.0-debian-12-r17 not found: manifest unknown

Root cause: Bitnami removed all container images from Docker Hub. Images are now only available via a paid Bitnami subscription. The chart (bitnami/keycloak:24.9.0) still specifies docker.io/bitnami/keycloak as the image repository, but those tags no longer exist publicly.

A replacement deployment model is needed that uses publicly available images without changing the identity provider choice.

Decision

Replace the Bitnami HelmRelease with a plain Kubernetes Deployment using the official Keycloak image from quay.io/keycloak/keycloak:26.3 (Red Hat / Keycloak project's own registry).

Run mode: start-dev — Keycloak's development mode uses an embedded H2 database, eliminating the PostgreSQL dependency entirely.

Realm bootstrapping: The --import-realm flag reads all *.json files from /opt/keycloak/data/import/ on startup. The realm-config.sops.yaml ConfigMap (SOPS-encrypted) is mounted there, so the homekube realm, clients, roles, and users are automatically imported every time Keycloak starts.

containers:
  - image: quay.io/keycloak/keycloak:26.3
    args:
      - start-dev
      - --import-realm
    volumeMounts:
      - name: realm-config
        mountPath: /opt/keycloak/data/import

Files:

Old New
identity/sources.yaml (Bitnami HelmRepository) Removed
identity/keycloak.yaml (HelmRelease) Removed
identity/keycloak-deployment.yaml (Deployment + Service + Ingress)
identity/realm-config.yaml (plaintext ConfigMap) identity/realm-config.sops.yaml (SOPS-encrypted ConfigMap)

Alternatives Considered

Option Reason Not Chosen
Pay for Bitnami subscription Adds cost and vendor dependency to a free learning environment
Codecentric Keycloak Helm chart Uses the official Keycloak image internally; adds Helm chart indirection for no benefit in a simple deployment
Switch to Authentik or Dex Different products — would negate the Keycloak learning investment already made
Pin to an older Bitnami tag The tags are gone — Docker Hub returns manifest unknown for all Bitnami tags

Consequences

Positive

  • Uses the official Keycloak project image — no third-party packaging layer
  • Eliminates PostgreSQL dependency — fewer pods, less RAM (~256 MB saved)
  • Simpler manifest — plain Deployment instead of HelmRelease with subchart
  • Realm config is fully GitOps via --import-realm — no manual UI setup required
  • quay.io is a stable, publicly available registry with no rate limits

Negative

  • start-dev mode: realm data is not persisted — Keycloak rebuilds its database from the GitOps realm JSON on every pod restart. Any changes made via the admin UI are lost unless committed to realm-config.sops.yaml
  • start-dev mode is not suitable for production — this is an explicit local-sandbox trade-off
  • H2 embedded database has no external access (acceptable since realm config is in Git)

Updating the Realm Config

Because realm data is ephemeral, all realm changes must go through Git:

# Edit the encrypted realm JSON
sops identity/realm-config.sops.yaml

# Commit and push
git add identity/realm-config.sops.yaml
git commit -m "feat: add new OIDC client"
git push origin main

# Restart Keycloak to reimport
kubectl rollout restart deployment/keycloak -n identity

Trade-offs

Simplicity and zero cost are prioritised over data persistence. For a local sandbox where minikube delete already resets all state, an ephemeral H2 database is no worse than a persistent PostgreSQL that would also be deleted.