hanzo-gateway
API gateway for all Hanzo services.
Hanzo Gateway
API gateway for all Hanzo services. KrakenD-based with Go auth middleware.
Per HIP-0004, the gateway is the unified AI provider interface: one OpenAI-compatible surface over 100+ providers, bring-your-own AI/keys. It injects identity (X-User-Id / X-Org-Id / X-User-Email from the IAM JWT) and fronts the unified cloud binary (HIP-0106) — per-product usage is metered in console.hanzo.ai and exhausted balances are gated with 402 responses.
URLs
- Production: api.hanzo.ai
- Health: api.hanzo.ai/__health (KrakenD built-in, via gateway.json)
- Models: api.hanzo.ai/v1/models (41 models, 14 Zen)
- IAM Client ID: hanzo-gateway
- Docker Image: ghcr.io/hanzoai/gateway:main
Tech Stack
- Framework: KrakenD (Go) with Lura router (luraproject/lura/v2)
- HTTP Engine: Gin
- Auth: Custom Go middleware (auth_middleware.go)
- Config: configs/hanzo/gateway.json (KrakenD endpoints)
Key Files
auth_middleware.go — JWT validation, billing check, X-IAM-* header injectionauth_middleware_security_test.go — 12+ security regression testsrouter_engine.go — Gin engine setup, health route dedup, host-based routingconfigs/hanzo/gateway.json — KrakenD endpoint definitions (146 endpoints)
Security (2026-03-25)
stripIdentityHeaders() — deletes ALL X-IAM-* headers before processing (prevents injection)- JWT issuer always validated (no empty-iss skip)
- JWT audience validation (configurable AUTH_AUDIENCE)
- Error messages sanitized ("Invalid token" — no JWT internals leaked)
- 7 regression tests for header injection vectors
Headers (2026-03-28)
- Gateway sets: X-User-Id, X-Org-Id, X-User-Email (unified, no IAM prefix)
- KrakenD propagates same headers via propagate_claims
- JWT claims: extracts
sub (user ID), owner (org), email, with fallback to preferred_username/name when sub is empty (Hanzo IAM compatibility) - Billing check: GET /api/v1/billing/balance on commerce (fail-open)
Health Endpoint (2026-03-27)
/__health is defined in gateway.json (KrakenD backend config)NewEngine() injects disable_health: true into luragin.Namespace extra_config- This prevents Lura from registering a duplicate
/__health route (which panics Gin) - Do NOT manually register
/__health in router_engine.go — KrakenD handles it
Telemetry (2026-03-25)
- OpenTelemetry exporter to otel-collector.hanzo.svc:4317
- Service name: gateway, sample rate: 0.1
Build & Deploy
- Go 1.26.4, Dockerfile uses golang:1.26.4-alpine
- K8s: deployment/gateway, 2 replicas
- CI: shared docker-build.yml workflow (multi-arch)
- Makefile:
make build, make test
Upstream
- Custom (not a fork), MIT license