We run Keycloak docker image in AWS ECS and we need a way to export a realm and all users for automation purposes using ansible. We can run the following command with ansible to run the export
docker exec -i 702f2fd7858d \
/bin/bash -c "export JDBC_PARAMS=?currentSchema=keycloak_service &&
/opt/jboss/keycloak/bin/standalone.sh \
-Djboss.socket.binding.port-offset=100 \
-Dkeycloak.migration.action=export \
-Dkeycloak.migration.provider=singleFile \
-Dkeycloak.migration.realmName=API \
-Dkeycloak.migration.usersExportStrategy=REALM_FILE \
-Dkeycloak.migration.file=/tmp/my_realm.json"
but the docker container continues to run after the export. We cannot grep the logs looking for the export process finishing as we use an AWS Log Driver for Docker that prevents access to any logs. It's a pity that the Keycloak REST API does not support the inclusion of users in the existing partial-export endpoint or at least to have an endpoint that triggers the export of a realm including users into a mounted filed system.
To export a realm, you can use the export command. Your Keycloak server instance must not be started when invoking this command. To export a realm to a directory, you can use the --dir <dir> option. When exporting realms to a directory, the server is going to create separate files for each realm being exported.
Create a realm called “help” and Enable it. Now I want to delete that realm right after enabling it. I navigated to master realm and under clients the realm called “help”… Now I hit the deleted button on the far right of client called “help-realm”.
I was facing the same problem a few days ago and implemented a working solution:
#!/usr/bin/env bash
#
# backup-keycloak.sh
# Copy the export bash script to the (already running) keycloak container
# to perform an export
docker cp docker-exec-cmd.sh keycloak:/tmp/docker-exec-cmd.sh
# Execute the script inside of the container
docker exec -it keycloak /tmp/docker-exec-cmd.sh
# Grab the finished export from the container
docker cp keycloak:/tmp/realms-export-single-file.json .
The Bash script to perform the export inside of the container is the following:
#!/usr/bin/env bash
#
# docker-exec-cmd.sh
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
# If something goes wrong, this script does not run forever, but times out
TIMEOUT_SECONDS=300
# Logfile for the keycloak export instance
LOGFILE=/tmp/standalone.sh.log
# destionation export file
JSON_EXPORT_FILE=/tmp/realms-export-single-file.json
# Remove files from old backups inside the container
# You could also move the files or change the name with timestamp prefix
rm -f ${LOGFILE} ${JSON_EXPORT_FILE}
# Start a new keycloak instance with exporting options enabled.
# Use the port offset argument to prevent port conflicts
# with the "real" keycloak instance.
timeout ${TIMEOUT_SECONDS}s \
/opt/jboss/keycloak/bin/standalone.sh \
-Dkeycloak.migration.action=export \
-Dkeycloak.migration.provider=singleFile \
-Dkeycloak.migration.file=${JSON_EXPORT_FILE} \
-Djboss.socket.binding.port-offset=99 \
> ${LOGFILE} &
# Grab the keycloak export instance process id
PID="${!}"
# Wait for the export to finish
# It will wait till it sees the string, which indicates
# a successful finished backup.
# If it will take too long (>TIMEOUT_SECONDS), it will be stopped.
timeout ${TIMEOUT_SECONDS}s \
grep -m 1 "Export finished successfully" <(tail -f ${LOGFILE})
# Stop the keycloak export instance
kill ${PID}
I came up with this one-liner:
sh -c 'echo $$; exec /opt/jboss/keycloak/bin/standalone.sh -Djboss.socket.binding.port-offset=98 -Dkeycloak.migration.action=export -Dkeycloak.migration.provider=dir -Dkeycloak.migration.dir=/tmp/realms/' | { read pid; while read -r line; do echo "$line"; test "$line" = "${line% Export finished successfully}" || kill $pid; done; }
It does not have any timeout logic it just waits for Export finished successfully. It should be posix compatible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With