#!/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= # 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."