Keycloak is an open source Identity and Access Management (IAM) solution that’s easy to run in Docker using a Configuration as Code (CAC) strategy enabling a workflow where a git source control repository can be cloned by a developer who can run one non-interactive script that starts Keycloak and gets it into a consistent state ready for use. Using this approach, most developers wouldn’t even need to know anything about Keycloak; they can just focus on developing and testing against its standard interfaces (such as OAuth2). However, developers will quickly hit a bump in the road: the Keycloak export created in the UI doesn’t include users nor does it include client secrets. In other words, when that export is imported, that data is missing. Which means that each time the import runs, Keycloak generates new client secrets and there no no users, which is clearly not a reproducible, consistent, usable state for the development team. Here are some workarounds for that shortcoming.
Note that actual, production secrets and other sensitive information should never be saved in source control and shared amongst a team. Only testing secrets used for developers in their development effort should be stored in that fashion.
Option A: Use Keycloak’s Export Command Line Option
One way to work around this omission of data is to use a different approach to the export. The documentation covers a way to stop Keycloak then use a command line option to generated a realm data export json file that does include users and secrets. However, that approach has a significant downside in that it requires Keycloak to be stopped and it’s harder to automate, especially when an ephemeral database (such as H2) is used.
Option B: Edit the Administrative Interface’s Realm Export Json
Another approach is to add the missing data to the realm export json. To use this approach, use the administrative interface’s export function to save the realm export json file then open in an edit.
- To add a client secret, search for the client with the secret that should be saved (for example, search for
"clientId": "my-client-app"
) and find the"secret": "**********"
within it, and replace the stars with the client secret that should be saved. - To add users, for example, add the following before the final
}
:
,
"users": [
{
"username": "user",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password"
}
],
"clientRoles": {
"realm-management": [ "realm-admin" ],
"account": [ "manage-account" ]
}
}
]
Using the Realm Export
With this realm export json that now contains secrets and users, it can be committed to source control and used by developers to create consistent, reproducible experience for the whole team. In the following example, the realm data file is named application-realm.json
.
---
version: "3.8"
services:
postgres:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: application
POSTGRES_USER: application
POSTGRES_PASSWORD: supersecretpassword
networks:
- common-network
keycloak:
image: jboss/keycloak
volumes:
- type: bind
source: ./application-realm.json
target: /application-realm.json
read_only: true
ports:
- "8180:8180"
command:
- "-Djboss.socket.binding.port-offset=100"
- "-Dkeycloak.migration.action=import"
- "-Dkeycloak.migration.provider=singleFile"
- "-Dkeycloak.migration.strategy=OVERWRITE_EXISTING"
- "-Dkeycloak.migration.file=/application-realm.json"
environment:
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: application
DB_USER: application
DB_PASSWORD: supersecretpassword
DB_SCHEMA: public
KEYCLOAK_USER: keycloak-admin
KEYCLOAK_PASSWORD: keycloak-password
KEYCLOAK_HOSTNAME: localhost
KEYCLOAK_FRONTEND_URL: http://localhost:8180/auth
depends_on:
- postgres
networks:
- common-network
networks:
common-network:
driver: bridge
volumes:
postgres_data:
driver: local
Note that keycloak.migration.* properties are used instead of jboss/keycloak’s KEYCLOAK_IMPORT environment variable. KEYCLOAK_IMPORT
will not overwite existing realm data and has no option that can do so. keycloak.migration.*
can overwrite existing realm data. Overwriting existing realm data is important because it makes the Keycloak state reproducible – anyone who runs this docker-compose configuration will end up with Keycloak in the same state as anyone else.