veylant/deploy/onboarding/onboard-tenant.sh
2026-02-23 13:35:04 +01:00

136 lines
5.4 KiB
Bash

#!/usr/bin/env bash
# deploy/onboarding/onboard-tenant.sh
#
# Provisions a new pilot tenant in Veylant IA:
# 1. Creates the tenant admin user
# 2. Seeds default routing policies (hr, finance, engineering)
# 3. Configures default rate limits
# 4. Verifies the setup
#
# Usage:
# export VEYLANT_URL=http://localhost:8090
# export VEYLANT_ADMIN_TOKEN=<super-admin-jwt>
# export TENANT_NAME="Acme Corp"
# export TENANT_ADMIN_EMAIL=admin@acme.example
# ./onboard-tenant.sh
#
# Required env vars:
# VEYLANT_URL - base URL of the proxy (no trailing slash)
# VEYLANT_ADMIN_TOKEN - JWT with admin role for the platform tenant
# TENANT_ADMIN_EMAIL - email of the new tenant's first admin
#
# Optional env vars:
# TENANT_ADMIN_FIRST - first name (default: Admin)
# TENANT_ADMIN_LAST - last name (default: User)
# RPM - requests per minute (default: 1000)
# BURST - burst size (default: 200)
set -euo pipefail
# ── Config ────────────────────────────────────────────────────────────────────
VEYLANT_URL="${VEYLANT_URL:?VEYLANT_URL is required}"
VEYLANT_ADMIN_TOKEN="${VEYLANT_ADMIN_TOKEN:?VEYLANT_ADMIN_TOKEN is required}"
TENANT_ADMIN_EMAIL="${TENANT_ADMIN_EMAIL:?TENANT_ADMIN_EMAIL is required}"
TENANT_ADMIN_FIRST="${TENANT_ADMIN_FIRST:-Admin}"
TENANT_ADMIN_LAST="${TENANT_ADMIN_LAST:-User}"
RPM="${RPM:-1000}"
BURST="${BURST:-200}"
API="${VEYLANT_URL}/v1/admin"
AUTH="Authorization: Bearer ${VEYLANT_ADMIN_TOKEN}"
# ── Helpers ───────────────────────────────────────────────────────────────────
log() { echo "[onboard] $*"; }
die() { echo "[onboard] ERROR: $*" >&2; exit 1; }
api_post() {
local path="$1"
local body="$2"
curl -sf -X POST "${API}${path}" \
-H "${AUTH}" \
-H "Content-Type: application/json" \
-d "${body}"
}
api_put() {
local path="$1"
local body="$2"
curl -sf -X PUT "${API}${path}" \
-H "${AUTH}" \
-H "Content-Type: application/json" \
-d "${body}"
}
api_get() {
local path="$1"
curl -sf -X GET "${API}${path}" \
-H "${AUTH}"
}
# ── Step 1: Health check ──────────────────────────────────────────────────────
log "Checking proxy health…"
status=$(curl -sf "${VEYLANT_URL}/healthz" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status',''))")
[[ "$status" == "ok" ]] || die "Proxy health check failed (got: $status)"
log "Proxy is healthy."
# ── Step 2: Create tenant admin user ─────────────────────────────────────────
log "Creating tenant admin user: ${TENANT_ADMIN_EMAIL}"
user_resp=$(api_post "/users" "{
\"email\": \"${TENANT_ADMIN_EMAIL}\",
\"first_name\": \"${TENANT_ADMIN_FIRST}\",
\"last_name\": \"${TENANT_ADMIN_LAST}\",
\"role\": \"admin\"
}")
user_id=$(echo "$user_resp" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))")
[[ -n "$user_id" ]] || die "Failed to create admin user"
log "Admin user created: id=${user_id}"
# ── Step 3: Seed default routing policies ─────────────────────────────────────
for tmpl in hr finance engineering catchall; do
log "Seeding routing template: ${tmpl}"
api_post "/policies/seed/${tmpl}" "{}" > /dev/null
log "${tmpl} policy seeded."
done
# ── Step 4: Configure rate limits ─────────────────────────────────────────────
# Extract tenant_id from the JWT (middle base64 segment).
TENANT_ID=$(echo "$VEYLANT_ADMIN_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('tenant_id',''))" 2>/dev/null || echo "")
if [[ -n "$TENANT_ID" ]]; then
log "Configuring rate limits for tenant ${TENANT_ID}: ${RPM} RPM, burst ${BURST}"
api_put "/rate-limits/${TENANT_ID}" "{
\"requests_per_min\": ${RPM},
\"burst_size\": ${BURST},
\"user_rpm\": $((RPM / 5)),
\"user_burst\": $((BURST / 5)),
\"is_enabled\": true
}" > /dev/null
log "Rate limits configured."
else
log "Warning: could not decode tenant_id from JWT — skipping rate-limit setup."
fi
# ── Step 5: Verify ────────────────────────────────────────────────────────────
log "Verifying setup…"
policies=$(api_get "/policies" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('data', [])))")
log "${policies} routing policies active."
users=$(api_get "/users" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('data', [])))")
log "${users} user(s) in the tenant."
log ""
log "✓ Tenant onboarding complete."
log " Admin: ${TENANT_ADMIN_EMAIL}"
log " Policies seeded: hr, finance, engineering, catchall"
log " Rate limit: ${RPM} RPM / ${BURST} burst"
log ""
log "Next step: issue a Keycloak JWT for ${TENANT_ADMIN_EMAIL} and share it with the admin."