livrare lot 2
This commit is contained in:
commit
8ecc78e729
763 changed files with 164593 additions and 0 deletions
31
backend/services/gateway-auth-layer/didiKong/Dockerfile
Normal file
31
backend/services/gateway-auth-layer/didiKong/Dockerfile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Kong 3.9 — the declarative config uses fields (ai_metrics, rate-limiting
|
||||
# redis block) introduced after 3.4; the running gateway is 3.9.1.
|
||||
FROM kong:3.9
|
||||
|
||||
# Switch to root to install curl and set permissions
|
||||
USER root
|
||||
|
||||
# Install curl for configuration import
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy custom entrypoint and configuration.
|
||||
# kong.yml is the JWT-enforcing declarative config (RS256 via Keycloak public
|
||||
# keys + jwt plugin on every protected route). Baked to the path Kong reads by
|
||||
# default so `docker run` of this image is SECURE BY DEFAULT — no reliance on a
|
||||
# runtime volume mount. (The previous image baked a config with `consumers: []`
|
||||
# and no jwt plugin; see kong.yml.insecure-legacy for that reference.)
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
COPY declarative/kong.yml /kong/declarative/kong.yml
|
||||
|
||||
# DBless + point Kong at the baked config. A volume mount at the same path can
|
||||
# still override this for environment-specific configs (cluster vs local).
|
||||
ENV KONG_DATABASE=off
|
||||
ENV KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yml
|
||||
|
||||
# Make entrypoint executable
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Switch back to kong user
|
||||
USER kong
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
208
backend/services/gateway-auth-layer/didiKong/INDEX.md
Normal file
208
backend/services/gateway-auth-layer/didiKong/INDEX.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# didiKong - Index
|
||||
|
||||
API Gateway pentru platforma DIDI. Toate requesturile externe trec prin Kong inainte sa ajunga la serviciile backend. Gestioneaza rutare, rate limiting, CORS, SSL si headere.
|
||||
|
||||
**Imagine**: didi-kong:latest (Kong 3.9.1)
|
||||
**Container**: didi-kong (activ, pe masina de deployment)
|
||||
|
||||
**Mod**: DB-less declarativ (`KONG_DATABASE=off`)
|
||||
**Porturi** (doar loopback `127.0.0.1`): 18000 (proxy HTTP -> container 8000), 18001 (admin API -> 8001), 18443 (proxy TLS -> 8443 ssl)
|
||||
|
||||
---
|
||||
|
||||
## Deployment: container local DB-less (activ)
|
||||
|
||||
Kong ruleaza ca un singur container `didi-kong` pe masina de deployment, in mod **DB-less** (`KONG_DATABASE=off`). Nu exista Kong Cluster, Control Plane, Data Planes sau HAProxy, si nu exista PostgreSQL pentru Kong.
|
||||
|
||||
- Config declarativa din `declarative/kong.yml.didi11-local`, montata in container la `/kong/declarative/kong.yml`.
|
||||
- Porturile sunt legate exclusiv pe loopback (`127.0.0.1`): proxy `18000`, admin API `18001`, proxy TLS `18443`. Kong nu e expus public direct; traficul extern intra prin edge/tunel catre proxy-ul local.
|
||||
- Single source of truth = fisierul declarativ `kong.yml.didi11-local`. Orice modificare de rute/plugin-uri se face in acest fisier + reload.
|
||||
|
||||
---
|
||||
|
||||
## Mod de operare: DB-less (declarativ)
|
||||
|
||||
Configuratia vine integral din fisierul `declarative/kong.yml.didi11-local`. Kong nu are baza de date proprie.
|
||||
```
|
||||
KONG_DATABASE=off
|
||||
KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yml
|
||||
```
|
||||
|
||||
Nu exista mod PostgreSQL / productie separata pentru Kong: acelasi fisier declarativ este sursa unica de adevar.
|
||||
|
||||
---
|
||||
|
||||
## Servicii inregistrate
|
||||
|
||||
Kong ruteaza catre 2 servicii backend (conform `kong.yml.didi11-local`):
|
||||
|
||||
| Serviciu | Target | Status |
|
||||
|----------|--------|--------|
|
||||
| didi-agent-v3 | http://didi-agent-v3:24803 | activ |
|
||||
| didi-framework | http://didi-framework:3005 | activ |
|
||||
|
||||
Nota: rutele agent-v3 au timeout mare (660s = 11 min) pentru procesarea video.
|
||||
|
||||
---
|
||||
|
||||
## Rute definite
|
||||
|
||||
### Agent service (activ)
|
||||
|
||||
| Path | Metode | Destinatie |
|
||||
|------|--------|------------|
|
||||
| /agent/health | GET | agent-api |
|
||||
| /agent/status | GET | agent-api |
|
||||
| /api/pipelines | GET | agent-api |
|
||||
| /api/analyze | POST | agent-api |
|
||||
| /api/sessions | GET | agent-api |
|
||||
| /api/upload | POST | agent-api |
|
||||
| /api/abort | POST | agent-api |
|
||||
| /api/v3/* | toate | agent-api (acopera si /api/v3/moderation/*) |
|
||||
|
||||
### didiFramework (config + HIL moderation)
|
||||
|
||||
| Path | Metode | Destinatie |
|
||||
|------|--------|------------|
|
||||
| /api/* | toate | didiFramework (acopera /api/moderation-config, /api/sensitive-topics, /api/moderation-roles) |
|
||||
|
||||
Nota: rutele de moderatie (HIL) calatoresc pe regulile generale `/api/v3/*` (agent-v3) si `/api/*` (didiFramework) — nu sunt necesare reguli Kong dedicate.
|
||||
|
||||
> Notă: serviciile Python legacy `orchestrator-api` și `analysis-api` (rute `/api/v1/catalog|pipelines|runs/*`,
|
||||
> `/analysis/*`) NU mai există în config-ul local — au fost eliminate odată cu migrarea pe agent-v3. Config-ul
|
||||
> `kong.yml.didi11-local` rutează exclusiv către `didi-agent-v3` și `didi-framework`.
|
||||
|
||||
### Admin dashboard
|
||||
|
||||
| Path | Metode | Destinatie |
|
||||
|------|--------|------------|
|
||||
| /admin | toate | admin-dashboard |
|
||||
| /admin/api | toate | admin-dashboard |
|
||||
|
||||
---
|
||||
|
||||
## Plugin-uri globale
|
||||
|
||||
5 plugin-uri active pe toate rutele:
|
||||
|
||||
### 1. CORS
|
||||
- Origins: localhost:3000, localhost:3001, localhost:8100, * (wildcard)
|
||||
- Metode: GET, POST, PUT, DELETE, OPTIONS, PATCH
|
||||
- Headere: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Authorization, X-Request-ID
|
||||
- Exposed headers: X-Auth-Token, X-Request-ID
|
||||
- Credentials: activat
|
||||
- Max age: 3600s
|
||||
- Preflight continue: nu
|
||||
|
||||
### 2. Rate Limiting
|
||||
- 100 requests/minut per consumer
|
||||
- 2000 requests/ora per consumer
|
||||
- 10000 requests/zi per consumer
|
||||
- Politica: local (fara state distribuit)
|
||||
- Fault tolerant: da
|
||||
|
||||
### 3. Correlation ID (Request ID Tracking)
|
||||
- Header: X-Request-ID
|
||||
- Generator: UUID
|
||||
- Echo downstream: da (returnat in raspuns)
|
||||
|
||||
### 4. Request Size Limiting
|
||||
- Max payload: 100MB (pentru upload media)
|
||||
- Require content-length: nu
|
||||
|
||||
### 5. Response Transformer
|
||||
- Adauga: X-Gateway: DIDI-Kong, X-API-Version: 2.0
|
||||
- Sterge: Server, Via (ascunde detalii interne)
|
||||
|
||||
---
|
||||
|
||||
## Upstreams (load balancing)
|
||||
|
||||
Config-ul local (`kong.yml.didi11-local`) NU definește upstream-uri — rutarea se face
|
||||
direct către serviciile `didi-agent-v3:24803` și `didi-framework:3005`. Scalarea orizontală
|
||||
a workerilor se face la nivel de agent-v3 (`scale-workers.sh`), nu prin upstream-uri Kong.
|
||||
|
||||
---
|
||||
|
||||
## SSL/TLS
|
||||
|
||||
- Certificat self-signed pentru <host-local>
|
||||
- Locatie: certs/server.crt, certs/server.key
|
||||
- Valabil: feb 2026 - feb 2027
|
||||
- Emitent: DIDI, Bucharest, RO
|
||||
- Servit pe proxy-ul TLS local `127.0.0.1:18443`
|
||||
|
||||
---
|
||||
|
||||
## Integrare Keycloak (LOCAL) + enforcement JWT (Modul 4 Gateway)
|
||||
|
||||
Kong valideaza token-urile emise de instanta Keycloak **locala** (`didi-keycloak`, port `28080`, servita sub `/auth`). Realm-urile locale sunt `didi-clients` (useri finali) si `didi-admins` (operatori). Issuer-ele locale au forma `http://localhost:28080/auth/realms/didi-clients` si `.../didi-admins`.
|
||||
|
||||
Enforcement-ul se face prin pluginul Kong `jwt` (nu OIDC/introspection): validare de semnatura **RS256** cu chei publice statice, `key_claim_name: iss` (Kong potriveste tokenul dupa claim-ul `iss` cu un `jwt_secret` inregistrat pe consumer).
|
||||
|
||||
Consumer: **`didi-keycloak-users`** — detine `jwt_secrets` (RS256, `rsa_public_key`) pentru toate issuer-ele acceptate, cheia fiind chiar valoarea `iss`:
|
||||
- local: `http://localhost:28080/realms/didi-clients`, `http://localhost:28080/realms/didi-admins`
|
||||
- plus issuer-ele externe/edge folosite in fata proxy-ului: `https://didi365.eu/auth/realms/{didi-clients,didi-admins}`, `https://<sso-extern>/realms/...`, `https://<sso-extern>/realms/...`, `https://<host-local>/auth/realms/...`, `https://10.11.10.11:{3001,8443}/auth/realms/...`
|
||||
|
||||
Pluginul `jwt` este activ pe **16 rute protejate** de pe cele doua servicii (`didi-agent-v3` si `didi-framework`), incluzand ruta **`/framework`** (route `didi-framework-direct`, jwt adaugat 2026-07-08). Rutele publice raman fara jwt (health/status, media public, verify-email, waitlist), iar rutele de extensie folosesc autentificare separata prin `X-API-Key` + rate-limiting.
|
||||
|
||||
JWT validation flow:
|
||||
1. Clientul (SPA/extensie) obtine token JWT de la Keycloak local (`/auth/realms/didi-clients` sau `/auth/realms/didi-admins`).
|
||||
2. Trimite request cu `Authorization: Bearer {token}`.
|
||||
3. Kong potriveste `iss` cu `jwt_secret`-ul consumer-ului `didi-keycloak-users` si valideaza semnatura RS256; token invalid/lipsa -> `401`.
|
||||
4. Daca valid, ruteaza requestul catre serviciul backend local (`didi-agent-v3:24803` / `didi-framework`).
|
||||
5. Serviciul backend decodeaza tokenul pentru `user_id`/`email`/`realm_access.roles` (fara re-validare — Kong a validat deja).
|
||||
|
||||
---
|
||||
|
||||
## Configurare performanta
|
||||
|
||||
```
|
||||
KONG_NGINX_WORKER_PROCESSES=auto
|
||||
KONG_MEM_CACHE_SIZE=256m
|
||||
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE=128k
|
||||
KONG_NGINX_PROXY_PROXY_BUFFERS=4 256k
|
||||
KONG_NGINX_PROXY_PROXY_BUSY_BUFFERS_SIZE=256k
|
||||
KONG_NGINX_HTTP_LARGE_CLIENT_HEADER_BUFFERS=4 64k
|
||||
```
|
||||
|
||||
Buffer-urile mari sunt necesare pentru headerele JWT de la Keycloak (token-urile pot fi foarte mari).
|
||||
|
||||
---
|
||||
|
||||
## Fisiere
|
||||
|
||||
```
|
||||
Dockerfile -- Imagine didi-kong (Kong 3.9), instaleaza curl, entrypoint
|
||||
entrypoint.sh -- Pornire Kong DB-less + wait for ready + log servicii
|
||||
declarative/
|
||||
kong.yml.didi11-local -- Configurare declarativa activa (single source of truth, montata la /kong/declarative/kong.yml)
|
||||
certs/
|
||||
server.crt -- Certificat SSL self-signed
|
||||
server.key -- Cheie privata SSL
|
||||
```
|
||||
|
||||
Zero cod custom. Zero plugin-uri Lua custom. Doar configurare declarativa si certificat SSL.
|
||||
|
||||
---
|
||||
|
||||
## Health check
|
||||
|
||||
```
|
||||
kong health (interval 30s, timeout 10s, retries 3, start period 60s)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Consumers
|
||||
|
||||
Configuratia declarativa defineste un singur consumer Kong: **`didi-keycloak-users`** (username + custom_id `didi-keycloak-users`), care detine `jwt_secrets`-urile RS256 pentru toate issuer-ele Keycloak locale/edge acceptate (vezi sectiunea Integrare Keycloak). Acest consumer este cel pe care pluginul `jwt` il rezolva la validarea tokenului.
|
||||
|
||||
Limitele per-tier (free/paid/enterprise) provin din atributele de grup Keycloak (realm-urile locale `didi-clients` / `didi-admins`) si sunt disponibile in claim-urile JWT pentru rate limiting; rutele de extensie au propriul rate-limiting per `X-API-Key` (30/min).
|
||||
|
||||
## Recent Changes
|
||||
|
||||
- **2026-07-08 — jwt pe `/framework`**: pluginul `jwt` (RS256, `key_claim_name: iss`) adaugat pe ruta `didi-framework-direct` (path `/framework`). Enforcement JWT acum activ pe 16 rute protejate pe `didi-agent-v3` + `didi-framework`.
|
||||
- **jwt_secrets pentru issuer-ele locale** pe consumer `didi-keycloak-users`: `http://localhost:28080/realms/didi-clients` + `.../didi-admins`, alaturi de issuer-ele edge (`didi365.eu/auth`, `<sso-extern>`, `<sso-extern>`, `<host-local>/auth`, `10.11.10.11:{3001,8443}/auth`) pentru realm-urile `didi-clients` si `didi-admins`.
|
||||
- **Rute de extensie** (`didi-agent-extension-analyze`, `-async`, `-status`, `-upload`): autentificare `X-API-Key` + `rate-limiting` 30/min + `request-transformer`; CORS extins cu origins `chrome-extension://[a-z]+`, `moz-extension://[a-z0-9-]+` + header `X-API-Key`.
|
||||
- **Single source of truth** = `declarative/kong.yml.didi11-local` (DB-less). Fara cluster, fara decK sync.
|
||||
121
backend/services/gateway-auth-layer/didiKong/MIGRATION.md
Normal file
121
backend/services/gateway-auth-layer/didiKong/MIGRATION.md
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
# Kong — migrat pe cluster shared (2026-04-28)
|
||||
|
||||
> **TL;DR**: containerul local `didi-kong` nu mai rulează. Tot traficul public DIDI trece prin clusterul Kong shared extern: `HAProxy 10.11.10.175` → `Kong DP1/DP2 (10.11.10.177/178)`. Configurația DIDI declarativă e în `declarative/kong-cluster.yml`.
|
||||
|
||||
---
|
||||
|
||||
## Ce era aici (înainte de 2026-04-28)
|
||||
|
||||
`didi-kong` — un container Kong 3.4.2 standalone (`image: didi-kong:latest`) definit în `backend/production/docker-compose.yml`. Mod Postgres (DB pe clusterul Patroni). Servea singur tot traficul `didi365.eu`. Avea 16 servicii + 35 rute + 5 plugin-uri globale + 1 consumer JWT.
|
||||
|
||||
## Ce e acum
|
||||
|
||||
Tot traficul DIDI a fost migrat pe **Kong cluster extern** (același folosit de `lege365`, `rafai`, `biddie`, `notify`, `firme`).
|
||||
|
||||
| Component cluster | IP:Port | Rol |
|
||||
|---|---|---|
|
||||
| HAProxy LB | `10.11.10.175:443` | edge → DP, terminare TLS pentru DIDI |
|
||||
| Kong CP (Control Plane) | `10.11.10.176:8001` | configurare via Admin API (DB-attached) |
|
||||
| Kong DP1 | `10.11.10.177:8000/8443` | proxy trafic |
|
||||
| Kong DP2 | `10.11.10.178:8000/8443` | proxy trafic |
|
||||
|
||||
Cluster Kong rulează versiunea 3.14.0.1 în mod Hybrid CP/DP, cu DB Postgres pe clusterul Patroni.
|
||||
|
||||
## Servicii DIDI consolidate pe cluster (4)
|
||||
|
||||
| Service cluster | Tag | Upstream | Routes |
|
||||
|---|---|---|---|
|
||||
| `didi-agent-v3` | `product:didi,env:prod,kind:api` | `10.11.10.12:24803` | 16 (15 API + 1 prefix /agent-v3) |
|
||||
| `didi-framework` | `product:didi,env:prod,kind:api` | `10.11.10.12:3005` | 6 |
|
||||
| `didi-keycloak` | `product:didi,env:prod,kind:auth` | `10.11.10.12:28000` | 2 |
|
||||
|
||||
> `didi-admin` NU e migrat — accesibil intern via VPN, păstrează Docker network DNS.
|
||||
|
||||
Toate rutele matchează pe `Host: didi365.eu, www.didi365.eu, <host-local>`.
|
||||
|
||||
## Servicii droppate complet
|
||||
|
||||
- `analysis-api`, `orchestrator-api` (legacy, 0 routes)
|
||||
- `agent-v3`, `keycloak` (alias-uri orfane)
|
||||
- `minio-storage` (deja în cluster MinIO 4-node, vezi `didiStorage/MIGRATION.md`)
|
||||
- `pgadmin`, `redis-commander`, `rabbitmq-management`, `minio-console` (tooling în dispariție)
|
||||
|
||||
## Configurația declarativă
|
||||
|
||||
```
|
||||
declarative/
|
||||
├── kong-cluster.yml ← config-ul curent al DIDI pe cluster (sursa de adevăr)
|
||||
├── kong-local-backup.yml ← snapshot complet al Kong-ului local înainte de migrare
|
||||
└── kong.yml ← config-ul declarativ legacy (DB-less staging)
|
||||
```
|
||||
|
||||
Apply / sync:
|
||||
```bash
|
||||
docker run --rm --network host -v $(pwd)/declarative:/cfg kong/deck:latest \
|
||||
gateway sync /cfg/kong-cluster.yml --kong-addr http://10.11.10.176:8001
|
||||
```
|
||||
|
||||
Validare fără modificări:
|
||||
```bash
|
||||
docker run --rm --network host -v $(pwd)/declarative:/cfg kong/deck:latest \
|
||||
gateway diff /cfg/kong-cluster.yml --kong-addr http://10.11.10.176:8001
|
||||
```
|
||||
|
||||
## Edge nginx (Contabo)
|
||||
|
||||
Edge nginx pe Contabo (`213.136.83.198`, `/srv/edge-nginx/conf.d/didi365.conf`) a fost actualizat să trimită `/auth/`, `/api/`, `/agent-v3/` la `https://10.11.10.175` (în loc de `https://<host-local>` care era kong local). Backup: `didi365.conf.bak.pre-kong-cluster-20260428`.
|
||||
|
||||
## Admin nginx
|
||||
|
||||
`backend/admin-dashboard/nginx-ssl.conf` — `location /api/` proxy_pass schimbat de la `https://kong:8443` (Docker DNS local) la `https://10.11.10.175` cu `Host: didi365.eu` overridden. Restul (`/auth/`, `/agent-v3/`, `/framework/`) bypass-ează Kong, merg direct la backend.
|
||||
|
||||
## Cum verifici că merge prin cluster
|
||||
|
||||
Răspunsurile prin cluster Kong au header-ul `X-Gateway: DIDI-Kong-Cluster`. Răspunsurile (vechile) prin Kong local aveau `X-Gateway: DIDI-Kong-Staging`.
|
||||
|
||||
```bash
|
||||
curl -sI https://didi365.eu/auth/realms/didi-clients | grep -i x-gateway
|
||||
# expect: x-gateway: DIDI-Kong-Cluster
|
||||
```
|
||||
|
||||
## Rollback (dacă apar probleme)
|
||||
|
||||
Kong local nu mai există ca container, dar imaginea `didi-kong:latest` e intactă local. Pași rollback:
|
||||
|
||||
1. **Restore docker-compose**: revert commitul care a scos `kong:` din `production/docker-compose.yml`
|
||||
2. **Repornește kong**: `cd backend/production && docker compose up -d kong`
|
||||
3. **Rollback edge Contabo**:
|
||||
```
|
||||
cp /srv/edge-nginx/conf.d/didi365.conf.bak.pre-kong-cluster-20260428 \
|
||||
/srv/edge-nginx/conf.d/didi365.conf
|
||||
nginx -s reload
|
||||
```
|
||||
4. **Rollback admin nginx**: revert commit-ul nginx-ssl.conf, rebuild `didi-admin:latest`
|
||||
|
||||
DB-ul Kong-ului local (`KONG_PG_DATABASE`) era pe clusterul Patroni — datele sunt încă acolo (nu s-au șters).
|
||||
|
||||
## Lecții importante (capcane confirmate)
|
||||
|
||||
1. **decK default `protocols: [https]` rupe HAProxy passthrough.** Cluster Kong returna `426 Please use HTTPS` deși edge termina TLS. HAProxy LB forwardează HTTP intern la DP — Kong vede HTTP. Fix: `_info.defaults.route.protocols: [http, https]`.
|
||||
|
||||
2. **Port binding upstream.** Original `didi-agent-v3` era `127.0.0.1:24803` și `didi-framework` deloc expus. Modificat în docker-compose la `10.11.10.12:24803`/`3005` ca DPs cluster să ajungă (LAN VLAN 10).
|
||||
|
||||
3. **strip_path nu e uniform.** Match local: `/agent/health`, `/auth`, `/framework`, `/agent-v3` au `strip_path: true`. Restul `false`. Verifică înainte să copiezi.
|
||||
|
||||
4. **Host header obligatoriu.** Cluster shared filtrează rute pe Host. Edge nginx și admin nginx fac `proxy_set_header Host didi365.eu`. Fără asta — 404.
|
||||
|
||||
5. **JWT plugin per-rută.** Cluster shared, alți tenanți nu vor JWT didi-clients. Plugin aplicat explicit pe 13 rute.
|
||||
|
||||
## Linkuri rapide
|
||||
|
||||
- Cluster Admin API: `http://10.11.10.176:8001`
|
||||
- Cluster ghid onboarding: `landingzone/kong-api/README.md` (repo `git.finesynergy.eu/lucian/landingzone`)
|
||||
- Documentație decK: <https://docs.konghq.com/deck/>
|
||||
|
||||
## Status
|
||||
|
||||
- ✅ Migrare aplicată: 2026-04-28
|
||||
- ✅ Kong local oprit și șters din docker-compose
|
||||
- ✅ Edge nginx Contabo actualizat
|
||||
- ✅ Admin nginx actualizat
|
||||
- ⏳ Soak 24-48h în desfășurare; eliminarea volumelor Kong după validare
|
||||
|
|
@ -0,0 +1,537 @@
|
|||
_format_version: "3.0"
|
||||
_info:
|
||||
select_tags:
|
||||
- product:didi
|
||||
- env:prod
|
||||
defaults:
|
||||
route:
|
||||
# Routes accept both HTTP and HTTPS (matches cluster pattern for lege365/rafai/etc).
|
||||
# HAProxy LB terminates TLS at edge, forwards HTTP to Kong DP — Kong must accept HTTP
|
||||
# internally or it returns 426 "Please use HTTPS protocol".
|
||||
protocols: [http, https]
|
||||
|
||||
# ============================================================
|
||||
# DIDI tenant configuration for shared Kong cluster
|
||||
# Cluster CP: 10.11.10.176:8001 | DP1: 10.11.10.177 | DP2: 10.11.10.178 | LB: 10.11.10.175
|
||||
# Hosts: didi365.eu (public) + www.didi365.eu + localhost (internal alias)
|
||||
# Upstreams: 10.11.10.12 (DIDI host) on exposed ports
|
||||
# Plugins are applied per-service (NOT global) — cluster shared with lege365/rafai/biddie/notify
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# CONSUMERS — JWT issuers preserved from local Kong (Keycloak realm didi-clients)
|
||||
# ============================================================
|
||||
consumers:
|
||||
- username: didi-keycloak-users
|
||||
custom_id: didi-keycloak-users
|
||||
tags: [product:didi, env:prod]
|
||||
jwt_secrets:
|
||||
- algorithm: RS256
|
||||
key: https://localhost/auth/realms/didi-clients
|
||||
secret: 1qG51hpfTte1TGQzcAhKWjVkXsMWNIun
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
|
||||
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
|
||||
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
|
||||
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
|
||||
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
|
||||
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
|
||||
/wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
- algorithm: RS256
|
||||
key: https://didi365.eu/auth/realms/didi-clients
|
||||
secret: IS8AJNbvC3taNROALc4bHslsZnSKELQD
|
||||
rsa_public_key: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
|
||||
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
|
||||
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
|
||||
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
|
||||
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
|
||||
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
|
||||
/wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
# SSO cluster (sso.local) — added 2026-04-29 after migration la Keycloak SSO public.
|
||||
# Same RSA public key (realm exported/imported from local with key preserved).
|
||||
- algorithm: RS256
|
||||
key: https://sso.local/realms/didi-clients
|
||||
secret: lEyVoR2eXLgWmQQ5q6fZRbCkVJhSaTuB
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
|
||||
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
|
||||
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
|
||||
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
|
||||
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
|
||||
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
|
||||
/wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
# Internal SSO host (used during transition; also kept for proxy fallback paths)
|
||||
- algorithm: RS256
|
||||
key: https://sso-admin.local/realms/didi-clients
|
||||
secret: kPwQjA4nFsUzMxRyV8tDeBcGhJlOvIuS
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
|
||||
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
|
||||
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
|
||||
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
|
||||
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
|
||||
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
|
||||
/wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
# didi-admins realm — admin-dashboard SPA auth (added 2026-05-04)
|
||||
# Different RSA key than didi-clients (separate realm).
|
||||
- algorithm: RS256
|
||||
key: https://didi365.eu/auth/realms/didi-admins
|
||||
secret: aDmInS001PuBlIcEdge2026May04PaSsKonGvErY
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
|
||||
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
|
||||
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
|
||||
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
|
||||
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
|
||||
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
|
||||
NwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
- algorithm: RS256
|
||||
key: https://sso.local/realms/didi-admins
|
||||
secret: aDmInS002SsOcLuStEr2026May04PaSsKonGvErY
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
|
||||
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
|
||||
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
|
||||
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
|
||||
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
|
||||
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
|
||||
NwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
- algorithm: RS256
|
||||
key: https://sso-admin.local/realms/didi-admins
|
||||
secret: aDmInS003LoCaLcLuStEr2026May04PaSsKonGv
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
|
||||
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
|
||||
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
|
||||
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
|
||||
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
|
||||
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
|
||||
NwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
- algorithm: RS256
|
||||
key: https://localhost/auth/realms/didi-admins
|
||||
secret: aDmInS004DiDi11LoCaL2026May04PaSsKonGvE
|
||||
rsa_public_key: |-
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
|
||||
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
|
||||
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
|
||||
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
|
||||
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
|
||||
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
|
||||
NwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
# ============================================================
|
||||
# SERVICES (4 consolidated from 9 local) + ROUTES + PER-SERVICE PLUGINS
|
||||
# ============================================================
|
||||
services:
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# SERVICE 1: didi-agent-v3 (was: agent-api + agent-v3 + agent-v3-api)
|
||||
# ----------------------------------------------------------
|
||||
- name: didi-agent-v3
|
||||
protocol: http
|
||||
host: 10.11.10.12
|
||||
port: 24803
|
||||
retries: 5
|
||||
connect_timeout: 60000
|
||||
write_timeout: 660000
|
||||
read_timeout: 660000
|
||||
tags: [product:didi, env:prod, kind:api]
|
||||
plugins:
|
||||
- name: cors
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
# chrome-extension://* and moz-extension://* required for browser extension API
|
||||
origins: [https://didi365.eu, https://www.didi365.eu, "chrome-extension://[a-z]+", "moz-extension://[a-z0-9-]+"]
|
||||
methods: [GET, POST, PUT, DELETE, OPTIONS, PATCH]
|
||||
# X-API-Key header required for extension auth
|
||||
headers: [Accept, Authorization, Content-Type, X-Request-ID, X-API-Key]
|
||||
exposed_headers: [X-Request-ID]
|
||||
credentials: true
|
||||
max_age: 3600
|
||||
preflight_continue: false
|
||||
- name: request-size-limiting
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
allowed_payload_size: 104857600
|
||||
size_unit: bytes
|
||||
require_content_length: false
|
||||
- name: response-transformer
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
add:
|
||||
headers: ["X-Gateway:DIDI-Kong-Cluster", "X-API-Version:2.0"]
|
||||
remove:
|
||||
headers: [Server, Via]
|
||||
- name: correlation-id
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
header_name: X-Request-ID
|
||||
generator: uuid
|
||||
echo_downstream: true
|
||||
routes:
|
||||
# JWT-protected endpoints
|
||||
- name: didi-agent-abort
|
||||
paths: [/api/abort]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: &didi-hosts [didi365.eu, www.didi365.eu, localhost]
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: &jwt-config
|
||||
key_claim_name: iss
|
||||
claims_to_verify: [exp]
|
||||
header_names: [authorization]
|
||||
uri_param_names: [jwt]
|
||||
run_on_preflight: true
|
||||
secret_is_base64: false
|
||||
maximum_expiration: 0
|
||||
- name: didi-agent-admin-services
|
||||
paths: [/api/v1/admin/services]
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-analysis
|
||||
paths: [/api/analysis]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-analyze
|
||||
paths: [/api/analyze]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-jobs
|
||||
paths: [/api/v1/jobs]
|
||||
methods: [GET, POST, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-pipelines
|
||||
paths: [/api/pipelines]
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-progress
|
||||
paths: [/api/progress]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-sessions
|
||||
paths: [/api/sessions]
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-storage
|
||||
paths: [/api/storage]
|
||||
methods: [GET, POST, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-subscriptions-v1
|
||||
# Legacy v1 endpoint on agent-v3 (current v2 is on framework-api)
|
||||
paths: [/api/v1/subscriptions]
|
||||
methods: [GET, POST, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, legacy:v1]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-agent-upload
|
||||
paths: [/api/upload]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
# Public endpoints (no JWT)
|
||||
- name: didi-agent-health
|
||||
# Local had strip_path=true: /agent/health -> "/" on agent-v3 (root, returns 200)
|
||||
paths: [/agent/health]
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: true
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true]
|
||||
- name: didi-agent-status
|
||||
paths: [/api/status]
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true]
|
||||
- name: didi-agent-media-public
|
||||
# Public media playback proxy (range-supported, served by agent-v3 itself)
|
||||
paths: [/api/v3/media/file]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true]
|
||||
- name: didi-agent-v3-prefix
|
||||
# Edge nginx forwards /agent-v3/* here. Local Kong stripped the prefix
|
||||
# (e.g. /agent-v3/api/v3/health -> /api/v3/health on agent-v3).
|
||||
# Local had JWT plugin on this route — preserved here to match security model.
|
||||
paths: [/agent-v3]
|
||||
hosts: *didi-hosts
|
||||
strip_path: true
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
# Browser extension API endpoints — NO JWT (X-API-Key validated in agent-v3).
|
||||
# All four routes share the same request-transformer pattern + rate-limit.
|
||||
# Regex paths (~ prefix) with `$` anchor prevent /analyze matching /analyze-async.
|
||||
|
||||
- name: didi-agent-extension-analyze
|
||||
# Sync analyze (legacy — small text only, hits Cloudflare 100s timeout otherwise)
|
||||
paths: [~/agent-v3/api/v3/pipeline/extension/analyze$]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true, auth:api-key]
|
||||
plugins:
|
||||
- name: request-transformer
|
||||
config:
|
||||
replace:
|
||||
uri: /api/v3/pipeline/extension/analyze
|
||||
- name: rate-limiting
|
||||
config: &ext-rate-limit
|
||||
minute: 30
|
||||
hour: 500
|
||||
policy: local
|
||||
limit_by: header
|
||||
header_name: X-API-Key
|
||||
fault_tolerant: true
|
||||
hide_client_headers: false
|
||||
error_code: 429
|
||||
error_message: "API rate limit exceeded"
|
||||
|
||||
- name: didi-agent-extension-analyze-async
|
||||
# Async dispatch — returns 202 + session_id (used by extension for all flows)
|
||||
paths: [~/agent-v3/api/v3/pipeline/extension/analyze-async$]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true, auth:api-key]
|
||||
plugins:
|
||||
- name: request-transformer
|
||||
config:
|
||||
replace:
|
||||
uri: /api/v3/pipeline/extension/analyze-async
|
||||
- name: rate-limiting
|
||||
config: *ext-rate-limit
|
||||
|
||||
- name: didi-agent-extension-upload
|
||||
# Multipart media upload (screenshot/video) — multer expects "file" field
|
||||
paths: [~/agent-v3/api/v3/pipeline/extension/upload$]
|
||||
methods: [POST, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true, auth:api-key]
|
||||
plugins:
|
||||
- name: request-transformer
|
||||
config:
|
||||
replace:
|
||||
uri: /api/v3/pipeline/extension/upload
|
||||
- name: rate-limiting
|
||||
config: *ext-rate-limit
|
||||
|
||||
- name: didi-agent-extension-status
|
||||
# Polling endpoint with sessionId capture — rewrite preserves the UUID
|
||||
paths: ['~/agent-v3/api/v3/pipeline/extension/status/(?<sid>[\w-]+)$']
|
||||
methods: [GET, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true, auth:api-key]
|
||||
plugins:
|
||||
- name: request-transformer
|
||||
config:
|
||||
replace:
|
||||
uri: /api/v3/pipeline/extension/status/$(uri_captures.sid)
|
||||
- name: rate-limiting
|
||||
config:
|
||||
# Polling can hit this every 2s — bump per-minute limit
|
||||
minute: 120
|
||||
hour: 2000
|
||||
policy: local
|
||||
limit_by: header
|
||||
header_name: X-API-Key
|
||||
fault_tolerant: true
|
||||
hide_client_headers: false
|
||||
error_code: 429
|
||||
error_message: "Polling rate limit exceeded"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# SERVICE 2: didi-framework (was: framework-api + didi-framework)
|
||||
# ----------------------------------------------------------
|
||||
- name: didi-framework
|
||||
protocol: http
|
||||
host: 10.11.10.12
|
||||
port: 3005
|
||||
retries: 5
|
||||
connect_timeout: 60000
|
||||
write_timeout: 60000
|
||||
read_timeout: 60000
|
||||
tags: [product:didi, env:prod, kind:api]
|
||||
plugins:
|
||||
- name: cors
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
origins: [https://didi365.eu, https://www.didi365.eu]
|
||||
methods: [GET, POST, PUT, DELETE, OPTIONS, PATCH]
|
||||
headers: [Accept, Authorization, Content-Type, X-Request-ID]
|
||||
exposed_headers: [X-Request-ID]
|
||||
credentials: true
|
||||
max_age: 3600
|
||||
preflight_continue: false
|
||||
- name: request-size-limiting
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
allowed_payload_size: 104857600
|
||||
size_unit: bytes
|
||||
require_content_length: false
|
||||
- name: response-transformer
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
add:
|
||||
headers: ["X-Gateway:DIDI-Kong-Cluster", "X-API-Version:2.0"]
|
||||
remove:
|
||||
headers: [Server, Via]
|
||||
- name: correlation-id
|
||||
tags: [product:didi, env:prod]
|
||||
config:
|
||||
header_name: X-Request-ID
|
||||
generator: uuid
|
||||
echo_downstream: true
|
||||
routes:
|
||||
- name: didi-framework-auth
|
||||
paths: [/api/auth]
|
||||
methods: [GET, POST, PUT, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-framework-auth-verify-email
|
||||
# PUBLIC route — must beat /api/auth (JWT) on priority
|
||||
paths: [/api/auth/verify-email]
|
||||
methods: [GET, POST]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
regex_priority: 100
|
||||
tags: [product:didi, env:prod, public:true]
|
||||
- name: didi-framework-history
|
||||
paths: [/api/history]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-framework-subscriptions
|
||||
# Current /api/subscriptions endpoint (v2). Legacy /api/v1/subscriptions is on agent-v3.
|
||||
paths: [/api/subscriptions]
|
||||
methods: [GET, POST, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
plugins:
|
||||
- name: jwt
|
||||
config: *jwt-config
|
||||
- name: didi-framework-waitlist
|
||||
# PUBLIC waitlist signup. Local Kong had this duplicated (one with JWT, one without).
|
||||
# Keeping no-JWT version — public signup is correct behavior.
|
||||
paths: [/api/waitlist]
|
||||
methods: [GET, POST, DELETE, OPTIONS]
|
||||
hosts: *didi-hosts
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod, public:true]
|
||||
- name: didi-framework-direct
|
||||
# Legacy /framework prefix — local had strip_path=true so /framework/api/X -> /api/X on framework
|
||||
paths: [/framework]
|
||||
hosts: *didi-hosts
|
||||
strip_path: true
|
||||
preserve_host: true
|
||||
tags: [product:didi, env:prod]
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# NOTE: didi-admin NOT migrated — internal-only (VPN access to 10.11.10.12 directly).
|
||||
# Will be revisited after admin nginx is replaced with simpler setup.
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# NOTE: didi-keycloak service REMOVED 2026-04-29.
|
||||
# DIDI now uses the external SSO cluster (https://sso.local/realms/didi-clients) directly
|
||||
# — SPA goes browser→sso.local, no proxy through cluster Kong needed.
|
||||
# JWT consumer didi-keycloak-users still validates tokens for SSO issuer.
|
||||
# ----------------------------------------------------------
|
||||
File diff suppressed because it is too large
Load diff
1829
backend/services/gateway-auth-layer/didiKong/declarative/kong.yml
Normal file
1829
backend/services/gateway-auth-layer/didiKong/declarative/kong.yml
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,392 @@
|
|||
_format_version: "3.0"
|
||||
_transform: true
|
||||
|
||||
# Service definitions for new architecture
|
||||
services:
|
||||
# Agent Service (NEW - replaces orchestration layer)
|
||||
- name: agent-api
|
||||
url: http://didi-agent:18789
|
||||
retries: 3
|
||||
connect_timeout: 120000
|
||||
write_timeout: 660000
|
||||
read_timeout: 660000
|
||||
tags:
|
||||
- agent
|
||||
- analysis
|
||||
|
||||
# Legacy: Orchestrator API Service (to be removed after migration)
|
||||
- name: orchestrator-api
|
||||
url: http://orchestrationLayer-orchestrator:8000
|
||||
retries: 5
|
||||
connect_timeout: 60000
|
||||
write_timeout: 60000
|
||||
read_timeout: 60000
|
||||
tags:
|
||||
- orchestrator
|
||||
- legacy
|
||||
|
||||
# Legacy: Analysis Service (to be removed after migration)
|
||||
- name: analysis-api
|
||||
url: http://orchestrationLayer-analysis:8004
|
||||
retries: 3
|
||||
connect_timeout: 120000
|
||||
write_timeout: 120000
|
||||
read_timeout: 120000
|
||||
tags:
|
||||
- analysis
|
||||
- legacy
|
||||
|
||||
# didiAI Platform Gateway (external) - disabled, configure via DIDIAI_GATEWAY_URL env var
|
||||
# - name: didiai-platform
|
||||
# url: ${DIDIAI_GATEWAY_URL}
|
||||
# retries: 3
|
||||
# connect_timeout: 60000
|
||||
# write_timeout: 60000
|
||||
# read_timeout: 60000
|
||||
# tags:
|
||||
# - didiai
|
||||
# - external
|
||||
|
||||
# Admin Dashboard
|
||||
- name: admin-dashboard
|
||||
url: http://didi-admin:80
|
||||
retries: 3
|
||||
connect_timeout: 30000
|
||||
write_timeout: 30000
|
||||
read_timeout: 30000
|
||||
tags:
|
||||
- ui
|
||||
- dashboard
|
||||
|
||||
# Routes
|
||||
routes:
|
||||
# ============================================
|
||||
# Agent Service Routes (NEW)
|
||||
# ============================================
|
||||
|
||||
# Agent Health Check
|
||||
- name: agent-health
|
||||
service: agent-api
|
||||
paths:
|
||||
- /agent/health
|
||||
strip_path: true
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# Agent Status (detailed)
|
||||
- name: agent-status
|
||||
service: agent-api
|
||||
paths:
|
||||
- /agent/status
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# Agent Pipelines List
|
||||
- name: agent-pipelines
|
||||
service: agent-api
|
||||
paths:
|
||||
- /api/pipelines
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# Agent Analysis (non-streaming)
|
||||
- name: agent-analyze
|
||||
service: agent-api
|
||||
paths:
|
||||
- /api/analyze
|
||||
strip_path: false
|
||||
methods:
|
||||
- POST
|
||||
|
||||
# Agent Session Status
|
||||
- name: agent-sessions
|
||||
service: agent-api
|
||||
paths:
|
||||
- /api/sessions
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# Agent File Upload
|
||||
- name: agent-upload
|
||||
service: agent-api
|
||||
paths:
|
||||
- /api/upload
|
||||
strip_path: false
|
||||
methods:
|
||||
- POST
|
||||
|
||||
# Agent Abort Session
|
||||
- name: agent-abort
|
||||
service: agent-api
|
||||
paths:
|
||||
- /api/abort
|
||||
strip_path: false
|
||||
methods:
|
||||
- POST
|
||||
|
||||
# ============================================
|
||||
# Legacy Orchestrator Routes (to be removed)
|
||||
# ============================================
|
||||
|
||||
# Orchestrator Routes
|
||||
- name: orchestrator-catalog
|
||||
service: orchestrator-api
|
||||
paths:
|
||||
- /api/v1/catalog
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
|
||||
- name: orchestrator-pipelines
|
||||
service: orchestrator-api
|
||||
paths:
|
||||
- /api/v1/pipelines
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- PATCH
|
||||
|
||||
- name: orchestrator-runs
|
||||
service: orchestrator-api
|
||||
paths:
|
||||
- /api/v1/runs
|
||||
strip_path: false
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
|
||||
- name: orchestrator-health
|
||||
service: orchestrator-api
|
||||
paths:
|
||||
- /orchestrator/health
|
||||
strip_path: true
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# Analysis Service Routes
|
||||
- name: analysis-health
|
||||
service: analysis-api
|
||||
paths:
|
||||
- /analysis/health
|
||||
strip_path: true
|
||||
methods:
|
||||
- GET
|
||||
|
||||
- name: analysis-stats
|
||||
service: analysis-api
|
||||
paths:
|
||||
- /analysis/stats
|
||||
strip_path: true
|
||||
methods:
|
||||
- GET
|
||||
|
||||
# didiAI Platform Routes (proxied) - disabled, enable when DIDIAI_GATEWAY_URL is configured
|
||||
# - name: didiai-extractors
|
||||
# service: didiai-platform
|
||||
# paths:
|
||||
# - /didiai/extractors
|
||||
# strip_path: true
|
||||
# methods:
|
||||
# - POST
|
||||
# - GET
|
||||
#
|
||||
# - name: didiai-models
|
||||
# service: didiai-platform
|
||||
# paths:
|
||||
# - /didiai/models
|
||||
# strip_path: true
|
||||
# methods:
|
||||
# - POST
|
||||
# - GET
|
||||
#
|
||||
# - name: didiai-discovery
|
||||
# service: didiai-platform
|
||||
# paths:
|
||||
# - /didiai/discovery
|
||||
# strip_path: true
|
||||
# methods:
|
||||
# - GET
|
||||
|
||||
# Admin Dashboard Routes
|
||||
- name: admin-ui
|
||||
service: admin-dashboard
|
||||
paths:
|
||||
- /admin
|
||||
strip_path: false
|
||||
preserve_host: true
|
||||
|
||||
- name: admin-api
|
||||
service: admin-dashboard
|
||||
paths:
|
||||
- /admin/api
|
||||
strip_path: false
|
||||
|
||||
# Global Plugins
|
||||
plugins:
|
||||
# CORS Configuration
|
||||
- name: cors
|
||||
config:
|
||||
origins:
|
||||
- "http://localhost:3000"
|
||||
- "http://localhost:3001"
|
||||
- "http://localhost:8100"
|
||||
- "*"
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- OPTIONS
|
||||
- PATCH
|
||||
headers:
|
||||
- Accept
|
||||
- Accept-Version
|
||||
- Content-Length
|
||||
- Content-MD5
|
||||
- Content-Type
|
||||
- Date
|
||||
- Authorization
|
||||
- X-Request-ID
|
||||
exposed_headers:
|
||||
- X-Auth-Token
|
||||
- X-Request-ID
|
||||
credentials: true
|
||||
max_age: 3600
|
||||
preflight_continue: false
|
||||
|
||||
# Rate Limiting (Global)
|
||||
- name: rate-limiting
|
||||
config:
|
||||
minute: 100
|
||||
hour: 2000
|
||||
day: 10000
|
||||
policy: local
|
||||
fault_tolerant: true
|
||||
hide_client_headers: false
|
||||
limit_by: consumer
|
||||
|
||||
# Request ID Tracking
|
||||
- name: correlation-id
|
||||
config:
|
||||
header_name: X-Request-ID
|
||||
generator: uuid
|
||||
echo_downstream: true
|
||||
|
||||
# Request Size Limiting (100MB for media files)
|
||||
- name: request-size-limiting
|
||||
config:
|
||||
allowed_payload_size: 104857600
|
||||
size_unit: bytes
|
||||
require_content_length: false
|
||||
|
||||
# Response Headers
|
||||
- name: response-transformer
|
||||
config:
|
||||
add:
|
||||
headers:
|
||||
- X-Gateway:DIDI-Kong
|
||||
- X-API-Version:2.0
|
||||
remove:
|
||||
headers:
|
||||
- Server
|
||||
- Via
|
||||
|
||||
# Consumers for future authentication (consumer_groups not supported in Kong 3.4)
|
||||
consumers: []
|
||||
|
||||
# Upstreams for load balancing (prepared for scaling)
|
||||
upstreams:
|
||||
# Agent Service Upstream (NEW)
|
||||
- name: agent-upstream
|
||||
algorithm: round-robin
|
||||
slots: 10000
|
||||
healthchecks:
|
||||
active:
|
||||
concurrency: 5
|
||||
healthy:
|
||||
http_statuses:
|
||||
- 200
|
||||
interval: 10
|
||||
successes: 2
|
||||
http_path: /health
|
||||
timeout: 10
|
||||
type: http
|
||||
unhealthy:
|
||||
http_failures: 3
|
||||
http_statuses:
|
||||
- 429
|
||||
- 500
|
||||
- 503
|
||||
interval: 10
|
||||
tcp_failures: 3
|
||||
timeouts: 3
|
||||
targets:
|
||||
- target: didi-agent:18789
|
||||
weight: 100
|
||||
tags:
|
||||
- agent
|
||||
|
||||
# Legacy: Orchestrator Upstream
|
||||
- name: orchestrator-upstream
|
||||
algorithm: round-robin
|
||||
slots: 10000
|
||||
healthchecks:
|
||||
active:
|
||||
concurrency: 10
|
||||
healthy:
|
||||
http_statuses:
|
||||
- 200
|
||||
- 302
|
||||
interval: 5
|
||||
successes: 3
|
||||
http_path: /health
|
||||
timeout: 5
|
||||
type: http
|
||||
unhealthy:
|
||||
http_failures: 3
|
||||
http_statuses:
|
||||
- 429
|
||||
- 500
|
||||
- 503
|
||||
interval: 5
|
||||
tcp_failures: 3
|
||||
timeouts: 3
|
||||
targets:
|
||||
- target: orchestrationLayer-orchestrator:8000
|
||||
weight: 100
|
||||
tags:
|
||||
- orchestrator
|
||||
- legacy
|
||||
|
||||
- name: analysis-upstream
|
||||
algorithm: least-connections
|
||||
slots: 10000
|
||||
healthchecks:
|
||||
active:
|
||||
concurrency: 5
|
||||
healthy:
|
||||
http_statuses:
|
||||
- 200
|
||||
interval: 10
|
||||
successes: 2
|
||||
http_path: /health
|
||||
timeout: 10
|
||||
type: http
|
||||
unhealthy:
|
||||
http_failures: 5
|
||||
interval: 10
|
||||
timeouts: 5
|
||||
targets:
|
||||
- target: orchestrationLayer-analysis:8004
|
||||
weight: 100
|
||||
tags:
|
||||
- analysis
|
||||
21
backend/services/gateway-auth-layer/didiKong/entrypoint.sh
Normal file
21
backend/services/gateway-auth-layer/didiKong/entrypoint.sh
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Start Kong in the background
|
||||
/docker-entrypoint.sh kong docker-start &
|
||||
KONG_PID=$!
|
||||
|
||||
# Wait for Kong to be ready
|
||||
echo "Waiting for Kong to start..."
|
||||
until kong health; do
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "Kong is ready!"
|
||||
echo "Configuration should already be imported by migrations container."
|
||||
|
||||
# Check current services count
|
||||
SERVICE_COUNT=$(curl -s http://localhost:8001/services 2>/dev/null | grep -o '"id"' | wc -l)
|
||||
echo "Current services in Kong: $SERVICE_COUNT"
|
||||
|
||||
# Keep Kong running in foreground
|
||||
wait $KONG_PID
|
||||
Loading…
Add table
Add a link
Reference in a new issue