diff --git a/Dockerfile b/Dockerfile index a67e0e8..1366c3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,47 @@ # syntax=docker/dockerfile:1 -ARG BUILD_IMAGE=alpine:3.19.1 -ARG RUN_IMAGE=quay.io/keycloak/keycloak:20.0.5 +ARG BUILD_IMAGE=registry.access.redhat.com/ubi9 +ARG RUN_IMAGE=quay.io/keycloak/keycloak:26.0.7 + +ARG ORACLE_DRIVER_URL=https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/23.5.0.24.07/ojdbc11-23.5.0.24.07.jar +ARG ORACLE_NLS_URL=https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/23.5.0.24.07/orai18n-23.5.0.24.07.jar ################## Stage 0 FROM ${BUILD_IMAGE} as builder +ARG ORACLE_DRIVER_URL +ARG ORACLE_NLS_URL + USER root -WORKDIR / -COPY . /app -## Let's minimize layers in final-product by organizing files into a single copy structure -RUN mkdir /unicopy \ - && cp /app/scripts/container-entrypoint.sh /unicopy \ - && cp /app/scripts/container-healthcheck.sh /unicopy \ - && cp /app/scripts/lib.sh /unicopy +RUN mkdir -p /mnt/rootfs +RUN dnf install --installroot /mnt/rootfs jq vim curl --releasever 9 --setopt install_weak_deps=false --nodocs -y && \ + dnf --installroot /mnt/rootfs clean all && \ + rpm --root /mnt/rootfs -e --nodeps setup + +COPY ./scripts /mnt/rootfs + +# Download Oracle DB Driver +RUN mkdir -p /mnt/rootfs/opt/keycloak/providers +ADD --chown=keycloak:keycloak --chmod=644 "${ORACLE_DRIVER_URL}" /mnt/rootfs/opt/keycloak/providers/ojdbc11.jar +ADD --chown=keycloak:keycloak --chmod=644 "${ORACLE_NLS_URL}" /mnt/rootfs/opt/keycloak/providers/orai18n.jar ################## Stage 1 FROM ${RUN_IMAGE} as runner -COPY --from=builder /unicopy / + +ENV KC_HOME=/opt/keycloak +ENV KC_HEALTH_ENABLED=true +ENV KC_METRICS_ENABLED=true +ENV KC_DB=oracle + USER root + +COPY --from=builder /mnt/rootfs / + +RUN ${KC_HOME}/bin/kc.sh build + RUN mkdir /container-entrypoint-initdb.d \ - && microdnf install jq vim + && chown -R keycloak:keycloak ${KC_HOME} + USER keycloak +WORKDIR ${KC_HOME} ENTRYPOINT ["/container-entrypoint.sh"] HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --start-interval=5s --retries=5 CMD /container-healthcheck.sh \ No newline at end of file diff --git a/README.md b/README.md index 0c28fec..a7e275d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ docker compose up ``` 3. Navigate to admin console ``` -http://localhost:8080 +http://localhost:8081/auth ``` *Note*: Login with username `admin` and password `admin` @@ -33,11 +33,11 @@ Mount a volume at `/container-entrypoint-initdb.d` containing bash scripts to ru Environment variables: | Name | Description | |------|-------------| -| KEYCLOAK_FRONTEND_HOSTNAME | Front end hostname | -| KEYCLOAK_FRONTEND_PORT | Front end port | -| KEYCLOAK_SERVER_URL | Backend URL | -| KEYCLOAK_ADMIN | Admin username | -| KEYCLOAK_ADMIN_PASSWORD | Admin password | +| KC_FRONTEND_URL | Front end scheme, hostname, port, and relative path | +| KC_BACKEND_URL | Back end scheme, hostname, port, and relative path | +| KC_HTTP_RELATIVE_PATH | Relative path, probably must match KC_FRONTEND_URL and KC_BACKEND_URL | +| KC_BOOTSTRAP_ADMIN_USERNAME | Admin username | +| KC_BOOTSTRAP_ADMIN_PASSWORD | Admin password | ## Release 1. Create a new release on the GitHub Releases page. The release should enumerate changes and link issues. diff --git a/compose.yaml b/compose.yaml index 27b8156..7393367 100644 --- a/compose.yaml +++ b/compose.yaml @@ -18,18 +18,18 @@ services: dirsrv: condition: service_healthy ports: - - "8080:8080" + - "8081:8080" - "9990:9990" environment: - KEYCLOAK_FRONTEND_HOSTNAME: 'localhost' - KEYCLOAK_FRONTEND_PORT: '8080' - KEYCLOAK_SERVER_URL: 'http://keycloak:8080' - KEYCLOAK_ADMIN: 'admin' - KEYCLOAK_ADMIN_PASSWORD: 'admin' - TZ: 'America/New_York' + KC_FRONTEND_URL: 'http://localhost:8081/auth' + KC_BACKEND_URL: 'http://keycloak:8080/auth' + KC_HTTP_RELATIVE_PATH: '/auth' + KC_BOOTSTRAP_ADMIN_USERNAME: 'admin' + KC_BOOTSTRAP_ADMIN_PASSWORD: 'admin' KC_DB: oracle KC_DB_URL: jdbc:oracle:thin:@//oracle:1521/xepdb1 KC_DB_USERNAME: keycloak_owner KC_DB_PASSWORD: password + TZ: 'America/New_York' volumes: - ./container/keycloak/initdb.d:/container-entrypoint-initdb.d diff --git a/container/keycloak/initdb.d/01_login.sh b/container/keycloak/initdb.d/01_login.sh index 00d3d28..f05d523 100755 --- a/container/keycloak/initdb.d/01_login.sh +++ b/container/keycloak/initdb.d/01_login.sh @@ -5,7 +5,7 @@ echo "---------" echo "| Login |" echo "---------" -# KEYCLOAK_ADMIN, KEYCLOAK_ADMIN_PASSWORD, KEYCLOAK_HOME, KEYCLOAK_SERVER_URL already set as used by entrypoint +# KC_BOOTSTRAP_ADMIN_USERNAME, KC_BOOTSTRAP_ADMIN_PASSWORD, KC_HOME, KC_BACKEND_URL already set as used by entrypoint login diff --git a/scripts/container-entrypoint.sh b/scripts/container-entrypoint.sh index bc2bf1a..0b75e4d 100755 --- a/scripts/container-entrypoint.sh +++ b/scripts/container-entrypoint.sh @@ -1,23 +1,23 @@ #!/bin/bash -export KEYCLOAK_HOME='/opt/keycloak' - echo "--------------------------" echo "| Step 1: Start Keycloak |" echo "--------------------------" -${KEYCLOAK_HOME}/bin/kc.sh start-dev --hostname $KEYCLOAK_FRONTEND_HOSTNAME --hostname-port=$KEYCLOAK_FRONTEND_PORT & +# start-dev implies --hostname-strict false --http-enabled true +# --hostname-backchannel-dynamic true ? +${KC_HOME}/bin/kc.sh start-dev --hostname ${KC_FRONTEND_URL} --hostname-admin ${KC_FRONTEND_URL} --hostname-debug true --http-relative-path ${KC_HTTP_RELATIVE_PATH} & echo "--------------------------------------" echo "| Step 2: Wait for Keycloak to start |" echo "--------------------------------------" -if [[ -z "${KEYCLOAK_SERVER_URL}" ]]; then - echo "Skipping Keycloak Setup: Must provide KEYCLOAK_SERVER_URL in environment" +if [[ -z "${KC_BACKEND_URL}" ]]; then + echo "Skipping Keycloak Setup: Must provide KC_BACKEND_URL in environment" return 0 fi -until curl ${KEYCLOAK_SERVER_URL} -sf -o /dev/null; +until curl ${KC_BACKEND_URL} -sf -o /dev/null; do echo $(date) " Still waiting for Keycloak to start..." sleep 5 @@ -85,10 +85,10 @@ function run_custom_scripts_recursive { done } -if [ ! -f /${KEYCLOAK_HOME}/setup-complete ]; then +if [ ! -f /${KC_HOME}/setup-complete ]; then echo -e "Running setup scripts" run_custom_scripts "/container-entrypoint-initdb.d" -touch /${KEYCLOAK_HOME}/setup-complete +touch /${KC_HOME}/setup-complete else echo -e "Setup already run; skipping" fi diff --git a/scripts/container-healthcheck.sh b/scripts/container-healthcheck.sh index 702e78b..5fd05ce 100755 --- a/scripts/container-healthcheck.sh +++ b/scripts/container-healthcheck.sh @@ -1,3 +1,3 @@ #!/bin/bash -test -f ${KEYCLOAK_HOME}/setup-complete && curl ${KEYCLOAK_SERVER_URL} -sf -o /dev/null \ No newline at end of file +test -f ${KC_HOME}/setup-complete && curl ${KC_BACKEND_URL} -sf -o /dev/null \ No newline at end of file diff --git a/scripts/lib.sh b/scripts/lib.sh index f38abd3..d75ec5a 100644 --- a/scripts/lib.sh +++ b/scripts/lib.sh @@ -1,25 +1,25 @@ #!/bin/bash login() { -VARIABLES=(KEYCLOAK_ADMIN - KEYCLOAK_ADMIN_PASSWORD - KEYCLOAK_HOME - KEYCLOAK_SERVER_URL) +VARIABLES=(KC_BOOTSTRAP_ADMIN_USERNAME + KC_BOOTSTRAP_ADMIN_PASSWORD + KC_HOME + KC_BACKEND_URL) for i in "${!VARIABLES[@]}"; do var=${VARIABLES[$i]} [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh config credentials \ - --server "${KEYCLOAK_SERVER_URL}" \ +${KC_HOME}/bin/kcadm.sh config credentials \ + --server "${KC_BACKEND_URL}" \ --realm master \ - --user "${KEYCLOAK_ADMIN}" \ - --password "${KEYCLOAK_ADMIN_PASSWORD}" + --user "${KC_BOOTSTRAP_ADMIN_USERNAME}" \ + --password "${KC_BOOTSTRAP_ADMIN_PASSWORD}" } create_realm() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM KEYCLOAK_REALM_DISPLAY_NAME KEYCLOAK_SESSION_IDLE_TIMEOUT @@ -30,7 +30,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create realms \ +${KC_HOME}/bin/kcadm.sh create realms \ -s id="${KEYCLOAK_REALM}" \ -s realm="${KEYCLOAK_REALM}" \ -s enabled=true \ @@ -42,7 +42,7 @@ ${KEYCLOAK_HOME}/bin/kcadm.sh create realms \ create_client() { VARIABLES=(KEYCLOAK_CLIENT_NAME - KEYCLOAK_HOME + KC_HOME KEYCLOAK_REALM KEYCLOAK_REDIRECT_URIS KEYCLOAK_SECRET @@ -53,7 +53,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create clients \ +${KC_HOME}/bin/kcadm.sh create clients \ -r "${KEYCLOAK_REALM}" \ -s clientId="${KEYCLOAK_CLIENT_NAME}" \ -s id="${KEYCLOAK_CLIENT_NAME}" \ @@ -63,14 +63,14 @@ ${KEYCLOAK_HOME}/bin/kcadm.sh create clients \ -s secret="${KEYCLOAK_SECRET}" if [ ${KEYCLOAK_SERVICE_ACCOUNT_ENABLED} = 'true' ] ; then -${KEYCLOAK_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-users -${KEYCLOAK_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-authorization -${KEYCLOAK_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-realm +${KC_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-users +${KC_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-authorization +${KC_HOME}/bin/kcadm.sh add-roles -r "${KEYCLOAK_REALM}" --uusername service-account-${KEYCLOAK_CLIENT_NAME} --cclientid realm-management --rolename view-realm fi } create_role() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM KEYCLOAK_ROLE_NAME) @@ -79,13 +79,13 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create roles \ +${KC_HOME}/bin/kcadm.sh create roles \ -r "${KEYCLOAK_REALM}" \ -s name="${KEYCLOAK_ROLE_NAME}" } create_user() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_EMAIL KEYCLOAK_FIRSTNAME KEYCLOAK_LASTNAME @@ -97,7 +97,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create users \ +${KC_HOME}/bin/kcadm.sh create users \ -r "${KEYCLOAK_REALM}" \ -s username="${KEYCLOAK_USERNAME}" \ -s firstName="${KEYCLOAK_FIRSTNAME}" \ @@ -105,14 +105,14 @@ ${KEYCLOAK_HOME}/bin/kcadm.sh create users \ -s email="${KEYCLOAK_EMAIL}" \ -s enabled=true -${KEYCLOAK_HOME}/bin/kcadm.sh set-password \ +${KC_HOME}/bin/kcadm.sh set-password \ -r "${KEYCLOAK_REALM}" \ --username "${KEYCLOAK_USERNAME}" \ --new-password "${KEYCLOAK_PASSWORD}" } assign_role() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM KEYCLOAK_ROLE_NAME KEYCLOAK_USERNAME) @@ -122,14 +122,14 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh add-roles \ +${KC_HOME}/bin/kcadm.sh add-roles \ -r "${KEYCLOAK_REALM}" \ --uusername "${KEYCLOAK_USERNAME}" \ --rolename "${KEYCLOAK_ROLE_NAME}" } create_ldap_storage_provider() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM) for i in "${!VARIABLES[@]}"; do @@ -137,7 +137,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create components \ +${KC_HOME}/bin/kcadm.sh create components \ -r "${KEYCLOAK_REALM}" \ -s parentId="${KEYCLOAK_REALM}" \ -s id=${KEYCLOAK_REALM}-ldap-provider \ @@ -179,7 +179,7 @@ ${KEYCLOAK_HOME}/bin/kcadm.sh create components \ } set_first_name_mapper_attribute() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM KEYCLOAK_FIRSTNAME_ATTR) @@ -188,15 +188,15 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -MAPPER_ID=`${KEYCLOAK_HOME}/bin/kcadm.sh get components -r ${KEYCLOAK_REALM} -q name='first name' --fields id | jq -r .[0].id` +MAPPER_ID=`${KC_HOME}/bin/kcadm.sh get components -r ${KEYCLOAK_REALM} -q name='first name' --fields id | jq -r .[0].id` -${KEYCLOAK_HOME}/bin/kcadm.sh update components/${MAPPER_ID} \ +${KC_HOME}/bin/kcadm.sh update components/${MAPPER_ID} \ -r "${KEYCLOAK_REALM}" \ -s 'config."ldap.attribute"'="${KEYCLOAK_FIRSTNAME_ATTR}" } create_role_mapper() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_REALM) for i in "${!VARIABLES[@]}"; do @@ -204,7 +204,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create components \ +${KC_HOME}/bin/kcadm.sh create components \ -r ${KEYCLOAK_REALM} \ -s parentId=${KEYCLOAK_REALM}-ldap-provider \ -s id=${KEYCLOAK_REALM}-ldap-role-mapper \ @@ -224,7 +224,7 @@ ${KEYCLOAK_HOME}/bin/kcadm.sh create components \ } run_user_storage_sync() { -VARIABLES=(KEYCLOAK_HOME +VARIABLES=(KC_HOME KEYCLOAK_PROVIDER KEYCLOAK_REALM) @@ -233,7 +233,7 @@ for i in "${!VARIABLES[@]}"; do [ -z "${!var}" ] && { echo "$var is not set. Exiting."; exit 1; } done -${KEYCLOAK_HOME}/bin/kcadm.sh create \ +${KC_HOME}/bin/kcadm.sh create \ -r ${KEYCLOAK_REALM} \ user-storage/${KEYCLOAK_PROVIDER}/sync?action=triggerFullSync } \ No newline at end of file