A Kubernetes operator that configures existing Keycloak instances.
cmd/main.go
└── registers all controllers with controller-runtime manager
api/v1/ — CRD type definitions (spec + status structs, webhooks)
api/v1alpha1/ — Alpha CRDs: ClusterKeycloak, ClusterKeycloakRealm, KeycloakOrganization
internal/controller/{resource}/
├── reconciler.go — Reconcile() entry point, fetches K8s resource, drives chain
└── chain/ — Sequential handler steps (chain of responsibility pattern)
internal/controller/helper/ — Shared: Keycloak client factory, finalizers, failure tracking
internal/webhook/v1/ — Admission webhooks for KeycloakClient (defaulting) and KeycloakRealm (validation)
pkg/client/keycloakv2/ — oapi-codegen generated Keycloak client
config/ — Kustomize manifests (crd, rbac, manager, webhook, certmanager, prometheus, etc.)
deploy-templates/ — Helm chart: values.yaml, templates/, crds/, _crd_examples/; README auto-generated by helm-docs
bundle/ — OLM bundle manifests for OperatorHub publication
tests/e2e/ — KUTTL test suites (one directory per scenario, e.g. helm-success-path); run with make e2e on kind
pkg/client/keycloakv2/ — oapi-codegen generated client wired through resty HTTP client (auth, retries, TLS). Key files:
keycloak_client.go—KeycloakClient, constructorNewKeycloakClient(ctx, url, clientId, ...opts), options pattern, resty-backedhttpClientgroup.go,roles.go,clients.go,users.go— resource-specific method groupsgenerated/client_generated.go— ~58k lines of oapi-codegen output; do not edit manually
Go 1.25, Docker, kubectl, kind, make
make build # compile binary
go run cmd/main.go # run locally (needs WATCH_NAMESPACE, OPERATOR_NAMESPACE env vars)
make test # unit tests
TEST_KEYCLOAK_URL=http://localhost:8086 make test # unit + integration
make start-keycloak # starts Keycloak on port 8086 via Docker
make e2e # kind-based KUTTL e2e tests
make lint-fix # run golangci-lint (config: .golangci.yaml) with auto-fix where possible
make generate # DeepCopy methods (kubebuilder markers)
make manifests # CRDs, RBAC, webhooks → config/
make mocks # test mocks via mockery
KEYCLOAK_VERSION=26.5.2 make generate-keycloak-go-client # regenerate oapi client (rare)
- Create
internal/controller/{resource}/chain/my_step.goimplementing the handler interface. - Wire it into
chain/chain.goin the correct call order. - Add a
_test.goalongside it; use Ginkgo + Gomega.
pkg/client/keycloakv2/generated/client_generated.go is auto-generated — do not edit manually.
Edit pkg/client/keycloakv2/openapi.yaml then re-run make generate-keycloak-go-client.
docs/development.md— local setup, debugging, VS Code config