Search code examples
exportkeycloak

how to get keycloak to export realm users and then exit


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.


Solution

  • 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}