@@ -20,6 +20,10 @@ spec:
|
||||
labels:
|
||||
{{- include "backend.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
|
||||
@@ -5,6 +5,11 @@ image:
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials)
|
||||
# si un compte Docker Hub authentifié est configuré — évite le rate-limit de
|
||||
# pull anonyme partagé par IP de nœud. Vide = pull anonyme (défaut).
|
||||
imagePullSecrets: []
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
@@ -16,6 +16,10 @@ spec:
|
||||
labels:
|
||||
{{- include "frontend.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
@@ -25,8 +29,13 @@ spec:
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
ports:
|
||||
# L'image xor1234/frontend-mln (nginx) écoute en dur sur le port
|
||||
# 80 (voir /etc/nginx/conf.d/default.conf embarqué dans l'image) —
|
||||
# déjà anticipé par deploy/chart-gestion/ingressroute/values.yaml
|
||||
# (frontend.servicePort: 80). 8080 ici ne correspondait à rien de
|
||||
# réellement écouté, d'où le "connection refused" en probe.
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
@@ -37,6 +46,15 @@ spec:
|
||||
mountPath: /srv/config.js
|
||||
subPath: config.js
|
||||
readOnly: true
|
||||
# readOnlyRootFilesystem:true (voir securityContext) empêche
|
||||
# nginx de créer /var/cache/nginx/client_temp au démarrage
|
||||
# ("mkdir() ... failed (30: Read-only file system)", CrashLoop) —
|
||||
# nginx a besoin d'y écrire même quand il ne sert que du
|
||||
# contenu statique.
|
||||
- name: nginx-cache
|
||||
mountPath: /var/cache/nginx
|
||||
- name: nginx-run
|
||||
mountPath: /var/run
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
@@ -56,6 +74,10 @@ spec:
|
||||
emptyDir: {}
|
||||
- name: caddy-data
|
||||
emptyDir: {}
|
||||
- name: nginx-cache
|
||||
emptyDir: {}
|
||||
- name: nginx-run
|
||||
emptyDir: {}
|
||||
- name: app-config
|
||||
configMap:
|
||||
name: {{ include "frontend.fullname" . }}-config
|
||||
|
||||
@@ -7,9 +7,18 @@ image:
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials)
|
||||
# si un compte Docker Hub authentifié est configuré — évite le rate-limit de
|
||||
# pull anonyme partagé par IP de nœud. Vide = pull anonyme (défaut).
|
||||
imagePullSecrets: []
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
# L'IngressRoute (deploy/chart-gestion/ingressroute) référence directement
|
||||
# ce port de Service (frontend.servicePort, déjà à 80 dans son
|
||||
# values.yaml — il anticipait correctement le vrai port de nginx). Doit
|
||||
# rester égal à containerPort (voir templates/deployment.yaml).
|
||||
port: 80
|
||||
|
||||
resources:
|
||||
requests:
|
||||
|
||||
@@ -18,6 +18,10 @@ spec:
|
||||
labels:
|
||||
{{- include "lbtelegram.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
|
||||
@@ -5,6 +5,11 @@ image:
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials)
|
||||
# si un compte Docker Hub authentifié est configuré — évite le rate-limit de
|
||||
# pull anonyme partagé par IP de nœud. Vide = pull anonyme (défaut).
|
||||
imagePullSecrets: []
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
|
||||
@@ -15,6 +15,10 @@ spec:
|
||||
labels:
|
||||
{{- include "postgresql.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
|
||||
@@ -3,6 +3,11 @@ image:
|
||||
tag: "16-alpine"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials)
|
||||
# si un compte Docker Hub authentifié est configuré — évite le rate-limit de
|
||||
# pull anonyme partagé par IP de nœud. Vide = pull anonyme (défaut).
|
||||
imagePullSecrets: []
|
||||
|
||||
auth:
|
||||
username: postgres
|
||||
database: gestion_db
|
||||
|
||||
@@ -15,6 +15,10 @@ spec:
|
||||
labels:
|
||||
{{- include "redis.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
|
||||
@@ -3,6 +3,11 @@ image:
|
||||
tag: "7-alpine"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials)
|
||||
# si un compte Docker Hub authentifié est configuré — évite le rate-limit de
|
||||
# pull anonyme partagé par IP de nœud. Vide = pull anonyme (défaut).
|
||||
imagePullSecrets: []
|
||||
|
||||
auth:
|
||||
# À surcharger via --set auth.password=xxx
|
||||
password: ""
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: gestion-registry-credentials
|
||||
description: Secret docker-registry (Docker Hub authentifié) installé par démo — évite le rate-limit de pull anonyme (100/6h par IP, contre 200/6h authentifié) partagé entre tous les pods du même nœud.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
@@ -0,0 +1,9 @@
|
||||
{{- if and .Values.username .Values.password }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ .Values.secretName }}
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
data:
|
||||
.dockerconfigjson: {{ printf `{"auths":{"%s":{"username":"%s","password":"%s","auth":"%s"}}}` .Values.registry .Values.username .Values.password (printf "%s:%s" .Values.username .Values.password | b64enc) | b64enc }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Identifiants Docker Hub (compte dédié, droits de lecture seule suffisent —
|
||||
# pas besoin d'un compte payant, le seul but est de doubler le rate-limit de
|
||||
# pull anonyme : 100/6h par IP -> 200/6h authentifié). Jamais codés en dur,
|
||||
# injectés par le control-plane (voir OMNEX_DOCKERHUB_USERNAME/PASSWORD dans
|
||||
# internal/config/config.go) au moment de l'installation.
|
||||
secretName: dockerhub-pull-secret
|
||||
registry: https://index.docker.io/v1/
|
||||
username: ""
|
||||
password: ""
|
||||
@@ -9,5 +9,14 @@ spec:
|
||||
chain:
|
||||
middlewares:
|
||||
- name: rate-limit
|
||||
- name: coraza-waf
|
||||
# coraza-waf désactivé temporairement (2026-08-17) : fait planter
|
||||
# Traefik (panic Go "unsafe.Slice: len out of range" dans le runtime
|
||||
# WASM du plugin coraza-http-wasm-traefik v0.3.0) dès qu'une vraie
|
||||
# IngressRoute de démo l'active — reproductible à 100% au chargement,
|
||||
# crash-loop du pod partagé, bloque TOUTES les démos. Jamais exercé
|
||||
# avant la toute première démo réelle. À investiguer (version du
|
||||
# plugin ? directives ModSecurity trop volumineuses/complexes pour ce
|
||||
# runtime WASM ?) avant réactivation — voir middleware-waf.yaml pour
|
||||
# les directives complètes.
|
||||
# - name: coraza-waf
|
||||
- name: security-headers
|
||||
|
||||
@@ -27,6 +27,17 @@ rateLimit:
|
||||
# https://github.com/traefik/traefik-helm-chart
|
||||
# =============================================================
|
||||
traefik:
|
||||
# Injecté par le provisioner (voir deploy/chart-gestion/registry-credentials,
|
||||
# installé dans le namespace traefik par EnsureSharedInfra) si un compte
|
||||
# Docker Hub authentifié est configuré — évite le rate-limit de pull
|
||||
# anonyme. Vide = pull anonyme (défaut). Sous "deployment", pas à la racine
|
||||
# : c'est l'emplacement attendu par values.schema.json du chart officiel
|
||||
# traefik/traefik (voir charts/traefik-41.1.0.tgz) — un imagePullSecrets à
|
||||
# la racine est rejeté ("Additional property imagePullSecrets is not
|
||||
# allowed").
|
||||
deployment:
|
||||
imagePullSecrets: []
|
||||
|
||||
# Expose les ports 80 et 443. Le port web redirige automatiquement vers
|
||||
# websecure au niveau de l'entrypoint (pas besoin d'IngressRoute dédiée).
|
||||
# Schéma valable pour le chart traefik/traefik >= 34 (vendored : 41.1.0,
|
||||
@@ -96,8 +107,17 @@ traefik:
|
||||
# prix de perdre l'IP réelle du client (SNAT par kube-proxy) — le
|
||||
# rate-limiter/logs verront l'IP du nœud plutôt que celle du client tant
|
||||
# qu'il n'y a pas de LoadBalancer (MetalLB) devant.
|
||||
#
|
||||
# type: ClusterIP — Traefik n'est plus exposé directement à internet
|
||||
# depuis l'ajout du WAF ModSecurity natif devant lui (voir
|
||||
# deploy/chart-gestion/waf-cluster, remplace coraza-http-wasm-traefik :
|
||||
# bug mémoire non résolu upstream, jcchavezs/coraza-http-wasm-traefik#9).
|
||||
# Le WAF termine le TLS public et rouvre une connexion vers l'entryPoint
|
||||
# websecure (port 8443) de ce Service, désormais interne au cluster —
|
||||
# aucun changement requis côté IngressRoute/entryPoints.
|
||||
service:
|
||||
spec:
|
||||
type: ClusterIP
|
||||
externalTrafficPolicy: Cluster
|
||||
|
||||
# Métriques Prometheus
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: gestion-waf-cluster
|
||||
description: WAF ModSecurity/OWASP CRS natif (nginx, pas WASM) devant le Traefik partagé — remplace le plugin coraza-http-wasm-traefik (bug mémoire non résolu upstream, voir jcchavezs/coraza-http-wasm-traefik#9 et traefik/traefik#11436). Même image/pattern que docker/waf (omnex-prod).
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
@@ -0,0 +1,16 @@
|
||||
{{- define "waf-cluster.fullname" -}}
|
||||
{{ .Release.Name }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "waf-cluster.labels" -}}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
{{- end -}}
|
||||
|
||||
{{- define "waf-cluster.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,147 @@
|
||||
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
|
||||
|
||||
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'"
|
||||
@@ -0,0 +1,105 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "waf-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "waf-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "waf-cluster.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "waf-cluster.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
# Force un rollout des pods quand la ConfigMap (nginx.conf,
|
||||
# custom-rules.conf) change — sinon nginx garde l'ancienne config en
|
||||
# mémoire jusqu'au prochain redémarrage manuel (les changements de
|
||||
# ConfigMap seule ne déclenchent pas de rollout par défaut).
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
# Pas de readOnlyRootFilesystem ici : l'image owasp/modsecurity-crs
|
||||
# écrit à plusieurs endroits internes à /etc/nginx/modsec (activation
|
||||
# des plugins CRS, génération de la config paranoia/anomaly) au
|
||||
# démarrage — voir les logs "Running CRS plugin activation" /
|
||||
# "Running CRS rule configuration". Même posture que docker/waf
|
||||
# (omnex-prod), qui tourne avec cette même image sans souci. À
|
||||
# durcir plus tard une fois le mapping exact des chemins écrits
|
||||
# identifié (cf. la mésaventure readOnlyRootFilesystem sur le
|
||||
# frontend, deploy/chart-gestion/frontend).
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 101
|
||||
runAsGroup: 101
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: waf
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
env:
|
||||
- name: DISABLE_MODSEC_ENV_SUBST
|
||||
value: "true"
|
||||
- name: PARANOIA
|
||||
value: "{{ .Values.waf.paranoia }}"
|
||||
- name: ANOMALY_INBOUND
|
||||
value: "{{ .Values.waf.anomalyInbound }}"
|
||||
- name: ANOMALY_OUTBOUND
|
||||
value: "{{ .Values.waf.anomalyOutbound }}"
|
||||
- name: MODSEC_AUDIT_LOG
|
||||
value: "/var/log/modsec/modsec_audit.log"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
- name: https
|
||||
containerPort: 443
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: conf
|
||||
mountPath: /etc/nginx/conf.d/app.conf
|
||||
subPath: app.conf
|
||||
- name: conf
|
||||
mountPath: /etc/nginx/modsec/custom-rules.conf
|
||||
subPath: custom-rules.conf
|
||||
- name: certs
|
||||
mountPath: /etc/nginx/certs
|
||||
readOnly: true
|
||||
- name: modsec-log
|
||||
mountPath: /var/log/modsec
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: https
|
||||
scheme: HTTPS
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: https
|
||||
scheme: HTTPS
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: conf
|
||||
configMap:
|
||||
name: {{ include "waf-cluster.fullname" . }}-conf
|
||||
- name: certs
|
||||
secret:
|
||||
secretName: {{ .Values.tls.secretName }}
|
||||
- name: modsec-log
|
||||
emptyDir: {}
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "waf-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "waf-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
# Cluster (pas Local) : même raison que Traefik (voir
|
||||
# deploy/chart-gestion/traefik/values.yaml) — bare-metal multi-nœuds, tout
|
||||
# nœud contacté doit pouvoir router vers le pod WAF où qu'il tourne.
|
||||
externalTrafficPolicy: Cluster
|
||||
selector:
|
||||
{{- include "waf-cluster.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
- name: https
|
||||
port: 443
|
||||
targetPort: https
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,45 @@
|
||||
# WAF partagé (ModSecurity natif, nginx) devant le Traefik partagé — un seul
|
||||
# déploiement pour toutes les démos, comme deploy/chart-gestion/traefik.
|
||||
# Doit être installé dans le MÊME namespace que le Traefik partagé (accès au
|
||||
# Secret TLS wildcard, pas de partage de Secret cross-namespace en k8s).
|
||||
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: owasp/modsecurity-crs
|
||||
tag: nginx-alpine
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
imagePullSecrets: []
|
||||
|
||||
# Certificat wildcard émis par cert-manager (voir deploy/cert-manager/), même
|
||||
# Secret que consomme le TLSStore de Traefik (templates/tlsstore.yaml).
|
||||
tls:
|
||||
secretName: wildcard-demo-tls
|
||||
|
||||
# Service + port internes du Traefik partagé (voir deploy/chart-gestion/traefik) :
|
||||
# ce WAF termine le TLS public puis rouvre une connexion TLS interne vers
|
||||
# l'entryPoint websecure de Traefik (aucune modification requise côté
|
||||
# IngressRoute/entryPoints — Traefik ne voit aucune différence).
|
||||
upstream:
|
||||
host: gestion-traefik.traefik.svc.cluster.local
|
||||
# Port du Service Kubernetes "gestion-traefik" (websecure), pas le port
|
||||
# interne du conteneur (8443, le Service l'abstrait derrière son propre
|
||||
# port 443 — voir kubectl -n traefik get svc gestion-traefik).
|
||||
port: 443
|
||||
|
||||
waf:
|
||||
paranoia: 2
|
||||
anomalyInbound: 5
|
||||
anomalyOutbound: 4
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
|
||||
service:
|
||||
type: LoadBalancer
|
||||
Reference in New Issue
Block a user