Funk-lab/ansible/roles/gateway/templates/nftables.conf.j2
ALI YESILKAYA fe0aa89ffa
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>
2026-07-07 22:58:24 +02:00

136 lines
6.1 KiB
Django/Jinja

#!/usr/sbin/nft -f
# Géré par Ansible — ne pas modifier manuellement
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Loopback
iif lo accept
# Connexions établies
ct state established,related accept
# ICMP
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# SSH depuis le LAN domestique, le LAN cluster et le tunnel WireGuard
tcp dport 22 ip saddr { 192.168.1.0/24, 192.168.10.0/24, 10.99.0.0/24 } accept
# WireGuard — handshake/transport (Freebox 51820/udp → funk-s01)
udp dport 51820 accept
# DNS + DHCP (dnsmasq) — cluster + clients VPN (dnsmasq écoute aussi sur wg0)
udp dport 53 ip saddr { 192.168.10.0/24, 10.99.0.0/24 } accept
tcp dport 53 ip saddr { 192.168.10.0/24, 10.99.0.0/24 } accept
udp dport 67 iif {{ lan_interface }} accept
# NFS
tcp dport { 111, 2049 } ip saddr 192.168.10.0/24 accept
udp dport { 111, 2049 } ip saddr 192.168.10.0/24 accept
# Services données (accès cluster uniquement)
tcp dport { 5432, 6333, 6334, 9000, 9001 } ip saddr 192.168.10.0/24 accept
# Monitoring — node_exporter (scraping par Prometheus : nœuds cluster + pods 10.42/16)
tcp dport 9100 ip saddr { 192.168.10.0/24, 10.42.0.0/16 } accept
# AlertManager webhook → Hermes monitor (pods k8s 10.42/16 + nœuds cluster)
tcp dport 9093 ip saddr { 192.168.10.0/24, 10.42.0.0/16 } accept
# Hermes gateway (accès LAN domestique + cluster + pods k8s pour alertmanager webhook)
tcp dport 8080 ip saddr { 192.168.1.0/24, 192.168.10.0/24, 10.42.0.0/16 } accept
# Hermes dashboard (poste admin uniquement)
tcp dport 9119 ip saddr {{ hermes_dashboard_allowed_ip }} accept
# LiteLLM proxy (pods k8s 10.42/16 + nœuds cluster + LAN domestique pour client vocal)
tcp dport 4000 ip saddr { 192.168.1.0/24, 192.168.10.0/24, 10.42.0.0/16 } accept
# Postfix relay SMTP (pods k8s 10.42/16 + nœuds cluster)
tcp dport 25 ip saddr { 192.168.10.0/24, 10.42.0.0/16 } accept
# Hermes auto-improve trigger server (pods k8s 10.42/16 + nœuds cluster)
tcp dport 9095 ip saddr { 192.168.10.0/24, 10.42.0.0/16 } accept
log prefix "nft-drop: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
# Forwarding LAN cluster → WAN (NAT sortant)
iif {{ lan_interface }} oif {{ wan_interface }} ct state new,established,related accept
# Forwarding LAN domestique → LAN cluster (accès admin depuis le poste perso)
iif {{ wan_interface }} oif {{ lan_interface }} ip saddr 192.168.1.0/24 ct state new,established,related accept
# Réponses WAN → cluster (connexions initiées depuis le cluster)
iif {{ wan_interface }} oif {{ lan_interface }} ct state established,related accept
# Satisfactory — trafic DNATé (192.168.1.200) → gpu-01, quelle que soit la source
# (couvre un éventuel port-forward internet depuis la box).
# 7777 = jeu/API ; 8888 = reliable messaging TCP (1.1) — bloqué = kick à ~60 s
ip daddr 192.168.10.20 tcp dport { 7777, 8888 } ct state new,established,related accept
ip daddr 192.168.10.20 udp dport 7777 ct state new,established,related accept
# NOTE : les anciens chemins Internet :9081 (Authentik direct) / :9080 (Guacamole
# direct), en HTTP clair vers les VIPs .201/.202, ont été FERMÉS au durcissement
# (2026-07-07). Tout passe désormais par funklab.online en HTTPS (ci-dessous).
# Les VIPs restent joignables en interne (LAN) ; seul l'accès Internet est retiré.
# Penser à supprimer aussi les redirections Freebox 9080/9081 (elles pointent ici
# dans le vide). Rétablir l'accès : re-DNAT ci-dessous + accept forward.
# Domaine public funklab.online — Internet DNATé (80/443) → Traefik (.200).
# Routage par sous-domaine + TLS Let's Encrypt côté Traefik. Rate-limit idem.
ip daddr 192.168.10.200 tcp dport { 80, 443 } ct state new limit rate 60/minute burst 30 packets accept
ip daddr 192.168.10.200 tcp dport { 80, 443 } ct state established,related accept
# WireGuard → lab : filtrage par pair (host_vars wireguard_peers)
{% for peer in wireguard_peers | selectattr('access', 'equalto', 'full') | list %}
# {{ peer.name }} — accès complet
iif "wg0" ip saddr {{ peer.ip }} ct state new,established,related accept
{% endfor %}
{% for peer in wireguard_peers | selectattr('access', 'equalto', 'portal') | list %}
# {{ peer.name }} — portail Guacamole uniquement (Traefik)
iif "wg0" ip saddr {{ peer.ip }} ip daddr 192.168.10.200 tcp dport 80 ct state new,established,related accept
{% endfor %}
# Retours vers le tunnel
oif "wg0" ct state established,related accept
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
# Satisfactory — DNAT WAN → serveur dédié sur gpu-01
# (joignable via 192.168.1.200 sans route vers 192.168.10.0/24)
iif {{ wan_interface }} tcp dport { 7777, 8888 } dnat to 192.168.10.20
iif {{ wan_interface }} udp dport 7777 dnat to 192.168.10.20:7777
# (Anciens DNAT Internet :9081→Authentik / :9080→Guacamole retirés au
# durcissement 2026-07-07 — tout passe par funklab.online HTTPS ci-dessous.)
# funklab.online — Freebox 80/443 → Traefik (routage par sous-domaine + TLS)
iif {{ wan_interface }} tcp dport { 80, 443 } dnat to 192.168.10.200
}
chain postrouting {
type nat hook postrouting priority 100;
# NAT masquerade pour le LAN cluster
oif {{ wan_interface }} ip saddr 192.168.10.0/24 masquerade
# Clients VPN → LAN cluster : masquerade en IP s01 (retours garantis même si
# un nœud ne route pas 10.99.0.0/24)
oif {{ lan_interface }} ip saddr 10.99.0.0/24 masquerade
}
}