Skip to content

ADR-086: Go-based migration toolkit for Keycloak export transformation

Category: architecture Provenance: guided-ai

Decision

Provide a standalone Go binary (tools/migration-toolkit/) that transforms Keycloak realm export JSON into Helm chart values.yaml files compatible with the keycloak-realm and keycloak-client charts. The toolkit lives in the operator repository but is independently compiled with zero runtime dependencies. It emits warnings for unsupported features rather than failing hard, writes unsupported data to a sidecar file, and generates a NEXT-STEPS.md checklist for the operator. Secret values are never written to values.yaml files. Instead, the toolkit extracts secrets and generates separate manifests depending on the chosen --secret-mode: plain Kubernetes Secrets (with clear warnings about GitOps unsuitability), ExternalSecret manifests (recommended for production), or SealedSecret manifests.

Rationale

A standalone Go binary avoids adding Python packaging complexity to end users who may not have a Python environment. Go cross-compiles to all platforms and produces a single static binary. Outputting Helm values.yaml rather than raw CRDs ensures users benefit from chart-level validation, schema enforcement, and future chart upgrades without re-running the toolkit. The warn-not-fail strategy prevents blocking migration for features that can be manually configured post-migration. Secret extraction to separate manifests follows ADR-005 (no plaintext secrets) and ADR-056 (recommend ESO/Sealed Secrets).

Agent Instructions

When working on the migration toolkit, use the toolkit: Taskfile namespace (toolkit:build, toolkit:test, toolkit:lint). The toolkit is Go code under tools/migration-toolkit/ and is independent of the Python operator codebase. Output format is Helm values.yaml, NOT raw CRDs. Users consume the output via helm install/upgrade with the keycloak-realm and keycloak-client charts. Never write plaintext secrets into values files — they go into separate Secret manifests controlled by --secret-mode. The plain mode generates real Kubernetes Secret manifests with stringData (actual plaintext values) and is appropriate for development or initial bootstrapping, but NOT for GitOps workflows. For production, recommend --secret-mode=eso or --secret-mode=sealed-secrets. Default client secret settings are manageSecret: false and secretRotation.enabled: false to avoid surprising workloads outside Kubernetes. Internal Keycloak clients (account, admin-cli, broker, realm-management, security-admin-console) are skipped by default. Deprecated client fields are silently dropped. Unsupported features produce stderr warnings with GitHub issue URLs, not hard failures.

Rejected Alternatives

Python-based toolkit using the existing operator dependencies

Would require users to install Python, uv, and all operator dependencies just to run a one-time migration tool. Go produces a single binary with zero runtime dependencies.

Output raw CRD manifests instead of Helm values.yaml

Raw CRDs bypass chart-level validation, default values, and schema evolution. Users would miss out on future chart improvements and would need to manually maintain CRD compliance.

Fail hard on unsupported features

Would block migration entirely for features that may not even be needed in the new deployment. Warning strategy allows incremental migration where supported features work immediately.

Embed secrets directly in values.yaml with a warning comment

Violates ADR-005. Even with warnings, plaintext secrets in Helm values files are likely to be committed to git repositories. Instead, secrets are extracted to separate Secret manifests (--secret-mode=plain) or ExternalSecret/SealedSecret manifests. The plain mode outputs real Kubernetes Secrets with stringData for development use, but with clear warnings that these must not be committed to git.