155 lines
5.9 KiB
YAML
155 lines
5.9 KiB
YAML
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: {{ include "waf-cluster.fullname" . }}-conf
|
|
namespace: {{ .Release.Namespace }}
|
|
labels:
|
|
{{- include "waf-cluster.labels" . | nindent 4 }}
|
|
data:
|
|
app.conf: |
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name _;
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
server_name _;
|
|
|
|
server_tokens off;
|
|
|
|
ssl_certificate /etc/nginx/certs/tls.crt;
|
|
ssl_certificate_key /etc/nginx/certs/tls.key;
|
|
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
|
|
ssl_prefer_server_ciphers off;
|
|
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 1d;
|
|
ssl_session_tickets off;
|
|
|
|
client_max_body_size 10M;
|
|
client_body_buffer_size 128k;
|
|
client_header_buffer_size 1k;
|
|
large_client_header_buffers 4 8k;
|
|
|
|
client_body_timeout 30s;
|
|
client_header_timeout 30s;
|
|
send_timeout 30s;
|
|
keepalive_timeout 65s;
|
|
|
|
access_log /dev/stdout;
|
|
error_log /dev/stderr warn;
|
|
|
|
modsecurity on;
|
|
modsecurity_rules_file /etc/nginx/modsec/custom-rules.conf;
|
|
|
|
# Terminaison TLS ici, puis nouvelle connexion TLS vers l'entryPoint
|
|
# websecure du Traefik partagé (deploy/chart-gestion/traefik) : aucun
|
|
# changement requis côté Traefik/IngressRoute, il continue de router
|
|
# par Host comme si le client s'y connectait directement. Host
|
|
# préservé pour que le routage par Host de Traefik fonctionne.
|
|
location / {
|
|
proxy_pass https://{{ .Values.upstream.host }}:{{ .Values.upstream.port }};
|
|
proxy_ssl_server_name on;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Connection "";
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_connect_timeout 10s;
|
|
proxy_send_timeout 300s;
|
|
proxy_read_timeout 300s;
|
|
}
|
|
|
|
location = /healthz {
|
|
access_log off;
|
|
return 200 "ok";
|
|
add_header Content-Type text/plain;
|
|
}
|
|
}
|
|
|
|
custom-rules.conf: |
|
|
# Règles maison — le reste (SecRuleEngine, Include CRS, seuils de
|
|
# paranoïa) est déjà configuré par l'entrypoint de l'image
|
|
# owasp/modsecurity-crs à partir des variables d'env PARANOIA/
|
|
# ANOMALY_INBOUND/ANOMALY_OUTBOUND (voir values.yaml waf.*), même
|
|
# mécanisme que docker/waf (omnex-prod).
|
|
SecAuditLogParts ABIFHZ
|
|
|
|
# 911100 (REQUEST-911-METHOD-ENFORCEMENT) n'autorise par défaut que GET
|
|
# HEAD POST OPTIONS — bloque tout DELETE/PUT/PATCH légitime de l'API
|
|
# REST. Même correctif appliqué côté docker/waf/custom-rules.conf
|
|
# (omnex-prod) et côté Coraza/Traefik (deploy/chart-gestion/traefik/
|
|
# templates/middleware-waf.yaml).
|
|
SecRuleRemoveById 911100
|
|
|
|
SecRule IP:BANNED "@eq 1" \
|
|
"id:100000,phase:1,deny,status:403,log,\
|
|
msg:'IP is banned'"
|
|
|
|
SecRule IP:REPUTATION_SCORE "@ge 100" \
|
|
"id:100099,phase:1,deny,status:403,log,\
|
|
msg:'Critical reputation score',\
|
|
setvar:'ip.blocked=1',expirevar:'ip.blocked=86400'"
|
|
|
|
SecRule TX:SQL_INJECTION_SCORE "@ge 5" \
|
|
"id:100001,phase:2,deny,status:403,log,\
|
|
msg:'SQL Injection detected',\
|
|
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
|
|
|
|
SecRule TX:XSS_SCORE "@ge 5" \
|
|
"id:100010,phase:2,deny,status:403,log,\
|
|
msg:'XSS detected',\
|
|
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
|
|
|
|
SecRule TX:RCE_SCORE "@ge 5" \
|
|
"id:100020,phase:2,deny,status:403,log,\
|
|
msg:'RCE detected',\
|
|
setvar:'ip.banned=1',expirevar:'ip.banned=259200'"
|
|
|
|
SecRule TX:LFI_SCORE "@ge 5" \
|
|
"id:100030,phase:2,deny,status:403,log,\
|
|
msg:'LFI detected',\
|
|
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
|
|
|
|
SecRule TX:INBOUND_ANOMALY_SCORE "@ge 20" \
|
|
"id:100060,phase:2,deny,status:403,log,\
|
|
msg:'Critical anomaly score',\
|
|
setvar:'ip.banned=1',expirevar:'ip.banned=172800'"
|
|
|
|
# Suppressions CRS pour les routes légitimes de l'app démo (mêmes IDs
|
|
# que l'ancienne config coraza-http-wasm, voir
|
|
# deploy/chart-gestion/traefik/templates/middleware-waf.yaml — conservé
|
|
# à titre d'historique, plus utilisé, coraza-waf retiré de la chaîne).
|
|
SecRule REQUEST_URI "@streq /api/v2/admin/protected/products" \
|
|
"id:399001,phase:2,nolog,pass,ctl:ruleRemoveById=932235"
|
|
SecRule REQUEST_URI "@streq /api/v2/admin/protected/products" \
|
|
"id:399002,phase:2,nolog,pass,ctl:ruleRemoveById=920120,ctl:ruleRemoveById=920121"
|
|
SecRule REQUEST_URI "@streq /api/v1/panier/remove" \
|
|
"id:399010,phase:1,nolog,pass,ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
|
|
SecRule REQUEST_URI "@streq /api/v1/panier/clear" \
|
|
"id:399011,phase:1,nolog,pass,ctl:ruleRemoveById=911100,ctl:ruleRemoveById=920350"
|
|
|
|
# Fichiers uploadés — WAF désactivé (lecture seule, contenu déjà validé
|
|
# à l'upload).
|
|
SecRule REQUEST_URI "@beginsWith /uploads/" \
|
|
"id:1000,phase:1,pass,nolog,ctl:ruleEngine=Off"
|
|
|
|
# Rate limit basique par IP (indépendant du RateLimit du control-plane
|
|
# sur /auth/login, et du middleware rate-limit de Traefik en aval).
|
|
SecAction \
|
|
"id:400161,phase:1,nolog,pass,\
|
|
setvar:'ip.request_window_1sec=+1',\
|
|
expirevar:'ip.request_window_1sec=1'"
|
|
|
|
SecRule IP:REQUEST_WINDOW_1SEC "@gt 20" \
|
|
"id:400160,phase:1,deny,status:429,log,\
|
|
msg:'Too many requests'"
|