mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-09 03:24:43 +02:00
feat(security): durcissement edge funklab.online (vraie IP client + rate-limit + TLS/headers) (#95)
- Traefik externalTrafficPolicy: Local → IP client réelle (fin du SNAT kube-proxy) - middleware ratelimit par IP (100/min, burst 200) sur les 6 routes publiques - middleware security-headers (HSTS, nosniff, X-Frame SAMEORIGIN, Referrer-Policy) - TLSOption globale : plancher TLS 1.2 + ciphers modernes - Guacamole REMOTE_IP_VALVE → ban anti-bruteforce par IP (fin du piège n°5) - nftables : fermeture des ports Internet legacy 9080/9081 (HTTP clair redondant) - allowCrossNamespace pour mutualiser les middlewares depuis infra - docs : section Durcissement (public-domain.md) + CAA OVH + pièges à jour Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a13b5a70cd
commit
fe0aa89ffa
13 changed files with 178 additions and 19 deletions
|
|
@ -11,6 +11,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`auth.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: authentik
|
||||
port: 9000
|
||||
|
|
|
|||
|
|
@ -65,6 +65,14 @@ spec:
|
|||
# system » (Alkatrazz). Dépannage sans Authentik : "*, openid" + re-sync.
|
||||
- name: EXTENSION_PRIORITY
|
||||
value: "openid, *"
|
||||
# Derrière Traefik : lire l'IP client réelle dans X-Forwarded-For (Traefik
|
||||
# la connaît grâce à externalTrafficPolicy: Local). Sans ça, l'anti-bruteforce
|
||||
# voit l'IP du pod Traefik → un ban bloque TOUT LE MONDE (piège n°5). Ici le
|
||||
# ban devient par IP. PROXY_ALLOWED_IPS = CIDR pods k8s (source = Traefik).
|
||||
- name: REMOTE_IP_VALVE_ENABLED
|
||||
value: "true"
|
||||
- name: PROXY_ALLOWED_IPS
|
||||
value: "10.42.0.0/16"
|
||||
- name: TZ
|
||||
value: "Europe/Paris"
|
||||
resources:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`portail.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: guacamole
|
||||
port: 8080
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`n8n.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: n8n
|
||||
port: 5678
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`openwebui.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: open-webui
|
||||
port: 8080
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`argocd.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: argocd-server
|
||||
port: 80
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ spec:
|
|||
routes:
|
||||
- match: Host(`grafana.funklab.online`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: security-headers
|
||||
namespace: infra
|
||||
- name: ratelimit
|
||||
namespace: infra
|
||||
services:
|
||||
- name: kube-prometheus-stack-grafana
|
||||
port: 80
|
||||
|
|
|
|||
42
k8s/infra/traefik/middlewares.yaml
Normal file
42
k8s/infra/traefik/middlewares.yaml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Middlewares mutualisés pour les routes publiques funklab.online.
|
||||
# Traefik est HORS ArgoCD → appliquer à la main (comme redirect.yaml) :
|
||||
# kubectl apply -f k8s/infra/traefik/middlewares.yaml
|
||||
# Référencés depuis les IngressRoutes des apps via { name: <m>, namespace: infra }
|
||||
# (nécessite providers.kubernetesCRD.allowCrossNamespace: true dans values.yaml).
|
||||
---
|
||||
# Rate-limit par IP client réelle (dépend de externalTrafficPolicy: Local sur le
|
||||
# service Traefik). Bucket à jetons : ~100 req/min soutenu, pointe (1er chargement
|
||||
# d'assets) jusqu'à 200. Anti-scan / anti-bruteforce volumétrique en bord ; la
|
||||
# protection fine du login reste côté Authentik/Guacamole. Ajustable si 429 gênants.
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: ratelimit
|
||||
namespace: infra
|
||||
spec:
|
||||
rateLimit:
|
||||
average: 100
|
||||
period: 1m
|
||||
burst: 200
|
||||
# sourceCriterion par défaut = IP distante (remoteAddr) = IP client réelle
|
||||
# grâce à externalTrafficPolicy: Local. Pas de depth XFF (aucun proxy amont
|
||||
# de confiance entre Internet et Traefik : Freebox + DNAT sont en L4).
|
||||
---
|
||||
# En-têtes de sécurité HTTP pour les apps publiques. Attaché uniquement aux routes
|
||||
# funklab.online (pas aux routes internes *.lab.local en HTTP).
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: security-headers
|
||||
namespace: infra
|
||||
spec:
|
||||
headers:
|
||||
# HSTS 1 an + sous-domaines (tout *.funklab.online est en HTTPS). Pas de preload
|
||||
# (n'engage pas l'apex sur les listes HSTS des navigateurs, réversible).
|
||||
stsSeconds: 31536000
|
||||
stsIncludeSubdomains: true
|
||||
contentTypeNosniff: true
|
||||
browserXssFilter: true
|
||||
referrerPolicy: strict-origin-when-cross-origin
|
||||
# SAMEORIGIN (pas DENY) : Grafana embarque ses propres panels en iframe.
|
||||
customFrameOptionsValue: SAMEORIGIN
|
||||
19
k8s/infra/traefik/tls-options.yaml
Normal file
19
k8s/infra/traefik/tls-options.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# TLSOption globale (nom `default` dans le namespace `default` = appliquée à toutes
|
||||
# les routes TLS qui n'en spécifient pas). Traefik est HORS ArgoCD → à la main :
|
||||
# kubectl apply -f k8s/infra/traefik/tls-options.yaml
|
||||
# Élève le plancher à TLS 1.2 et fixe des ciphers modernes (TLS 1.3 auto, non
|
||||
# configurable). Vérifier ensuite : nmap --script ssl-enum-ciphers -p 443 <host>.
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: default
|
||||
namespace: default
|
||||
spec:
|
||||
minVersion: VersionTLS12
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
|
|
@ -8,9 +8,20 @@
|
|||
service:
|
||||
type: LoadBalancer
|
||||
loadBalancerIP: 192.168.10.200 # VIP MetalLB — NE PAS changer
|
||||
# Préserve l'IP client réelle jusqu'à Traefik (sinon kube-proxy SNAT en Cluster →
|
||||
# Traefik voit l'IP d'un nœud). Requis pour le rate-limit par IP (middleware
|
||||
# ratelimit) et le X-Forwarded-For propagé aux apps (ban Guacamole par IP).
|
||||
# MetalLB L2 : la VIP n'est annoncée que depuis un nœud portant un pod Traefik prêt.
|
||||
spec:
|
||||
externalTrafficPolicy: Local
|
||||
ingressRoute:
|
||||
dashboard:
|
||||
enabled: true
|
||||
# Autorise les IngressRoutes (auth/ai/monitoring/argocd) à référencer les middlewares
|
||||
# mutualisés du namespace infra (ratelimit, security-headers). Défaut Traefik v3 = false.
|
||||
providers:
|
||||
kubernetesCRD:
|
||||
allowCrossNamespace: true
|
||||
logs:
|
||||
general:
|
||||
level: INFO
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue