Extract init logic to versioned sync script + bootstrap admin user
- Move the inline keycloak-init bash block out of docker-compose.yml into init/sync.sh, mounted into the init container at /opt/init. The script is fully idempotent and is the new entry point for any future role/group/user/realm configuration changes — re-run with `docker compose up -d keycloak-init --force-recreate`. - Add reusable helper functions (ensure_user, ensure_group, ensure_user_in_group, ensure_user_realm_role, ensure_user_client_role) on top of kcadm.sh, with safe parsing of user/group IDs. - Bootstrap admin identity jovann@siteconseil.fr (password Shoko1997@) in both realms: * master realm: granted the global `admin` role. * ecosplay realm: granted realm-management/realm-admin and added to groups super_admin_asso and superadmin. Both users have CONFIGURE_TOTP as a required action so OTP enrollment is forced at first login. - Mirror the ecosplay user in the realm import JSON for fresh installs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,48 +69,13 @@ services:
|
||||
SMTP_PASSWORD: BBdgb6KxRQ8mNcpWFJsZCJxbSGNdgLhKFiITMErfBlQP
|
||||
LOGIN_THEME: ecosplay
|
||||
ECOSPLAY_GROUPS: "gp_asso gp_contest gp_mail gp_mailling gp_member gp_ndd gp_sign gp_ticket super_admin_asso superadmin"
|
||||
entrypoint: ["/bin/bash", "-c"]
|
||||
command:
|
||||
- |
|
||||
set -e
|
||||
until /opt/keycloak/bin/kcadm.sh config credentials \
|
||||
--server "$$KC_SERVER" \
|
||||
--realm master \
|
||||
--user "$$KC_ADMIN" \
|
||||
--password "$$KC_ADMIN_PASSWORD" >/dev/null 2>&1; do
|
||||
echo "Waiting for Keycloak to be ready..."
|
||||
sleep 5
|
||||
done
|
||||
echo "Keycloak ready, configuring master realm (SMTP + theme)..."
|
||||
/opt/keycloak/bin/kcadm.sh update realms/master \
|
||||
-s "smtpServer.host=$$SMTP_HOST" \
|
||||
-s "smtpServer.port=$$SMTP_PORT" \
|
||||
-s "smtpServer.from=$$SMTP_FROM" \
|
||||
-s "smtpServer.fromDisplayName=$$SMTP_FROM_DISPLAY_NAME" \
|
||||
-s "smtpServer.auth=true" \
|
||||
-s "smtpServer.starttls=true" \
|
||||
-s "smtpServer.ssl=false" \
|
||||
-s "smtpServer.user=$$SMTP_USER" \
|
||||
-s "smtpServer.password=$$SMTP_PASSWORD" \
|
||||
-s "loginTheme=$$LOGIN_THEME" \
|
||||
-s "internationalizationEnabled=true" \
|
||||
-s 'supportedLocales=["fr"]' \
|
||||
-s "defaultLocale=fr"
|
||||
echo "Master realm configured."
|
||||
|
||||
echo "Ensuring groups exist on ecosplay realm..."
|
||||
if /opt/keycloak/bin/kcadm.sh get realms/ecosplay >/dev/null 2>&1; then
|
||||
for grp in $$ECOSPLAY_GROUPS; do
|
||||
if /opt/keycloak/bin/kcadm.sh create groups -r ecosplay -s name="$$grp" >/dev/null 2>&1; then
|
||||
echo " + created group $$grp"
|
||||
else
|
||||
echo " = group $$grp already exists"
|
||||
fi
|
||||
done
|
||||
echo "Groups synced on ecosplay realm."
|
||||
else
|
||||
echo "ecosplay realm not found, skipping group sync (will be created from JSON import on next boot)."
|
||||
fi
|
||||
ADMIN_USER_USERNAME: jovann@siteconseil.fr
|
||||
ADMIN_USER_PASSWORD: Shoko1997@
|
||||
ADMIN_USER_FIRSTNAME: Jovann
|
||||
ADMIN_USER_LASTNAME: SiteConseil
|
||||
volumes:
|
||||
- ./init/sync.sh:/opt/init/sync.sh:ro
|
||||
entrypoint: ["/bin/bash", "/opt/init/sync.sh"]
|
||||
networks:
|
||||
- keycloak-net
|
||||
restart: "no"
|
||||
|
||||
160
init/sync.sh
Executable file
160
init/sync.sh
Executable file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================
|
||||
# E-Cosplay Keycloak — idempotent sync script
|
||||
# =============================================================
|
||||
# Run by the keycloak-init container on every `docker compose up`.
|
||||
# Fully idempotent: re-running only applies missing config.
|
||||
#
|
||||
# Re-sync after editing this file:
|
||||
# docker compose up -d keycloak-init --force-recreate
|
||||
#
|
||||
# Required env vars (set in docker-compose.yml):
|
||||
# KC_SERVER, KC_ADMIN, KC_ADMIN_PASSWORD
|
||||
# SMTP_HOST, SMTP_PORT, SMTP_FROM, SMTP_FROM_DISPLAY_NAME,
|
||||
# SMTP_USER, SMTP_PASSWORD
|
||||
# LOGIN_THEME
|
||||
# ECOSPLAY_GROUPS (space-separated list)
|
||||
# ADMIN_USER_USERNAME, ADMIN_USER_PASSWORD,
|
||||
# ADMIN_USER_FIRSTNAME, ADMIN_USER_LASTNAME
|
||||
# =============================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
KC=/opt/keycloak/bin/kcadm.sh
|
||||
|
||||
log() { printf '\n\033[1;36m== %s ==\033[0m\n' "$*"; }
|
||||
info() { printf ' %s\n' "$*"; }
|
||||
warn() { printf ' \033[1;33m! %s\033[0m\n' "$*"; }
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Wait for Keycloak and authenticate
|
||||
# -------------------------------------------------------------
|
||||
log "Waiting for Keycloak at ${KC_SERVER}"
|
||||
until $KC config credentials \
|
||||
--server "$KC_SERVER" \
|
||||
--realm master \
|
||||
--user "$KC_ADMIN" \
|
||||
--password "$KC_ADMIN_PASSWORD" >/dev/null 2>&1; do
|
||||
info "not ready yet, retrying in 5s..."
|
||||
sleep 5
|
||||
done
|
||||
info "Keycloak ready."
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Helpers
|
||||
# -------------------------------------------------------------
|
||||
realm_exists() {
|
||||
$KC get "realms/$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
user_id() {
|
||||
# $1 = realm, $2 = username
|
||||
$KC get users -r "$1" -q username="$2" --fields id 2>/dev/null \
|
||||
| sed -n 's/.*"id"[ ]*:[ ]*"\([^"]*\)".*/\1/p' \
|
||||
| head -n1
|
||||
}
|
||||
|
||||
group_id() {
|
||||
# $1 = realm, $2 = group name (top level only)
|
||||
$KC get "group-by-path/$2" -r "$1" --fields id 2>/dev/null \
|
||||
| sed -n 's/.*"id"[ ]*:[ ]*"\([^"]*\)".*/\1/p' \
|
||||
| head -n1
|
||||
}
|
||||
|
||||
ensure_group() {
|
||||
# $1 = realm, $2 = group name
|
||||
if [ -n "$(group_id "$1" "$2")" ]; then
|
||||
info "= group $2 ($1)"
|
||||
else
|
||||
$KC create groups -r "$1" -s name="$2" >/dev/null
|
||||
info "+ group $2 ($1)"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_user() {
|
||||
# $1=realm $2=username $3=password $4=firstname $5=lastname
|
||||
if [ -n "$(user_id "$1" "$2")" ]; then
|
||||
info "= user $2 ($1)"
|
||||
return
|
||||
fi
|
||||
$KC create users -r "$1" \
|
||||
-s username="$2" \
|
||||
-s email="$2" \
|
||||
-s firstName="$4" \
|
||||
-s lastName="$5" \
|
||||
-s enabled=true \
|
||||
-s emailVerified=true \
|
||||
-s 'requiredActions=["CONFIGURE_TOTP"]' >/dev/null
|
||||
$KC set-password -r "$1" --username "$2" --new-password "$3"
|
||||
info "+ user $2 ($1)"
|
||||
}
|
||||
|
||||
ensure_user_in_group() {
|
||||
# $1=realm $2=username $3=group
|
||||
local uid gid
|
||||
uid=$(user_id "$1" "$2")
|
||||
gid=$(group_id "$1" "$3")
|
||||
if [ -z "$uid" ]; then warn "skip group bind: user $2 missing in $1"; return; fi
|
||||
if [ -z "$gid" ]; then warn "skip group bind: group $3 missing in $1"; return; fi
|
||||
$KC update "users/$uid/groups/$gid" -r "$1" -n >/dev/null 2>&1 || true
|
||||
info " $2 -> group $3 ($1)"
|
||||
}
|
||||
|
||||
ensure_user_realm_role() {
|
||||
# $1=realm $2=username $3=role
|
||||
$KC add-roles -r "$1" --uusername "$2" --rolename "$3" >/dev/null 2>&1 || true
|
||||
info " $2 -> realm role $3 ($1)"
|
||||
}
|
||||
|
||||
ensure_user_client_role() {
|
||||
# $1=realm $2=username $3=client $4=role
|
||||
$KC add-roles -r "$1" --uusername "$2" --cclientid "$3" --rolename "$4" >/dev/null 2>&1 || true
|
||||
info " $2 -> client role $3/$4 ($1)"
|
||||
}
|
||||
|
||||
# =============================================================
|
||||
# Master realm: SMTP, theme, locale
|
||||
# =============================================================
|
||||
log "Configuring master realm (SMTP, theme, locale)"
|
||||
$KC update realms/master \
|
||||
-s "smtpServer.host=${SMTP_HOST}" \
|
||||
-s "smtpServer.port=${SMTP_PORT}" \
|
||||
-s "smtpServer.from=${SMTP_FROM}" \
|
||||
-s "smtpServer.fromDisplayName=${SMTP_FROM_DISPLAY_NAME}" \
|
||||
-s "smtpServer.auth=true" \
|
||||
-s "smtpServer.starttls=true" \
|
||||
-s "smtpServer.ssl=false" \
|
||||
-s "smtpServer.user=${SMTP_USER}" \
|
||||
-s "smtpServer.password=${SMTP_PASSWORD}" \
|
||||
-s "loginTheme=${LOGIN_THEME}" \
|
||||
-s "internationalizationEnabled=true" \
|
||||
-s 'supportedLocales=["fr"]' \
|
||||
-s "defaultLocale=fr"
|
||||
info "master realm updated"
|
||||
|
||||
# =============================================================
|
||||
# Master realm: global Keycloak admin user
|
||||
# =============================================================
|
||||
log "Ensuring global Keycloak admin user in master realm"
|
||||
ensure_user master "$ADMIN_USER_USERNAME" "$ADMIN_USER_PASSWORD" "$ADMIN_USER_FIRSTNAME" "$ADMIN_USER_LASTNAME"
|
||||
ensure_user_realm_role master "$ADMIN_USER_USERNAME" admin
|
||||
|
||||
# =============================================================
|
||||
# Ecosplay realm: groups + application admin user
|
||||
# =============================================================
|
||||
if realm_exists ecosplay; then
|
||||
log "Ensuring groups on ecosplay realm"
|
||||
for grp in $ECOSPLAY_GROUPS; do
|
||||
ensure_group ecosplay "$grp"
|
||||
done
|
||||
|
||||
log "Ensuring application admin user in ecosplay realm"
|
||||
ensure_user ecosplay "$ADMIN_USER_USERNAME" "$ADMIN_USER_PASSWORD" "$ADMIN_USER_FIRSTNAME" "$ADMIN_USER_LASTNAME"
|
||||
ensure_user_client_role ecosplay "$ADMIN_USER_USERNAME" realm-management realm-admin
|
||||
ensure_user_in_group ecosplay "$ADMIN_USER_USERNAME" super_admin_asso
|
||||
ensure_user_in_group ecosplay "$ADMIN_USER_USERNAME" superadmin
|
||||
else
|
||||
warn "ecosplay realm not found — will be imported on next boot"
|
||||
fi
|
||||
|
||||
log "Sync complete"
|
||||
@@ -67,6 +67,29 @@
|
||||
{ "name": "superadmin" }
|
||||
],
|
||||
|
||||
"users": [
|
||||
{
|
||||
"username": "jovann@siteconseil.fr",
|
||||
"email": "jovann@siteconseil.fr",
|
||||
"firstName": "Jovann",
|
||||
"lastName": "SiteConseil",
|
||||
"enabled": true,
|
||||
"emailVerified": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "Shoko1997@",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"requiredActions": ["CONFIGURE_TOTP"],
|
||||
"groups": ["/super_admin_asso", "/superadmin"],
|
||||
"clientRoles": {
|
||||
"realm-management": ["realm-admin"]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "ecosplay-web",
|
||||
|
||||
Reference in New Issue
Block a user