api-gateway (Kong) — Domain Model
Status: populated Owner: TBD (Platform / SRE) Last updated: 2026-04-17 Companion: SERVICE_OVERVIEW · ADR-0001 · Service Template
1. Note on terminology
Kong is infrastructure, not a DDD bounded context. This document does not describe a business domain; it describes the Kong configuration model — the concepts Kong exposes and how Ghasi-SMS-Gateway maps to them. Where the service template says "aggregates / entities / value objects," read "Kong configuration objects under our naming and ownership rules."
Authoritative business domain models live in upstream services (sms-orchestrator, auth-service, billing-service, etc.).
2. Kong configuration concepts
| Kong concept | Definition | Ghasi mapping |
|---|---|---|
| Service | A named upstream (host + port + protocol + optional path) | One per platform microservice (svc-sms-orchestrator, svc-auth, ...) |
| Route | A match rule (hosts, paths, methods) pointing to a Service | One per API path prefix — see API_CONTRACTS |
| Plugin | Reusable middleware enabled at global / service / route / consumer scope | Auth, rate-limit, correlation-id, opentelemetry, http-log, prometheus |
| Consumer | An identity Kong recognises | One consumer per Ghasi account_id (when pre-provisioned) |
| Credential | Auth secret attached to a Consumer | key-auth (hashed API key), jwt credential (issuer + key) |
| Upstream | Load-balanced target group for a Service | Kubernetes Service DNS per microservice |
| Target | Backend instance in an Upstream | Resolved via Kube DNS; no manual targets in DB-less mode |
| Vault reference | Secret indirection, e.g. {vault://env/JWT_SECRET} | Used for signing keys, Redis password, OTel endpoint |
3. Ghasi naming conventions
| Object | Name pattern | Example |
|---|---|---|
| Service | svc-<service-name> | svc-sms-orchestrator, svc-auth-service |
| Route | rt-<service-short>-<version>-<purpose> | rt-sms-v1-send, rt-auth-v1-login |
| Consumer | csm-<account_id> | csm-acct_01HW9X... |
| Plugin instance | plg-<plugin-name>-<scope> | plg-rate-limit-global, plg-jwt-default |
| Tags | env:<env>, `tier:<customer | internal>, owner: |
All names are stable and referenced from the decK YAML under ops/kong/ in the application monorepo.
4. Plugin catalog (Ghasi usage)
| Plugin | Scope | Purpose | Detail |
|---|---|---|---|
jwt | Route (most) | Validate Bearer JWTs against auth-service JWKS | SECURITY_MODEL §3 |
key-auth | Route (SMS send, webhook test) | Validate X-Api-Key header | SECURITY_MODEL §4 |
rate-limiting-advanced | Global + route overrides | Per-key / per-account / per-operator limits, Redis-backed | APPLICATION_LOGIC §4 |
request-size-limiting | Route | Reject oversized payloads | API_CONTRACTS §6 |
ip-restriction | Route (admin, partner) | Allow/deny lists | SECURITY_MODEL §5 |
correlation-id | Global | Inject/propagate X-Request-Id | APPLICATION_LOGIC §3 |
opentelemetry | Global | Export spans to OTel collector | OBSERVABILITY §5 |
http-log | Global | Push access logs to Loki | OBSERVABILITY §3 |
prometheus | Global | Expose /metrics for scrape | OBSERVABILITY §2 |
request-transformer | Route (selected) | Strip dangerous headers, inject X-Gateway-Source: kong | SECURITY_MODEL §6 |
bot-detection | Global | Block obvious bot UAs | SECURITY_MODEL §7 |
Custom: ghasi-api-key-lookup (optional) | Route (SMS send, webhook) | Resolve API key → account_id + scopes via cached call to auth-service | APPLICATION_LOGIC §5 |
The custom plugin is the only Ghasi-authored element. Its code lives in the application monorepo at ops/kong/plugins/ghasi-api-key-lookup/; this folder documents only its contract and behaviour.
5. Consumer model
A Kong Consumer represents an authenticated principal at the edge. Ghasi maps one Consumer per platform account (not per end-user):
username = csm-<account_id>- Tags:
account_id:<id>,tier:<free|starter|pro|enterprise>,env:<staging|prod> - Credentials: one or more
key-authentries (rotate-in-place by issuing a second credential before revoking the first);jwtcredentials with JWKS pulled fromauth-service.
Consumers are provisioned by auth-service (the system of record for accounts and API keys). Sync mechanism:
- Preferred for static consumers (partners, internal): decK YAML generated by
auth-serviceat release time. - Runtime for customer API keys: the custom
ghasi-api-key-lookupplugin avoids per-consumer rows — resolves the key at request time against a cachedauth-serviceendpoint (TTL 60s).
6. Invariants
- Every Route must point at an upstream Service; no Route references an external host directly.
- Every public Route must enable at least one auth plugin (
jwtorkey-auth); CI lint rejects a Route without auth unless explicitly taggedpublic:true. - Every Route must have
env:<...>andowner:<team>tags. - Plugin execution phase order is fixed: auth → rate-limit → request-transformer → correlation-id → opentelemetry → upstream → http-log (Kong's built-in phases; we do not rely on ordering beyond that).
- Credentials are never stored in plaintext in YAML — use vault references.
- No body logging. SMS message content never appears in Kong logs.
7. What this folder does not own
- User / account / API-key domain model →
services/auth-service/DOMAIN_MODEL.md. - SMS message / idempotency model →
services/sms-orchestrator/DOMAIN_MODEL.md. - Billing, webhook, DLR models → their service folders.
8. Open questions
- Per-customer Kong Consumer rows, or rely entirely on the custom
ghasi-api-key-lookupplugin? Trade-off: per-consumer rate limit keys vs operational simplicity. - Single shared JWT realm (
ghasi-platform) vs per-tenant realms.