Aller au contenu principal

Passerelle APISIX et WAF

Version anglaise : en/waf-gateway.md.

Fichiers : deploy/apisix/config.yaml (réglages du nœud) et deploy/apisix/apisix.yaml (routes déclaratives, mode standalone).

TLS​

  • ssl_protocols: TLSv1.2 TLSv1.3, suites ECDHE avec AES-GCM ou ChaCha20-Poly1305 uniquement, tickets de session désactivés.
  • Règle globale redirect: {http_to_https: true} : tout accès HTTP reçoit une redirection 301 vers HTTPS.
  • Strict-Transport-Security: max-age=31536000; includeSubDomains; preload sur toutes les réponses (plugin_config edge-hardening), en plus de EAI_HSTS_ENABLED=true côté backend.
  • Vers le control plane : HTTP à l'intérieur du cluster (scheme: http, le control plane ne sert que du HTTP), chiffré de nœud à nœud par WireGuard et authentifié par l'authentification mutuelle Cilium (entrée depuis le namespace apisix avec authentication.mode: required), et upstream_host égal à EAI_ALLOWED_HOSTS.

WAF Coraza et OWASP CRS​

Le module coraza-proxy-wasm est chargé par la section wasm de config.yaml (fichier /usr/local/apisix/proxywasm/coraza-proxy-wasm.wasm, image miroir dans Harbor épinglée par digest). Le plugin coraza-filter charge @coraza.conf-recommended, @crs-setup.conf.example et @owasp_crs/*.conf avec SecRuleEngine On : mode bloquant, niveau de paranoïa 1, seuil d'anomalie entrant 5.

Pour un faux positif : ajouter une exclusion ciblée (SecRuleUpdateTargetById ou SecRuleRemoveById sur une route précise), jamais SecRuleEngine DetectionOnly en production. Passer d'abord la route en niveau de paranoïa 2 sur un environnement de recette avant de durcir.

En-têtes internes​

Le client ne peut jamais fournir une identité ou une adresse :

  1. le plugin real-ip (priorité la plus haute) calcule l'adresse du client à partir de X-Forwarded-For uniquement si le pair est le répartiteur de charge (10.0.0.0/8) ;
  2. serverless-pre-function supprime ensuite tous les en-têtes X-Dev-*, X-SPIFFE-ID, X-Forwarded-*, X-Real-IP et Forwarded, et supprime un X-Request-Id qui n'est pas un jeton court (^[A-Za-z0-9._:-]{8,128}$), ce qui empêche l'injection d'en-têtes et la falsification des journaux ;
  3. proxy-rewrite réécrit X-Forwarded-For, X-Real-IP, X-Forwarded-Proto, X-Forwarded-Host et X-Forwarded-Port avec les valeurs de la passerelle ;
  4. request-id génère un identifiant UUID lorsque le client n'en a pas fourni de valide.

Côté backend, EAI_TRUSTED_PROXIES ne contient que le CIDR des pods APISIX et du contrôleur d'ingress : un autre pair ne peut pas imposer X-Forwarded-For ni X-SPIFFE-ID.

Limites de taille et de débit​

RouteCorps maximalLimite
/v1/* (OIDC)10 Mio (EAI_MAX_BODY_BYTES)600 requêtes par minute par jeton, Redis TLS partagé
/v1/* (clé API)10 Mio1200 par minute par clé, 200 connexions simultanées
routes de téléversement (_UPLOAD de security/limits.py)100 Mio (EAI_MAX_UPLOAD_BYTES)60 par minute par jeton ou clé
/v1/gateway/*, /v1/realtime/*10 Mio20 requêtes par seconde par IP
/login, /api/auth/* du portail64 Kio10 par minute par IP
toutes les routes publiques50 requêtes par seconde par IP (rafale 100)

Les compteurs partagés utilisent l'utilisateur ACL Redis apisix sur TLS (redis_ssl: true, redis_ssl_verify: true).

Métriques et documentation jamais publiques​

La route deny-metrics (priorité 1000) répond 404 pour /metrics, /apisix/prometheus/metrics, /openapi.json, /docs et /redoc. L'exportateur Prometheus d'APISIX écoute sur un port privé (9091) ; Prometheus collecte les pods directement, autorisé par les NetworkPolicies depuis le namespace d'observabilité. EAI_DOCS_ENABLED=false désactive aussi la documentation côté backend en production.

CORS et en-têtes de réponse​

  • CORS uniquement sur la route OIDC, origine exacte https://<portal-host>, sans identifiants, liste d'en-têtes explicite, max_age 600.
  • En-têtes ajoutés : X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy, Permissions-Policy, Cache-Control: no-store ; Server et X-Powered-By sont retirés, enable_server_tokens: false.

Ingress du portail​

templates/portal/ingress.yaml crée deux Ingress (/ et /login) avec TLS cert-manager, redirection HTTPS forcée, TLS 1.2 et 1.3, HSTS, taille de corps limitée et une limite dédiée sur /login (portal.ingress.loginRateLimitPerMinute, 10 par défaut). Les en-têtes de sécurité de bord sont dans la ConfigMap <release>-portal-edge-headers, appliquée par l'annotation custom-headers ; le contrôleur doit les autoriser dans global-allowed-response-headers. Les snippets restent désactivés sur le contrôleur.