Documentation
¶
Overview ¶
admin-guard is the single forward-auth gate for Hanzo's admin surfaces. It authorizes on TWO tiers (one predicate each, both in authz.go's authorize):
- GLOBAL platform-sudo — an IAM user whose org (`owner`) is the reserved admin org (owner == AdminOrg) — reaches EVERY admin surface: the raw global/DO-infra consoles (platform.hanzo.ai, studio, commerce-admin, the raw KMS admin UI, the IAM management UI) AND every tenant surface.
- TENANT admin — an owner/admin of a brand org (lux, zoo, hanzo, pars, …) — reaches ONLY that brand's own admin surface (admin.<brand>.<domain>), and is denied on every other brand's surface and on the global surfaces.
The tenant org is derived from the request Host (admin.lux.cloud → lux) — the ingress-set X-Forwarded-Host, never user input — against the canonical HIP-0111 brand registry mirrored in authz.go. A host that is not a recognized tenant surface admits GLOBAL sudo ONLY: fail closed.
It is consumed by hanzoai/ingress (Traefik) as a ForwardAuth middleware: the ingress forwards each request's headers to GET /__guard/verify and enforces the verdict.
verdict 2xx → allow (caller is a global admin)
verdict 302 → redirect (caller is a non-admin → console.hanzo.ai;
or anonymous → IAM PKCE login)
One gate, one mechanism, every admin surface. Clients never reach a raw admin or a 403 dead-end: a non-admin is always sent to the unified client surface, console.hanzo.ai.
Identity resolution is decomplected into three orthogonal sources, tried in order, each producing the SAME principal {owner, isAdmin, orgs} that the ONE authorize() predicate consumes:
- the guard's own signed session cookie (set after a prior PKCE login) — the browser fast path, carrying owner+isAdmin, scoped to the request's registrable domain;
- a Bearer / Basic JWT validated through the edge (the API path) — carries owner, isAdmin, and the full org-membership set, so no IAM round-trip;
- an IAM session cookie, resolved by calling IAM get-account server-side (the path for a browser that has an IAM session but no guard cookie yet).
The login flow is standard OAuth2 Authorization-Code + PKCE against IAM (client_id default `hanzo-admin-guard`), mirroring oauth2-proxy.