Files
HiveGrid-Wireframes/hivegrid-cloud/infra/authentik/bootstrap/bootstrap.sh
T

106 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# infra/authentik/bootstrap/bootstrap.sh
#
# Idempotent post-deploy bootstrap. Waits for the Authentik server to become
# ready, then ensures the project blueprints (./blueprints/*.yaml) are loaded
# and applied. The blueprint files themselves are also mounted into the
# server/worker containers via docker-compose.yml — the worker auto-applies
# them at startup. This script is a belt-and-braces re-trigger that:
# 1. polls /-/health/ready/ until it returns 200,
# 2. triggers /api/v3/managed/blueprints/<id>/apply/ for every blueprint
# so they re-apply immediately rather than waiting for the next worker
# tick,
# 3. prints the operator-actionable next steps (rotate bootstrap token,
# enable MFA on the admin account, etc.).
#
# Run this from the operator's machine OR inside a Coolify post-deploy hook:
#
# export AUTHENTIK_BASE_URL=https://auth.boiler.saas-ctrl.com
# export AUTHENTIK_BOOTSTRAP_TOKEN=$(cat ~/.cli-tokens/authentik-bootstrap)
# bash infra/authentik/bootstrap/bootstrap.sh
set -Eeuo pipefail
: "${AUTHENTIK_BASE_URL:?AUTHENTIK_BASE_URL must be set (e.g. https://auth.boiler.saas-ctrl.com)}"
: "${AUTHENTIK_BOOTSTRAP_TOKEN:?AUTHENTIK_BOOTSTRAP_TOKEN must be set (see .env.example)}"
WAIT_MAX_SECONDS="${WAIT_MAX_SECONDS:-300}"
WAIT_INTERVAL_SECONDS="${WAIT_INTERVAL_SECONDS:-5}"
log() { printf "\033[1;34m[authentik-bootstrap]\033[0m %s\n" "$*"; }
err() { printf "\033[1;31m[authentik-bootstrap:ERROR]\033[0m %s\n" "$*" >&2; }
die() { err "$*"; exit 1; }
# ----------------------------------------------------------------------------
# Step 1: wait for /-/health/ready/
# ----------------------------------------------------------------------------
log "waiting for ${AUTHENTIK_BASE_URL}/-/health/ready/ (timeout ${WAIT_MAX_SECONDS}s)"
deadline=$(( $(date +%s) + WAIT_MAX_SECONDS ))
while true; do
if curl -fsS -o /dev/null -w "%{http_code}" "${AUTHENTIK_BASE_URL}/-/health/ready/" | grep -q "^200$"; then
log "server ready"
break
fi
if [[ $(date +%s) -ge ${deadline} ]]; then
die "timed out waiting for /-/health/ready/"
fi
sleep "${WAIT_INTERVAL_SECONDS}"
done
# ----------------------------------------------------------------------------
# Step 2: list blueprints and trigger re-apply
# ----------------------------------------------------------------------------
auth_header="Authorization: Bearer ${AUTHENTIK_BOOTSTRAP_TOKEN}"
log "listing managed blueprints"
blueprints_json="$(curl -fsS -H "${auth_header}" "${AUTHENTIK_BASE_URL}/api/v3/managed/blueprints/?page_size=200")" || die "blueprint listing failed (check AUTHENTIK_BOOTSTRAP_TOKEN)"
# Extract pk for any blueprint whose `path` starts with /blueprints/toolctrl/.
ids="$(printf "%s" "${blueprints_json}" \
| python3 -c 'import sys, json; data=json.load(sys.stdin); [print(b["pk"]) for b in data.get("results", []) if b.get("path","").startswith("/blueprints/toolctrl/")]')"
if [[ -z "${ids}" ]]; then
log "no /blueprints/toolctrl/* blueprints found yet — the worker has not picked them up"
log "this is expected on the very first boot; the worker auto-discovers them within ~30s"
log "re-run this script in 1 minute to apply explicitly"
exit 0
fi
# ----------------------------------------------------------------------------
# Step 3: apply each blueprint
# ----------------------------------------------------------------------------
for id in ${ids}; do
log "applying blueprint ${id}"
curl -fsS -X POST -H "${auth_header}" "${AUTHENTIK_BASE_URL}/api/v3/managed/blueprints/${id}/apply/" \
-o /dev/null \
|| err "apply failed for blueprint ${id} (will be retried by the worker)"
done
log "bootstrap complete"
cat <<'EONOTE'
----------------------------------------------------------------------
NEXT STEPS (operator)
----------------------------------------------------------------------
1. Log into https://auth.boiler.saas-ctrl.com using AUTHENTIK_BOOTSTRAP_EMAIL
+ AUTHENTIK_BOOTSTRAP_PASSWORD. The first login forces a password change.
2. In the Authentik UI, enroll TOTP for your account
(User Settings -> Authenticators -> Set up TOTP). Required because
the toolctrl-require-mfa-totp-for-admin policy denies access to the
admin OIDC application without a verified TOTP device.
3. Rotate AUTHENTIK_BOOTSTRAP_TOKEN — it grants full admin-API access
and is no longer needed after this bootstrap. Generate a fresh
personal admin token instead, and store it in Coolify-Vault.
4. Add real human admins by creating users in the Authentik UI and
adding them to the `toolctrl-admin` group. Force TOTP enrollment
on each.
5. Verify OIDC discovery from the admin-panel side once #82 is wired:
curl -fsS https://auth.boiler.saas-ctrl.com/application/o/toolctrl-admin-panel/.well-known/openid-configuration | jq .issuer
----------------------------------------------------------------------
EONOTE