Example: Keycloak in-cluster
The generic recipe is in Onboard an app. This page is the Keycloak fill-in on this company’s first
Project Loom node — not a special snowflake. The next server copies workloads/keycloak/{base,overlays} and changes
hosts.
The operator lives in namespace keycloak. Each instance is an ApplicationSet app: keycloak-staging and
keycloak-prod.
flowchart TD Op[apps/keycloak-operator] --> Operator[Keycloak Operator] AS[apps/workloads.yaml] --> Stg[overlays/staging] AS --> Prod[overlays/prod] Stg --> CR1[Keycloak CR name keycloak] Stg --> PG1[keycloak-pg] Prod --> CR2[Keycloak CR name keycloak] Prod --> PG2[keycloak-pg] Operator -. manages .-> CR1 Operator -. manages .-> CR2
Operator
Section titled “Operator”apps/keycloak-operator.yaml syncs platform/keycloak-operator into keycloak, pinned to 26.6.3,
ServerSideApply (CRDs are large).
Instance + Postgres
Section titled “Instance + Postgres”workloads/keycloak/base/keycloak.yaml is HTTP-only behind Traefik. Overlay patches set hostname and Ingress host.
spec: instances: 1 db: vendor: postgres host: keycloak-pg-rw database: keycloak http: httpEnabled: true ingress: enabled: falseCNPG cluster keycloak-pg (secret keycloak-pg-app). Operator Service keycloak-service on :8080. TLS Secret
keycloak-tls. UAT uat.auth.webbies.dev (overlay still staging), prod auth.webbies.dev.
Realms
Section titled “Realms”keycloak-config-cli (Sync Job) applies workloads/keycloak/overlays/<env>/realms/*.yaml. Not KeycloakRealmImport.
First-time service
account: Provision §8. Lockout
later: Restore.
App-specific clients (Penvoice public PKCE, Talon confidential BFF, …) live in those realm files because those products are on this node. The next app adds its own realm file — that is product config, not platform process.
Auth flow (Penvoice on this node)
Section titled “Auth flow (Penvoice on this node)”The API is a resource server: it validates JWTs against that env’s issuer. Issuer URL is an Infisical value, not Git. Same pattern for any OIDC app.