How do you manage your realm configuration?

We just started using Keycloak, and we wonder how to properly manage realm configuration for our servers.

We’re reluctant to configure realms via UI (-only) because it’s hard to keep track of what’s changed. After some time and changes by different people, knowledge of what’s actually configured gets lost. So we want to adopt „configuration as code“ and started using keycloak-config-cli (GitHub - adorsys/keycloak-config-cli: Import YAML/JSON-formatted configuration files into Keycloak - Configuration as Code for Keycloak.) which looks promising: we can keep our configuration in a 'realm.yaml‘ and automatically bring servers to a well-defined state.

Our realm.yaml holds a complete realm definition, but without defaults and without ids. E.g. it only contains clients we added or changed; unchanged clients that come with keycloak are omitted. Technically, our realm.yaml is the output of „kcadm.sh create realms/our-realm/partial-export“ with only those parts we added or changed, and without ids.

However, we also need the UI to experiment with configuration changes, and UI+export is the only way (we know) to figure out the yaml syntax. To add UI changes back to our realm.yaml, we use the above export and diff it against the previous export (i.e. export before the ui changes). This works ok since we wrote a simple normalization script (which mostly normalizes ids and sorts arrays, see below).

So here’s my question: given your experience, does it make sense to manage configuration like that? Do you have a similar workflow? Or what problems do you see, what’s your preferred way to do it?

Regards Michael

#!/bin/sh
if [ “$#” -ne 1 ] ; then
echo “Normalize arrays and ids”
echo “usage: normalize.sh ”
exit 1
fi

set -e
json=$(cat “$1”)
json=$(echo “${json}” | jq ‘.clientScopes = (.clientScopes | sort_by(.name))’)
json=$(echo “${json}” | jq ‘(… | select(.protocolMappers?) | .protocolMappers) |= sort_by(.name)’)
json=$(echo “${json}” | jq ‘(.components | .[“org.keycloak.keys.KeyProvider”]) |= sort_by(.name)’)
json=$(echo “${json}” | jq ‘(.components | .[“org.keycloak.storage.UserStorageProvider”] | . | .subComponents | .[“org.keycloak.storage.ldap.mappers.LDAPStorageMapper”]) |= sort_by(.name)’)

json=$(echo “${json}” | jq ‘(.components | .[“org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy”]) |= sort_by(.name, .subType)’)
json=$(echo “${json}” | jq ‘(… | select(.[“allowed-protocol-mapper-types”]?) | .[“allowed-protocol-mapper-types”] ) |= sort’)
json=$(echo “${json}” | jq '(… | select(.id?) | .id) |= “XXX” ')
echo “${json}” | jq --sort-keys

Hello Michael,

I would appreciate if you could please somehow provide (me) the script normalize.sh ? I copied it from your post, did some replacement of the “ and ‘ but that wasn’t enough to make it valid.

Thank you

Ramón