Switch admin to jovann@e-cosplay.fr + disable default admin
- Rename the bootstrap human admin from jovann@siteconseil.fr to jovann@e-cosplay.fr in docker-compose env vars and in the realm import JSON. Keycloak identifies users by username so a new user is created on the next sync run; the old jovann@siteconseil.fr is left in place and can be deleted manually from the admin UI. - Introduce a service account client `sync-bot` in the master realm (confidential, service accounts enabled, direct grants off) granted the `admin` realm role. sync.sh now authenticates via client_credentials, falling back to the bootstrap admin only on the very first run — so reconciliation keeps working after the default admin is disabled. - Add disable_default_admin() at the end of the sync script. It first verifies that sync-bot can authenticate, then flips the `admin` user's `enabled` flag to false. Idempotent and safe: refuses to run if sync-bot auth is broken, and is a no-op if admin is already disabled. - SYNC_BOT_CLIENT / SYNC_BOT_SECRET env vars added to the init container for both bootstrap authentication and service client secret reconciliation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,10 +69,12 @@ services:
|
|||||||
SMTP_PASSWORD: BBdgb6KxRQ8mNcpWFJsZCJxbSGNdgLhKFiITMErfBlQP
|
SMTP_PASSWORD: BBdgb6KxRQ8mNcpWFJsZCJxbSGNdgLhKFiITMErfBlQP
|
||||||
LOGIN_THEME: ecosplay
|
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"
|
ECOSPLAY_GROUPS: "gp_asso gp_contest gp_mail gp_mailling gp_member gp_ndd gp_sign gp_ticket super_admin_asso superadmin"
|
||||||
ADMIN_USER_USERNAME: jovann@siteconseil.fr
|
ADMIN_USER_USERNAME: jovann@e-cosplay.fr
|
||||||
ADMIN_USER_PASSWORD: Shoko1997@
|
ADMIN_USER_PASSWORD: Shoko1997@
|
||||||
ADMIN_USER_FIRSTNAME: Jovann
|
ADMIN_USER_FIRSTNAME: Jovann
|
||||||
ADMIN_USER_LASTNAME: Serreau
|
ADMIN_USER_LASTNAME: Serreau
|
||||||
|
SYNC_BOT_CLIENT: sync-bot
|
||||||
|
SYNC_BOT_SECRET: dev-sync-bot-9f3b2a7c1e8d4f6a0b5c2e1d7f8a4b3c
|
||||||
volumes:
|
volumes:
|
||||||
- ./init/sync.sh:/opt/init/sync.sh:ro
|
- ./init/sync.sh:/opt/init/sync.sh:ro
|
||||||
entrypoint: ["/bin/bash", "/opt/init/sync.sh"]
|
entrypoint: ["/bin/bash", "/opt/init/sync.sh"]
|
||||||
|
|||||||
117
init/sync.sh
117
init/sync.sh
@@ -16,6 +16,7 @@
|
|||||||
# ECOSPLAY_GROUPS (space-separated list)
|
# ECOSPLAY_GROUPS (space-separated list)
|
||||||
# ADMIN_USER_USERNAME, ADMIN_USER_PASSWORD,
|
# ADMIN_USER_USERNAME, ADMIN_USER_PASSWORD,
|
||||||
# ADMIN_USER_FIRSTNAME, ADMIN_USER_LASTNAME
|
# ADMIN_USER_FIRSTNAME, ADMIN_USER_LASTNAME
|
||||||
|
# SYNC_BOT_CLIENT, SYNC_BOT_SECRET
|
||||||
# =============================================================
|
# =============================================================
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -29,16 +30,44 @@ warn() { printf ' \033[1;33m! %s\033[0m\n' "$*"; }
|
|||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
# Wait for Keycloak and authenticate
|
# Wait for Keycloak and authenticate
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
log "Waiting for Keycloak at ${KC_SERVER}"
|
# Two authentication paths:
|
||||||
until $KC config credentials \
|
# 1. sync-bot service account (preferred, used after bootstrap).
|
||||||
|
# 2. Default bootstrap admin (used on first run, before sync-bot
|
||||||
|
# has been created and granted the admin role).
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
KC_LOGIN_MODE=none
|
||||||
|
|
||||||
|
login_as_sync_bot() {
|
||||||
|
[ -n "${SYNC_BOT_SECRET:-}" ] || return 1
|
||||||
|
$KC config credentials \
|
||||||
|
--server "$KC_SERVER" \
|
||||||
|
--realm master \
|
||||||
|
--client "$SYNC_BOT_CLIENT" \
|
||||||
|
--secret "$SYNC_BOT_SECRET" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
login_as_admin() {
|
||||||
|
$KC config credentials \
|
||||||
--server "$KC_SERVER" \
|
--server "$KC_SERVER" \
|
||||||
--realm master \
|
--realm master \
|
||||||
--user "$KC_ADMIN" \
|
--user "$KC_ADMIN" \
|
||||||
--password "$KC_ADMIN_PASSWORD" >/dev/null 2>&1; do
|
--password "$KC_ADMIN_PASSWORD" >/dev/null 2>&1
|
||||||
info "not ready yet, retrying in 5s..."
|
}
|
||||||
|
|
||||||
|
log "Authenticating to Keycloak at ${KC_SERVER}"
|
||||||
|
while true; do
|
||||||
|
if login_as_sync_bot; then
|
||||||
|
KC_LOGIN_MODE=sync-bot
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if login_as_admin; then
|
||||||
|
KC_LOGIN_MODE=bootstrap
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
info "Keycloak not ready / no valid credentials yet, retrying in 5s..."
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
info "Keycloak ready."
|
info "Authenticated (mode=$KC_LOGIN_MODE)"
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
@@ -171,6 +200,72 @@ ensure_client() {
|
|||||||
info "+ client $2 ($1)"
|
info "+ client $2 ($1)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_sync_bot() {
|
||||||
|
# Create (or keep in sync) the automation service client in master.
|
||||||
|
# Grants its service account the master 'admin' realm role so that
|
||||||
|
# sync.sh can authenticate with client_credentials after the default
|
||||||
|
# admin user is disabled.
|
||||||
|
local cid
|
||||||
|
cid=$(client_internal_id master "$SYNC_BOT_CLIENT")
|
||||||
|
if [ -z "$cid" ]; then
|
||||||
|
$KC create clients -r master \
|
||||||
|
-s "clientId=$SYNC_BOT_CLIENT" \
|
||||||
|
-s "name=Sync Bot" \
|
||||||
|
-s "description=Service account used by init/sync.sh for unattended config reconciliation" \
|
||||||
|
-s 'protocol=openid-connect' \
|
||||||
|
-s 'enabled=true' \
|
||||||
|
-s 'publicClient=false' \
|
||||||
|
-s "secret=$SYNC_BOT_SECRET" \
|
||||||
|
-s 'standardFlowEnabled=false' \
|
||||||
|
-s 'implicitFlowEnabled=false' \
|
||||||
|
-s 'directAccessGrantsEnabled=false' \
|
||||||
|
-s 'serviceAccountsEnabled=true' >/dev/null
|
||||||
|
cid=$(client_internal_id master "$SYNC_BOT_CLIENT")
|
||||||
|
info "+ service client $SYNC_BOT_CLIENT (master)"
|
||||||
|
else
|
||||||
|
$KC update "clients/$cid" -r master \
|
||||||
|
-s 'enabled=true' \
|
||||||
|
-s 'serviceAccountsEnabled=true' \
|
||||||
|
-s 'standardFlowEnabled=false' \
|
||||||
|
-s 'directAccessGrantsEnabled=false' \
|
||||||
|
-s "secret=$SYNC_BOT_SECRET" >/dev/null
|
||||||
|
info "= service client $SYNC_BOT_CLIENT (master)"
|
||||||
|
fi
|
||||||
|
# Grant 'admin' realm role to the auto-generated service account user
|
||||||
|
$KC add-roles -r master \
|
||||||
|
--uusername "service-account-${SYNC_BOT_CLIENT}" \
|
||||||
|
--rolename admin >/dev/null 2>&1 || true
|
||||||
|
info " service-account-${SYNC_BOT_CLIENT} -> realm role admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_default_admin() {
|
||||||
|
# Only disable once we're sure sync-bot can authenticate (otherwise
|
||||||
|
# next run would be locked out).
|
||||||
|
if ! login_as_sync_bot; then
|
||||||
|
warn "sync-bot auth not working, refusing to disable default admin"
|
||||||
|
login_as_admin >/dev/null 2>&1 || true
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Re-login as admin to perform the disable action (sync-bot's token
|
||||||
|
# was used only for verification)
|
||||||
|
login_as_admin >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
local admin_id current
|
||||||
|
admin_id=$(user_id master "$KC_ADMIN")
|
||||||
|
if [ -z "$admin_id" ]; then
|
||||||
|
info "no '$KC_ADMIN' user in master, nothing to disable"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
current=$($KC get "users/$admin_id" -r master --fields enabled 2>/dev/null \
|
||||||
|
| sed -n 's/.*"enabled"[ ]*:[ ]*\(true\|false\).*/\1/p' | head -n1)
|
||||||
|
if [ "$current" = "false" ]; then
|
||||||
|
info "= default admin user '$KC_ADMIN' already disabled"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
$KC update "users/$admin_id" -r master -s enabled=false >/dev/null
|
||||||
|
info "+ default admin user '$KC_ADMIN' disabled"
|
||||||
|
}
|
||||||
|
|
||||||
# =============================================================
|
# =============================================================
|
||||||
# Master realm: SMTP, theme, locale
|
# Master realm: SMTP, theme, locale
|
||||||
# =============================================================
|
# =============================================================
|
||||||
@@ -191,6 +286,12 @@ $KC update realms/master \
|
|||||||
-s "defaultLocale=fr"
|
-s "defaultLocale=fr"
|
||||||
info "master realm updated"
|
info "master realm updated"
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# Master realm: automation service account (sync-bot)
|
||||||
|
# =============================================================
|
||||||
|
log "Ensuring sync-bot service client in master realm"
|
||||||
|
ensure_sync_bot
|
||||||
|
|
||||||
# =============================================================
|
# =============================================================
|
||||||
# Master realm: global Keycloak admin user
|
# Master realm: global Keycloak admin user
|
||||||
# =============================================================
|
# =============================================================
|
||||||
@@ -236,4 +337,10 @@ else
|
|||||||
warn "ecosplay realm not found — will be imported on next boot"
|
warn "ecosplay realm not found — will be imported on next boot"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# Disable default bootstrap admin (only after sync-bot is proven)
|
||||||
|
# =============================================================
|
||||||
|
log "Disabling default bootstrap admin user"
|
||||||
|
disable_default_admin
|
||||||
|
|
||||||
log "Sync complete"
|
log "Sync complete"
|
||||||
|
|||||||
@@ -69,8 +69,8 @@
|
|||||||
|
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"username": "jovann@siteconseil.fr",
|
"username": "jovann@e-cosplay.fr",
|
||||||
"email": "jovann@siteconseil.fr",
|
"email": "jovann@e-cosplay.fr",
|
||||||
"firstName": "Jovann",
|
"firstName": "Jovann",
|
||||||
"lastName": "Serreau",
|
"lastName": "Serreau",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user