Skip to main content

Getting Started with the Keycloak Realm Management chart

Prerequisites

  1. The Keycloak chart already installed and Keycloak running.
  2. Helm v3.
  3. Docker (used by the import pipeline to run keycloak-config-cli).
  4. Admin credentials for the target Keycloak instance.

Chart structure

keycloak-realm-management/
├── Chart.yaml
├── values.yaml # shared defaults
├── values.schema.json # JSON Schema for values validation
├── templates/
│ ├── master/ # master realm component files
│ ├── products/ # mia-platform realm component files
│ └── extensibility/ # mia-extensions realm component files
├── ci/ # minimal values for CI chart validation
└── Makefile # render + import pipeline

Each realm is rendered and imported independently. A separate values file per realm+environment drives the configuration.

Step 1: Create a values file

Create a values file for the mia-platform realm. At minimum, provide the realm identity, the Keycloak URL, the enabled products, and the IdP configuration:

# mia-platform-values.yaml
realmId: mia-platform
realmName: Mia Platform

urls:
keycloak: https://keycloak.example.com
console: https://console.example.com
catalog: https://catalog.example.com
aiFoundry: https://ai-foundry.example.com

products:
console: true
catalog: true
aiFoundry: true

identityProviders:
- alias: corporate-sso
displayName: Corporate SSO
enabled: true
providerId: oidc
trustEmail: true
config:
issuer: https://idp.example.com
authorizationUrl: https://idp.example.com/oauth2/authorize
tokenUrl: https://idp.example.com/oauth2/token
userInfoUrl: https://idp.example.com/oauth2/userinfo
jwksUrl: https://idp.example.com/oauth2/jwks
clientId: mia-platform-broker
clientAuthMethod: private_key_jwt
defaultScope: openid email profile
pkceEnabled: "true"
pkceMethod: S256
syncMode: FORCE
useJwksUrl: "true"
disableUserInfo: "false"
isAccessTokenJWT: "true"

See the Helm Values reference for the full list of available values.

Step 2: Render and review

Render the mia-platform realm templates to review what will be applied:

helm template keycloak-realm-management . \
-f mia-platform-values.yaml \
--show-only 'templates/products/*.yaml'

This outputs the component YAML files that keycloak-config-cli will apply.

Step 3: Import

The chart does not call keycloak-config-cli directly; import is driven by Makefile targets that render the chart and then run keycloak-config-cli via Docker.

Where the keycloak-config-cli client comes from

Each realm template (master, products, extensibility) declares its own keycloak-config-cli service-account client, with a secret resolved via Keycloak's Vault SPI as ${vault.keycloak-config-cli-client-secret}. This client is created by the realm's own import — it is not something you create manually in the admin console — but the vault entry backing its secret must already exist before that first import, otherwise Keycloak cannot resolve the secret.

Provision the vault entry through the Keycloak chart's vault.* values, before installing/upgrading Keycloak:

# keycloak values.yaml
vault:
enabled: true
secretStoreRef:
name: my-secret-store
kind: SecretStore
data:
- secretKey: keycloak-config-cli-client-secret
remoteRef:
key: secret/keycloak/keycloak-config-cli
property: clientSecret

This provisions a keycloak-vault-secrets Secret, mounted into the Keycloak pod, from which Keycloak's file-based Vault provider resolves ${vault.keycloak-config-cli-client-secret} at realm-import time.

info

Without an External Secrets SecretStore, you can create the same Secret directly, as long as vault.enabled: true and the key name matches:

kubectl create secret generic keycloak-vault-secrets \
--namespace keycloak \
--from-literal=keycloak-config-cli-client-secret="$(openssl rand -hex 32)"
note

This applies to Keycloak instances deployed via the Keycloak chart. For a customer-managed Keycloak instance, the keycloak-config-cli client must instead be created manually — see Customer Keycloak via CLI.

