diff --git a/docker-compose.yml b/docker-compose.yml index d29158d..9971f49 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,12 @@ services: build: context: ./sso-manager-node dockerfile: Dockerfile.openldap + args: + # A submodule's .git is a pointer file, not a real repo — the image + # can't resolve its own commit hash from inside the build context. + # setup.sh sets this from the host, where the submodule resolves + # correctly (git -C sso-manager-node rev-parse --short HEAD). + GIT_COMMIT: ${SSO_GIT_COMMIT:-} container_name: sso-manager restart: unless-stopped networks: [theta-net] @@ -74,6 +80,12 @@ services: build: context: ./proxy dockerfile: Dockerfile + args: + # A submodule's .git is a pointer file, not a real repo — the image + # can't resolve its own commit hash from inside the build context. + # setup.sh sets this from the host, where the submodule resolves + # correctly (git -C proxy rev-parse --short HEAD). + GIT_COMMIT: ${PROXY_GIT_COMMIT:-} container_name: proxy restart: unless-stopped networks: [theta-net] diff --git a/setup.env.example b/setup.env.example index 0f094ec..ba6d5bc 100644 --- a/setup.env.example +++ b/setup.env.example @@ -45,7 +45,11 @@ CFG_DOMAIN=example.com #CFG_SMTP_FROM=SSO Manager # ── DO NOT put secrets here ────────────────────────────────────────────────── -# The LDAP admin password, JWT secret, admin password, and LDAP service-account -# password are GENERATED (random) into ./config/sso-secrets.js on first run. -# Change them later by editing ./config/sso-secrets.js directly. Do NOT set -# CFG_LDAP_ADMIN_PASS / CFG_JWT_SECRET / CFG_ADMIN_PASS / CFG_SVC_PASS here. \ No newline at end of file +# The LDAP admin password, JWT secret, admin password, LDAP service-account +# password, and the proxy's local admin password are all GENERATED (random) +# into ./config/sso-secrets.js + ./config/proxy-secrets.js on first run. +# Change them later by editing those files directly (the proxy's local admin +# password is the exception — see ./config/proxy-secrets.js's auth.localAdminPass +# comment for how to actually change it after the account exists). Do NOT set +# CFG_LDAP_ADMIN_PASS / CFG_JWT_SECRET / CFG_ADMIN_PASS / CFG_SVC_PASS / +# CFG_PROXY_ADMIN_PASS here. \ No newline at end of file diff --git a/setup.sh b/setup.sh index 88fc03e..b7bcafc 100755 --- a/setup.sh +++ b/setup.sh @@ -272,6 +272,10 @@ module.exports = { adminGroups: ['app_sso_admin'], adminUsers: ['proxyadmin2'], groupRoleMap: {}, + // Initial password for the local anti-lockout admin (proxyadmin2) — + // only read by the proxy the first time that account is created; + // changing it here later has no effect on an already-created account. + localAdminPass: $(js_str "$CFG_PROXY_ADMIN_PASS"), }, stack: { ssoHost: $(js_str "$CFG_SSO_HOST"), @@ -317,6 +321,7 @@ ensure_config() { CFG_JWT_SECRET="${CFG_JWT_SECRET:-}" CFG_ADMIN_PASS="${CFG_ADMIN_PASS:-}" CFG_SVC_PASS="${CFG_SVC_PASS:-}" + CFG_PROXY_ADMIN_PASS="${CFG_PROXY_ADMIN_PASS:-}" # ── One-time migration from .env / proxy.env (existing deployments) ── # Preserve the operator's existing secrets so the running deployment keeps @@ -379,6 +384,7 @@ ensure_config() { CFG_JWT_SECRET="${CFG_JWT_SECRET:-$(rand_hex 32)}" CFG_ADMIN_PASS="${CFG_ADMIN_PASS:-$(rand_hex 16)}" CFG_SVC_PASS="${CFG_SVC_PASS:-$(rand_hex 16)}" + CFG_PROXY_ADMIN_PASS="${CFG_PROXY_ADMIN_PASS:-$(rand_hex 16)}" mkdir -p "$CONFIG_DIR" && chmod 700 "$CONFIG_DIR" write_sso_secrets @@ -529,6 +535,12 @@ backup_before_rebuild() { backup_before_rebuild # ── 4. Start SSO Manager, wait for health ───────────────────────────────────── +# SSO_GIT_COMMIT: sso-manager-node is a git submodule here, so its .git is a +# pointer file (not a real repo) -- the image can't resolve its own commit +# hash from inside the Docker build context. Resolve it on the host (where +# the submodule DOES resolve correctly) and pass it in as a build arg; see +# docker-compose.yml and sso-manager-node's Dockerfile.openldap. +export SSO_GIT_COMMIT="$(git -C sso-manager-node rev-parse --short HEAD 2>/dev/null || echo unknown)" info "Building + starting sso-manager (first run builds the image; this takes a while)..." "${COMPOSE[@]}" up -d --build sso-manager @@ -549,6 +561,8 @@ done read_config_kv() { "${COMPOSE[@]}" exec -T sso-manager node -e ' const c = require("/config/sso-secrets.js"); + let p = {}; + try { p = require("/config/proxy-secrets.js"); } catch (_) {} const o = { SSO_HOST: (c.stack && c.stack.ssoHost) || "", PROXY_HOST: (c.stack && c.stack.proxyHost) || "", @@ -556,6 +570,7 @@ read_config_kv() { ORG_NAME: c.name || "", ADMIN_UID: (c.bootstrap && c.bootstrap.adminUid) || "", ADMIN_PASS: (c.bootstrap && c.bootstrap.adminPass) || "", + PROXY_LOCAL_ADMIN_PASS: (p.auth && p.auth.localAdminPass) || "", }; for (const k in o) console.log(k + "=" + (o[k] == null ? "" : o[k])); ' 2>/dev/null @@ -566,6 +581,7 @@ SSO_HOST="$(cfgval SSO_HOST)" PROXY_HOST="$(cfgval PROXY_HOST)" ADMIN_UID="$(cfgval ADMIN_UID)" ADMIN_PASS="$(cfgval ADMIN_PASS)" +PROXY_LOCAL_ADMIN_PASS="$(cfgval PROXY_LOCAL_ADMIN_PASS)" info "Stack config:" info " SSO host: https://${SSO_HOST}" @@ -592,6 +608,8 @@ else fi # ── 6. Start the proxy, wait for health ─────────────────────────────────────── +# PROXY_GIT_COMMIT: same reasoning as SSO_GIT_COMMIT above. +export PROXY_GIT_COMMIT="$(git -C proxy rev-parse --short HEAD 2>/dev/null || echo unknown)" info "Building + starting proxy (first run builds the image; this takes a while)..." "${COMPOSE[@]}" up -d --build proxy @@ -662,6 +680,12 @@ echo " First admin login:" echo " user: ${ADMIN_UID}" echo " pass: ${ADMIN_PASS}" echo +echo " Proxy local admin (anti-lockout fallback if the SSO is unreachable):" +echo " user: proxyadmin2" +echo " pass: ${PROXY_LOCAL_ADMIN_PASS}" +echo " (only shown when the account is first created; edit ./config/proxy-secrets.js" +echo " or use the proxy UI to change it afterward)" +echo echo " Secrets live in ./config/ (sso-secrets.js + proxy-secrets.js). Back them" echo " up off-host — ./setup.sh snapshots to ./backups/ before each rebuild." echo