Плагины и middleware в API Gateway
1) Зачем нужны плагины и middleware
API-шлюз — точка принудительного исполнения корпоративных политик. Правильно собранная цепочка плагинов:- стандартизирует безопасность (authN/authZ, WAF, CORS),
- защищает устойчивость (rate limit, circuit breaker, retry-policies),
- управляет контрактом (валидация схем, трансформации),
- дает наблюдаемость (метрики, логи, трассировка),
- снижает стоимость (кэширование, дедупликация, канареечные правила).
Ключ: минимальная латентность и четкая последовательность применения.
2) Классы плагинов и что они делают
1. Идентификация/аутентификация
JWT/JWKS-провайдеры, OAuth2/OIDC, API-ключи, mTLS (client cert).
HMAC-подписи (вебхуки/партнеры), DPoP/PoP на краю.
2. Авторизация
RBAC/ABAC/OPA/Cedar (PDP) с локальным кэшем решений.
BOLA-guard: проверка `tenant`/`owner` в заголовках/контексте.
3. Сетевые и протокольные защиты
WAF (OWASP CRS), антибот (rate/behavioral), Geo/IP/ASN-фильтры, TLS-профили.
CORS, CSP-заголовки, Fetch-Metadata фильтры, CORP/COOP/COEP.
4. Устойчивость
Rate limiting (token bucket/GCRA), квоты и конкурентность.
Circuit breaker, таймауты, adaptive concurrency, load shedding.
Retry-policy с per-try timeout и джиттером.
5. Трансформации и валидация
Перепись путей/заголовков, body-rewrite, JSON/XML ↔, gRPC ↔ HTTP.
Валидация схем (OpenAPI/JSON Schema/Protobuf), нормализация ID.
6. Кэширование и производительность
Response/fragment cache, ETag/If-None-Match, компрессия, brotli.
Request collapsing (coalescing) для одинаковых ключей.
7. Наблюдаемость и аудит
Метрики RED/USE, логирование решений (429/403/5xx), трассировка (W3C Trace-Context/OpenTelemetry), сэмплинг (tail/adaptive).
Аудит заголовков безопасности и версий политик.
8. Жизненный цикл и эксплуатация
Canary/blue-green, feature-flags, shadow-решения (логировать, не применять), миграции версий.
3) Порядок применения (рекомендуемая цепочка)
[Ingress TLS]
→ Early-Deny (ASN/Geo, IP allow/deny)
→ mTLS / Client Cert Auth
→ JWT/OAuth2 AuthN (JWKS cache)
→ OPA/ABAC AuthZ (solution cache)
→ Rate Limit / Concurrency
→ Circuit / Timeout / Retries (пер-try)
→ Schema Validation (request)
→ Transform (headers/path/body) / CORS
→ Caching (lookup)
→ Upstream Proxy (app)
← Caching (store) / Compression
← Response Transform / Schema Validation (response)
← Logging / Tracing / Metrics / Security Headers
Принцип: раньше — дешевле/фатальнее (deny, auth, лимиты), позже — «косметика» (трансформации, кэш).
4) Производительность и кардинальность
Придерживайтесь O(1) шагов без внешних запросов в горячем пути.
Все «внешние звонки» плагинов (PDP/JWKS) — через короткие TTL и asynchronous refresh.
Метки/лейблы для метрик — ограниченная кардинальность (`tenant`, `plan`, `route`, но не `user_id`).
«Тяжелые» плагины (WAF, body-transform) — включать селективно per-route.
5) Примеры конфигураций
5.1 Envoy: JWT + RateLimit + OPA + Retries (псевдо)
yaml static_resources:
listeners:
- name: public_listener filter_chains:
- filters:
- name: envoy. filters. network. http_connection_manager typed_config:
route_config:
name: main virtual_hosts:
- name: api domains: ["api. example. com"]
routes:
- match: { prefix: "/v1/payments" }
route:
cluster: payments timeout: 350ms retry_policy:
retry_on: connect-failure,reset,5xx,gateways num_retries: 1 per_try_timeout: 200ms http_filters:
- name: envoy. filters. http. jwt_authn typed_config:
providers:
oidc:
issuer: https://auth. example. com/
remote_jwks:
http_uri: { uri: https://auth. example. com/.well-known/jwks. json, cluster: jwks, timeout: 2s }
cache_duration: 300s forward: true
- name: envoy. filters. http. ext_authz # OPA/Cedar PDP typed_config:
http_service:
server_uri: { uri: http://opa:8181, cluster: opa, timeout: 50ms }
authorization_request: { allowed_headers: { patterns: [{ exact: "authorization" }, { exact: "x-tenant" }] } }
- name: envoy. filters. http. ratelimit typed_config:
domain: public-api rate_limit_service:
grpc_service: { envoy_grpc: { cluster_name: rl } }
- name: envoy. filters. http. router
5.2 NGINX/OpenResty: HMAC + Lua + Redis (псевдо)
nginx lua_shared_dict jwks 10m;
lua_shared_dict limits 10m;
server {
listen 443 ssl http2;
Early deny by ASN/Geo if ($bad_asn) { return 403; }
HMAC signature check (webhooks/partners)
set_by_lua_block $sig_ok {
return verify_hmac_signature(ngx. var. http_x_signature, ngx. var. request_time, ngx. var. request_body)
}
if ($sig_ok = 0) { return 401; }
Token bucket in Redis access_by_lua_block {
local key = ngx. var. binary_remote_addr.. ":".. ngx. var. request_uri local allowed, retry_after = ratelimit_allow(key, 50, 100)
if not allowed then ngx. header["Retry-After"] = retry_after return ngx. exit(429)
end
}
proxy_read_timeout 300ms;
proxy_connect_timeout 100ms;
proxy_pass http://app_backend;
}
5.3 Kong: плагины по маршруту
yaml services:
- name: payments url: http://payments:8080 routes:
- service: payments paths: ["/v1/payments"]
plugins:
- name: jwt config: { key_claim_name: kid, secret_is_base64: false, run_on_preflight: false }
- name: opa config: { server_url: "http://opa:8181/v1/data/authz/allow", timeout: 50 }
- name: rate-limiting config: { second: 50, policy: redis, redis_host: redis, fault_tolerant: true }
- name: correlation-id config: { header_name: "traceparent" }
- name: response-transformer config: { add: { headers: ["Strict-Transport-Security:max-age=31536000"] } }
5.4 Apache APISIX: JWT + Limit + Proxy-Mirror (shadow)
yaml routes:
- uri: /v1/wallets/
plugins:
openid-connect:
client_id: wallet discovery: "https://auth. example. com/.well-known/openid-configuration"
scope: "openid"
limit-count:
count: 100 time_window: 60 key_type: "var"
key: "remote_addr"
proxy-mirror: # shadow traffic host: "http://shadow-backend:8080"
upstream_id: 1
5.5 Traefik: Middleware-цепочка
yaml http:
middlewares:
hsts-headers:
headers:
stsSeconds: 31536000 stsIncludeSubdomains: true ratelimit:
rateLimit:
average: 50 burst: 100 routers:
api:
rule: "Host(`api. example. com`) && PathPrefix(`/v1`)"
service: app middlewares:
- hsts-headers
- ratelimit
6) Многоарендность и версии политик
Ключ маршрутизации: `{tenant, plan, region, route, version}`.
Плагины читают `tenant` из mTLS SAN/JWT-клейма/заголовка → применяют пер-тенант лимиты/квоты/правила.
Версионируйте политики (`policy_version`), ведите changelog и канареечный rollout.
7) Тестирование и rollout
До релиза
Контрактные тесты цепочки (таблица «если-то»): auth→deny, auth→allow, rate→429, schema→422.
Нагрузочные: бурсты ×10, длинные плато, «грязные» паттерны (slow-POST).
Chaos: деградация PDP/JWKS/Redis — должны быть fail-closed/деградация к минимально безопасному.
Релиз
`Report-Only`/shadow-mode (логируем решения без применения).
Canary 1–5% трафика + сравнение метрик (p95/p99, 4xx/5xx/429).
Автоматический rollback по SLO/алертам.
8) Наблюдаемость и метрики
Метрики:- `http_requests_total{route,tenant,plan,status}`
- `request_duration_seconds_bucket{route}` (p95/p99)
- `rate_limited_total{policy}`, `retry_total{reason}`, `circuit_state`
- `authn_fail_total{reason}`, `authz_denied_total{action}`
- `schema_validation_fail_total{route}`
- Трейсы: спаны per-filter, атрибуты `policy_version`, `tenant`, `limit_key`.
- Логи (сэмплированно): решения deny/429/5xx с причинами и `trace_id`.
- Дашборды: Exec-сводка, per-route, per-tenant, «горячие» политики.
9) Безопасность и эксплуатация
Все секреты (HMAC, JWKS private, API-ключи) — в KMS/Vault, не в конфиг-файлах.
Политика deny-by-default для чувствительных маршрутов.
Короткие TTL JWKS/кэша PDP, асинхронные обновления с backoff.
Миграции схем трансформаций — versioned; «ломающие» — через dual-write.
Ограничивайте body-size (DoS) и глубину JSON.
10) Антипаттерны
Универсальный «все включено» набор плагинов на каждом маршруте → лишние миллисекунды и счета.
Внешние зависимости плагинов без кэша/таймаутов → каскадные таймауты.
Отсутствие порядка фильтров: сначала трансформации/логика, потом лимиты — неверно.
Высокая кардинальность лейблов метрик (raw `user_id`/`ip`).
Смешивание authN/authZ в шаблонах трансформации (неявные решения в Lua/Jinja).
Логирование секретов/токенов.
Один глобальный Redis/кластер для всех лимитов без шардирования/резерва.
11) Специфика iGaming/финансов
Пер-тенант/пер-юрисдикция правила: KYC/AML, санкции, лимиты ответственных платежей.
Жесткие политики для платежных маршрутов: короткие таймауты, один повтор, идемпотентность (`Idempotency-Key`).
Разделение периметров для PSP/KYC SDK (отдельные домены/цепочки плагинов).
Аудит неизменяемых логов решений (выводы, блокировки, санкционный отказ).
12) Чек-лист prod-готовности
- Определен порядок фильтров: authN → authZ → limits → circuit/timeout → schema → transform → cache.
- Пер-маршрутный набор плагинов; тяжелые — только там, где нужно.
- JWKS/PDP с коротким TTL и кэшом; таймауты и fallback-стратегии.
- Rate/Quota/Concurrency — спроектированы ключи, шардирование хранилища.
- Набор метрик RED/USE, трассировка OTel, сэмплинг tail/adaptive.
- Canary + shadow-режим, auto-rollback по SLO.
- Секреты в KMS/Vault; конфиги — версионируемые, с миграциями.
- Лимиты body/headers; защита от oversize/slow-POST.
- Документация для клиентов: коды 401/403/409/422/429/5xx, `Retry-After`, примеры заголовков.
13) TL;DR
Стройте цепочку «ранний отказ → аутентификация/авторизация → лимиты/устойчивость → валидация → трансформации/кэш → телеметрия». Включайте только нужные плагины per-route, кэшируйте внешние решения (JWKS/PDP), задавайте таймауты и retry-политики, контролируйте кардинальность метрик. Релизите через shadow/canary, держите секреты в KMS/Vault и измеряйте влияние каждого плагина на p95/p99.