Appearance
Seeding SPI (keycloak-seeding)
The keycloak-seeding extension automates Keycloak realm provisioning at startup. It reads JSON configuration files and idempotently creates realms, clients, roles, and groups — eliminating manual Keycloak setup steps from environment provisioning workflows.
Purpose
Without the seeding SPI, every new environment (dev, stage, preprod, uat, prod) would require a DevOps engineer to:
- Open the Keycloak admin console
- Manually create the
microtecandbusinessownerrealms - Create 10+ OIDC clients (one per MFE app)
- Configure client scopes, redirect URIs, token mappers
- Create roles and default groups
With the seeding SPI, this entire process runs automatically when the Keycloak container starts.
Idempotency
The seeding SPI is fully idempotent. It can be run any number of times (container restarts, rolling updates, re-deployments) without creating duplicate resources.
Safe to Restart
Restarting the Keycloak container will NOT create duplicate realms, clients, or roles. The SPI checks for existence before creating any resource.
Idempotency checks by resource type:
| Resource | Check Method | Behavior if Exists |
|---|---|---|
| Realm | RealmManager.getRealmByName() | Skip entirely |
| Client | realm.getClientByClientId() | Skip |
| Role | realm.getRole(roleName) | Skip |
| Group | realm.getGroupByPath() | Skip |
| User | userProvider.getUserByUsername() | Skip |
Configuration File Structure
Seed files are mounted into the container at /opt/keycloak/seed/:
/opt/keycloak/seed/
├── realm-microtec.json
├── realm-businessowner.json
└── default-users.json (optional, dev/stage only)Realm Config Schema
json
{
"realm": "microtec",
"displayName": "Microtec ERP",
"enabled": true,
"ssoSessionMaxLifespan": 36000,
"accessTokenLifespan": 1800,
"refreshTokenMaxReuse": 5,
"loginTheme": "microtec-rtl",
"accountTheme": "microtec-rtl",
"internationalizationEnabled": true,
"supportedLocales": ["ar", "en"],
"defaultLocale": "ar",
"clients": [
{
"clientId": "apps-accounting",
"protocol": "openid-connect",
"publicClient": true,
"enabled": true,
"redirectUris": [
"https://dev.microtec-test.com/accounting/*",
"http://localhost:4402/*"
],
"webOrigins": ["*"],
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false
}
],
"roles": {
"realm": [
{ "name": "erp-user", "description": "Standard ERP user" },
{ "name": "erp-admin", "description": "ERP administrator" },
{ "name": "tenant-owner", "description": "Company tenant owner" }
]
},
"groups": [
{
"name": "ERP Users",
"path": "/ERP Users",
"realmRoles": ["erp-user"]
}
]
}ConfigureRealmClients Step
After realm creation, the SPI runs a dedicated ConfigureRealmClients step that applies post-creation client configuration:
Why account-console is Disabled
The account-console client provides Keycloak's built-in self-service account management UI. For Microtec ERP:
- ERP users manage their profiles through the custom ERP application, not Keycloak's UI
- Disabling reduces the attack surface
- The
accountclient (REST API only) remains enabled for programmatic access
java
// SetClientEnabledAsync method added to SPI
public void setClientEnabledAsync(RealmModel realm, String clientId, boolean enabled) {
ClientModel client = realm.getClientByClientId(clientId);
if (client != null) {
client.setEnabled(enabled);
log.infof("Client '%s' in realm '%s' set to enabled=%b", clientId, realm.getName(), enabled);
} else {
log.warnf("Client '%s' not found in realm '%s'", clientId, realm.getName());
}
}Usage in ConfigureRealmClients:
java
// Disable account-console (self-service UI not needed)
setClientEnabledAsync(realm, "account-console", false);
// Enable account (REST API used by ERP apps)
setClientEnabledAsync(realm, "account", true);Protocol Mappers Applied
The seeding SPI automatically configures protocol mappers for JWT token enrichment:
| Mapper Name | Type | Claim | Description |
|---|---|---|---|
tenant-id | User Attribute | tenantId | Injects tenant database context |
tenant-name | User Attribute | tenantName | Human-readable company name |
user-roles | Role | roles | Realm roles in token |
phone-number | User Attribute | phoneNumber | For phone-based features |
locale | User Attribute | locale | ar/en for UI localization |
Environment-Specific Seeding
Different environments receive different seed configurations:
| Environment | default-users.json | accountTheme | Min Clients |
|---|---|---|---|
| dev | Yes (test users) | microtec-dev | All 10 MFE clients |
| stage | Yes (QA users) | microtec-rtl | All 10 MFE clients |
| preprod | No | microtec-rtl | All 10 MFE clients |
| uat | No | microtec-rtl | All 10 MFE clients |
| production | No | microtec-rtl | All 10 MFE clients |
Production Seeding
Default users are NEVER seeded in production. The default-users.json file is only mounted in dev and stage environments. Production Keycloak instances are provisioned with realms and clients only.
Container Configuration
The seed files are passed to the container via ConfigMap mount (on-prem) or Azure Blob → Init Container (Azure):
yaml
# Azure Container App environment variable
- name: KEYCLOAK_SEED_ENABLED
value: "true"
- name: KEYCLOAK_SEED_PATH
value: "/opt/keycloak/seed"
# Volume mount (via init container copying from blob)
volumeMounts:
- volumeName: seed-config
mountPath: /opt/keycloak/seed
readOnly: trueTroubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Realm not created on startup | KEYCLOAK_SEED_ENABLED=false | Set to true in CAE env vars |
| Duplicate client error | Idempotency check failed | Check Keycloak DB for partial state; verify SPI version |
account-console still enabled | ConfigureRealmClients step skipped | Check SPI logs for step execution; verify JAR version |
| Seed file not found | Volume mount failed | Check init container logs; verify blob access |
| JSON parse error | Invalid realm config | Validate JSON against schema; check special characters |
bash
# Check seeding logs in Keycloak container
kubectl logs -l app=keycloak --since=5m | grep -i "seeding\|seed\|realm"
# Or via Azure CLI for CAE
az containerapp logs show \
--name keycloak \
--resource-group mic-erp-be-dev-apps-rg \
--followRelated Documentation
- Keycloak Overview — SPI extension list and deployment
- Realm Configuration — Full client ID and OIDC reference
- Multi-Account SPI — Account switcher SPI