Skip to content

v0.10.0

Latest

Choose a tag to compare

@github-actions github-actions released this 27 Jul 15:23

This release unifies resource identity across all CRDs: every resource now declares its Keycloak identifier in a dedicated, immutable spec field instead of inside the raw definition blob. It also scopes namespaced references to their own namespace, adds declarative role and group assignment on KeycloakUser (including client service accounts), and fixes duplicate user-profile components and an organization reconcile loop.

Breaking changes

Typed identifier fields on all resource CRDs (#101)

Every resource CRD now identifies its Keycloak object through a dedicated spec field. The field is required, is validated at admission, and is immutable once set (changing an identifier previously orphaned the old Keycloak object silently).

CRD Identifier field
KeycloakRealm, ClusterKeycloakRealm spec.realmName
KeycloakClient spec.clientId
KeycloakUser spec.username (omit for service accounts via clientRef)
KeycloakGroup, KeycloakRole, KeycloakClientScope, KeycloakComponent, KeycloakOrganization, KeycloakProtocolMapper, KeycloakIdentityProviderMapper spec.name
KeycloakIdentityProvider, KeycloakRequiredAction spec.alias

Migration

Add the spec field carrying the same value the definition uses. An identifier inside spec.definition is tolerated only when it matches the spec field, so existing definitions do not need to be rewritten; a conflicting value is rejected.

# Before
spec:
  definition:
    realm: production
    enabled: true

# After
spec:
  realmName: production    # new: required, immutable
  definition:
    realm: production      # optional; must match spec.realmName if present
    enabled: true

Unmigrated resources report InvalidIdentifier in their status and pause reconciliation until the spec field is added — nothing is deleted. The resolved identifier is surfaced in each resource's status (e.g. status.realmName) and is what dependent resources consume.

Also note: the KeycloakClient status field status.clientID was renamed to status.clientId.

Namespaced references no longer cross namespaces (#90)

The namespace property is removed from all namespaced refs (realmRef, instanceRef, clientRef, clientScopeRef, userRef, roleRef, groupRef, parentGroupRef, identityProviderRef); they now always resolve in the referring resource's own namespace. The field is silently pruned by the API server, not rejected — audit your manifests before upgrading.

Cross-namespace sharing remains fully supported through the cluster-scoped kinds: point resources in any namespace at a shared ClusterKeycloakRealm (clusterRealmRef) or ClusterKeycloakInstance (clusterInstanceRef), or co-locate the resources in one namespace.

Role and group assignments move out of the KeycloakUser definition (#94)

realmRoles, clientRoles, and groups keys inside spec.definition are now rejected with InvalidDefinition. They were previously ignored (Keycloak's user endpoint does not apply them), which commonly bit users pasting exported user representations. They are now typed spec fields that are actually reconciled — see Highlights below.

# Before (keys were silently ignored)
spec:
  username: jdoe
  definition:
    enabled: true
    realmRoles: ["offline_access"]
    groups: ["developers"]

# After (authoritatively reconciled)
spec:
  username: jdoe
  definition:
    enabled: true
  realmRoles:
    - offline_access
  groups:
    - developers

Stricter admission validation for references (#105)

CRD schemas now enforce what the API documentation always required: exactly one of realmRef/clusterRealmRef (or clientRef on users), at most one of role/roleRef, exactly one role-mapping subject, and so on. Manifests that were previously accepted with ambiguous or missing references are now rejected at admission time.

Highlights

  • Identifier unification — uniform identity handling across all resource CRDs: typed, immutable identifier fields with CEL validation, resolved identifiers surfaced in status for dependent controllers, and deletion paths that no longer issue Keycloak calls with empty identifiers. See the new Spec Layout section for the architecture behind this. (#101)
  • Declarative user roles and groupsspec.realmRoles, spec.clientRoles, and spec.groups on KeycloakUser are reconciled through Keycloak's dedicated role-mapping and group-membership endpoints, for regular users and service accounts alike. Each field is authoritative when set (an empty list removes everything) and unmanaged when omitted. Do not combine them with KeycloakRoleMapping resources for the same user. (#94)
  • Role mappings for service accountsKeycloakRoleMapping gains subject.serviceAccountRef to assign roles to a client's service account without an intermediate KeycloakUser. (#94)
  • User-profile component adoptionKeycloakComponent now adopts the unnamed declarative-user-profile component Keycloak creates when the user profile is saved through the Admin UI or /users/profile API, instead of creating a duplicate. (#104)
  • Organization drift detectionKeycloakOrganization compares desired and current state before updating, ending the continuous PUT loop that flooded logs and Keycloak. (#96)
  • Nightly container builds (#102) and GitHub Actions pinned to immutable SHAs (#103).

Upgrade Guide

1. Upgrade the operator first

The new identifier fields do not exist in the v0.9.0 CRD schemas and would be pruned if you applied migrated manifests before upgrading. Upgrade the operator (which updates the CRDs), then migrate manifests. Existing resources keep running; unmigrated ones pause reconciliation with InvalidIdentifier until step 2 — nothing is deleted.

helm upgrade keycloak-operator oci://ghcr.io/hostzero-gmbh/charts/keycloak-operator \
  --namespace keycloak-operator \
  --version 0.10.0

2. Migrate manifests

For every resource:

  1. Add the typed identifier field (see the table above) with the value currently used inside spec.definition.
  2. Remove namespace from any refs; switch cross-namespace setups to clusterRealmRef / clusterInstanceRef.
  3. On KeycloakUser, move realmRoles / clientRoles / groups out of spec.definition into the spec fields.
  4. Ensure exactly one realm/instance/subject reference is set per resource.

What's Changed

  • Feat/same namespace refs by @fkold in #90
  • fix: prevent continious update organization loop by @nejec in #96
  • chore: add nightly container builds by @nejec in #102
  • ci: pin GitHub Actions to immutable SHAs by @luxass in #103
  • fix(crd): enforce mutually exclusive references by @luxass in #105
  • chore(deps): bump softprops/action-gh-release from 3.0.0 to 3.0.1 by @dependabot[bot] in #108
  • chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 by @dependabot[bot] in #107
  • chore(deps): bump the kubernetes group with 3 updates by @dependabot[bot] in #114
  • chore(deps): bump the github-actions group with 9 updates by @dependabot[bot] in #115
  • chore(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #119
  • chore(deps): bump github.com/prometheus/client_golang from 1.23.2 to 1.24.1 by @dependabot[bot] in #118
  • chore(deps): bump github.com/go-logr/logr from 1.4.3 to 1.4.4 by @dependabot[bot] in #117
  • chore(deps): bump the kubernetes group with 3 updates by @dependabot[bot] in #116
  • Feat: identifier unification by @fkold in #101
  • feat: reconcile realm roles, client roles, and groups on KeycloakUser by @mohamedhabas11 in #94
  • fix: adopt existing user profile components by @luxass in #104

New Contributors

Full Changelog: v0.9.0...v0.10.0