Once the vault secret is in place, the first import of each realm must use make import-admin-<realm> (it creates that realm's keycloak-config-cli client). Every subsequent import of the same realm can then use make import-<realm>, with KEYCLOAK_CLIENT_SECRET set to the same vault secret value and LOGIN_REALM set to that realm's ID (master, mia-platform, or mia-extensions).

Two import modes are available, depending on how keycloak-config-cli authenticates to Keycloak:

  • make import-<realm> — authenticates with a client_credentials grant against a service account client (typically keycloak-config-cli). Requires KEYCLOAK_CLIENT_SECRET and, for non-master realms, LOGIN_REALM set to the realm the service account client lives in.
  • make import-admin-<realm> — authenticates as an admin user (KEYCLOAK_USER / KEYCLOAK_PASSWORD) against the master realm. Useful for the very first import, before a keycloak-config-cli service account client exists.
# client_credentials grant (steady-state imports)
make import-products \
ENV=dev \
KEYCLOAK_URL=https://keycloak.example.com \
KEYCLOAK_CLIENT_SECRET=<keycloak-config-cli_client_secret> \
LOGIN_REALM=mia-platform

# admin user/password grant (initial bootstrap only)
make import-admin-products \
ENV=dev \
KEYCLOAK_URL=https://keycloak.example.com \
KEYCLOAK_USER=admin \
KEYCLOAK_PASSWORD=<admin_password>

make import-products (and make import-admin-products) run:

  1. hacks/template.sh to render each component file in templates/products/ for the given values file.
  2. Renders files to rendered/<ENV>/products/<values-file-name>/.
  3. Invokes keycloak-config-cli via Docker with IMPORT_FILES_LOCATIONS='/configs/*.yaml' and all resource types set to the no-delete managed policy (IMPORT_MANAGED_CLIENT, IMPORT_MANAGED_ROLE, IMPORT_MANAGED_GROUP, IMPORT_MANAGED_ORGANIZATION, etc.), plus IMPORT_REMOTESTATE_ENABLED=true.

The master realm uses the dedicated make import-master / make import-admin-master targets, which do not require --env.

To import every realm, run the target for each one individually (master, products, extensibility, or any custom realm folder under templates/):

make import-admin-master KEYCLOAK_URL=https://keycloak.example.com KEYCLOAK_USER=admin KEYCLOAK_PASSWORD=<admin_password>
make import-admin-products ENV=dev KEYCLOAK_URL=https://keycloak.example.com KEYCLOAK_USER=admin KEYCLOAK_PASSWORD=<admin_password>
make import-admin-extensibility ENV=dev KEYCLOAK_URL=https://keycloak.example.com KEYCLOAK_USER=admin KEYCLOAK_PASSWORD=<admin_password>

Step 4: Verify

After import, verify the realm in the Keycloak admin console:

  1. Navigate to the mia-platform realm.
  2. Check that the configured IdP appears under Identity Providers.
  3. Check that clients for the enabled products appear under Clients.
  4. Test the login flow by accessing a Mia Platform product URL and verifying that the IdP redirect works correctly.

Environment variables

VariableDefaultDescription
KEYCLOAK_URLhttp://localhost:8080Keycloak base URL
KEYCLOAK_USERadminAdmin username. Used only by make import-admin-* targets.
KEYCLOAK_PASSWORDadminAdmin password. Used only by make import-admin-* targets.
KEYCLOAK_CLIENT_SECRET-Client secret for the keycloak-config-cli service account client. Required by make import-* (non-admin) targets.
LOGIN_REALM-Realm containing the keycloak-config-cli service account client, used for the client_credentials grant. Required by make import-* (non-admin) targets for non-master realms.
ENVdevEnvironment name: used to organise rendered output in rendered/<ENV>/ and to resolve the default values file path values/<ENV>/<realm>-values.yaml. Not used for the master realm.
VALUESvalues/<ENV>/<realm>-values.yamlOverride the values file path passed to hacks/template.sh.