Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| pratique:informatique:parefeu:nftables [30/05/2024 11:07] – Zatalyz | pratique:informatique:parefeu:nftables [25/06/2025 20:40] (Version actuelle) – [Sur hyperviseur exposé sur internet] Zatalyz | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| ====== Nftables ====== | ====== Nftables ====== | ||
| + | <WRAP center round important 60%> | ||
| + | Les exemples de configuration doivent être validés par des personnes experimentées, | ||
| + | </ | ||
| + | |||
| ===== Passer de iptables à nftables ===== | ===== Passer de iptables à nftables ===== | ||
| Déjà, sur toute nouvelle version de Debian, par défaut c'est nftables derrière (commande '' | Déjà, sur toute nouvelle version de Debian, par défaut c'est nftables derrière (commande '' | ||
| Ligne 9: | Ligne 13: | ||
| ===== nftables.conf ===== | ===== nftables.conf ===== | ||
| Ce fichier ''/ | Ce fichier ''/ | ||
| + | |||
| + | ==== Fichier par défaut et fonctionnement ==== | ||
| Fichier par défaut sur ma Debian : | Fichier par défaut sur ma Debian : | ||
| Ligne 31: | Ligne 37: | ||
| * On peut mettre une commande directement (pas n' | * On peut mettre une commande directement (pas n' | ||
| * '' | * '' | ||
| - | * '' | + | * '' |
| * Ici " | * Ici " | ||
| - | * Les chaines sont une suite de règles à appliquer dans un contexte précis. Ici, les noms " | + | * Les chaines sont une suite de règles à appliquer dans un contexte précis. Ici, les noms " |
| + | * Les type peuvent être : '' | ||
| + | * Les hook peuvent être : '' | ||
| + | * S'il n'y a pas la règle '' | ||
| * '' | * '' | ||
| + | * Peu importe l' | ||
| - | ==== Vérification et mise en place ==== | + | Ça c'est donc la version de base et terriblement trop permissive ; suivant les cas d' |
| + | |||
| + | Quelque soit la version, je préfère une politique où je refuse tout, en dehors de ce qui est explicitement autorisé. | ||
| + | |||
| + | |||
| + | ==== Options ==== | ||
| + | Je ne vais pas tout décrire, y'a la doc pour ça, juste ce que j'ai trouvé à utiliser et pourquoi (quand ça ne me semblait pas explicite avec un petit commentaire dans la configuration). | ||
| + | |||
| + | === IPv6 === | ||
| + | Sur la partie ipv6, j'ai ajouté la ligne suivante sans trop comprendre((Copié de [[https:// | ||
| + | |||
| + | < | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Ces paquets sont nécessaires au bon fonctionnement d'IPv6 et doivent donc être acceptés, au risque sinon de casser le réseau, d' | ||
| + | |||
| + | < | ||
| + | Cette règle protège contre certaines attaques de spoofing en s' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | === Smurf Attack === | ||
| + | C'est une attaque assez sournoise. En français " | ||
| + | |||
| + | Il y a deux cas de figures. | ||
| + | |||
| + | On est sur un dédié, pas de réseau sous forme de bridge, on met ces lignes : | ||
| + | < | ||
| + | ip daddr 255.255.255.255 drop | ||
| + | ip daddr 224.0.0.1 drop</ | ||
| + | |||
| + | Mais si on utilise un bridge réseau (cas classique quand on a un hyperviseur), | ||
| + | |||
| + | La solution basique consiste à utiliser le nom du réseau (via un '' | ||
| + | |||
| + | <code bash># Autoriser ARP (sinon les VMs se retrouvent isolées) | ||
| + | meta iifname $IFACES_LAN ether type arp accept | ||
| + | # Autoriser DHCP (indispensable avec des VMs clients DHCP) | ||
| + | meta iifname $IFACES_LAN ip protocol udp udp dport { 67, 68 } accept | ||
| + | # Bloquer le broadcast limité uniquement sur le WAN | ||
| + | ip daddr { 255.255.255.255, | ||
| + | |||
| + | <WRAP center round info 100%> | ||
| + | L' | ||
| + | |||
| + | Pour ipv6, ça a encore l'air d' | ||
| + | </ | ||
| + | |||
| + | === Différence entre saddr et daddr === | ||
| + | * saddr : " | ||
| + | * daddr : " | ||
| + | |||
| + | === Autres éléments de syntaxe === | ||
| + | <WRAP center round info 60%> | ||
| + | Je copie des " | ||
| + | </ | ||
| + | |||
| + | |||
| + | Il est possible de déclarer en une ligne plusieurs redirections du même type. Par exemple si suivant les ports tcp redirigent vers diverses ip internes (ou externes !), ça donne ça (exemple issu de ''/ | ||
| + | |||
| + | < | ||
| + | chain prerouting { | ||
| + | type nat hook prerouting priority 0; | ||
| + | #Thanks to nftables maps, if you have a previous iptables NAT (destination NAT) ruleset like this: | ||
| + | # % iptables -t nat -A PREROUTING -p tcp --dport 1000 -j DNAT --to-destination 1.1.1.1: | ||
| + | # % iptables -t nat -A PREROUTING -p udp --dport 2000 -j DNAT --to-destination 2.2.2.2: | ||
| + | # % iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 3.3.3.3: | ||
| + | |||
| + | # It can be easily translated to nftables in a single line: | ||
| + | |||
| + | dnat tcp dport map { 1000 : 1.1.1.1, 2000 : 2.2.2.2, 3000 : 3.3.3.3} : tcp dport map { 1000 : 1234, 2000 : 2345, 3000 : 3456 } | ||
| + | } | ||
| + | chain postrouting { | ||
| + | type nat hook postrouting priority 0; | ||
| + | |||
| + | #Likewise, in iptables NAT (source NAT): | ||
| + | # % iptables -t nat -A POSTROUTING -s 192.168.1.1 -j SNAT --to-source 1.1.1.1 | ||
| + | # % iptables -t nat -A POSTROUTING -s 192.168.2.2 -j SNAT --to-source 2.2.2.2 | ||
| + | # % iptables -t nat -A POSTROUTING -s 192.168.3.3 -j SNAT --to-source 3.3.3.3 | ||
| + | |||
| + | # Translated to a nftables one-liner: | ||
| + | |||
| + | snat ip saddr map { 192.168.1.1 : 1.1.1.1, 192.168.2.2 : 2.2.2.2, 192.168.3.3 : 3.3.3.3 } | ||
| + | } | ||
| + | }</ | ||
| + | |||
| + | On peut aussi définir des variables avec '' | ||
| + | < | ||
| + | table inet firewall { | ||
| + | define tcp_ports = {80, 443} | ||
| + | chain inbound { | ||
| + | type filter hook input priority 0; policy drop; | ||
| + | tcp dport { $tcp_ports } ct state new accept | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | === Modulariser : une ou plusieurs chaines/ | ||
| + | Comme expliqué en intro, on peut donner n' | ||
| + | |||
| + | * Une chaine est exécutée si elle a l' | ||
| + | * Ou si elle a été appelé depuis une autre chaine avec '' | ||
| + | |||
| + | Par exemple : | ||
| + | < | ||
| + | table inet firewall { | ||
| + | chain inbound { | ||
| + | type filter hook input priority 0; policy drop; | ||
| + | jump machinssh | ||
| + | } | ||
| + | chain machinssh { | ||
| + | counter comment " | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Pourquoi faire " | ||
| + | * Quand une règle doit être appelée plusieurs fois (par exemple pour input ET output) | ||
| + | * pour déclarer | ||
| + | * Pour clarifier les blocs et potentiellement n' | ||
| + | * Il suffit de commenter un " | ||
| + | |||
| + | Exemple d' | ||
| + | < | ||
| + | ├── 00-definitions.nft | ||
| + | ├── 10-sets.nft | ||
| + | ├── 20-input.nft | ||
| + | ├── 30-fight.nft | ||
| + | ├── 40-confperso.nft | ||
| + | └── 99-main.nft</ | ||
| + | |||
| + | Le nftables.conf ressemblera alors à ceci : | ||
| + | <code bash nftables.conf># | ||
| + | |||
| + | flush ruleset | ||
| + | |||
| + | include "/ | ||
| + | include "/ | ||
| + | include "/ | ||
| + | include "/ | ||
| + | include "/ | ||
| + | |||
| + | Cela permet alors de ne recharger/ | ||
| + | |||
| + | === Ips martiennes === | ||
| + | Quand j'ai lu dans une doc de pare-feu " | ||
| + | |||
| + | ^ Plage IPv4 ^ Description | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | |||
| + | ^ Plage IPv6 ^ Description | ||
| + | | ':: | ||
| + | | '::/ | ||
| + | | ':: | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | | ' | ||
| + | |||
| + | Maintenant, on bloque quoi et quand ? Ça me donne mal au crâne, parce que bloquer le mauvais truc peut créer des bugs bizarres. | ||
| + | |||
| + | On commence par "ip a" pour voir les interfaces actives sur notre serveur, qu'on déclarera avec " | ||
| + | |||
| + | Un exemple sur un hyperviseur xen : | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | |||
| + | |||
| + | ===== Exemples de fichiers suivant les cas ===== | ||
| + | ==== Sur hyperviseur exposé sur internet ==== | ||
| + | C'est abondamment commenté donc ça devrait permettre de s'y retrouver. | ||
| + | |||
| + | Il faut évidement relire, adapter les ip et les ports. | ||
| + | |||
| + | J'ai mis une option : si l' | ||
| + | |||
| + | <WRAP center round important 100%> | ||
| + | Ça < | ||
| + | </ | ||
| + | |||
| + | |||
| + | <code bash / | ||
| + | # | ||
| + | |||
| + | flush ruleset | ||
| + | |||
| + | # Table sur le trafic de type input/ | ||
| + | # De base on rejette tout, sauf ce qui est explicitement autorisé. | ||
| + | # Séparer ipv4 et ipv6 simplifie le travail... | ||
| + | |||
| + | table inet firewall { | ||
| + | # ------------------------------ | ||
| + | # Define : des trucs à déclarer une fois ici | ||
| + | # ------------------------------ | ||
| + | # Le nom de nos interfaces | ||
| + | define IFACES_LAN = { " | ||
| + | define IFACES_WAN = { " | ||
| + | # ------------------------------ | ||
| + | # SETS - alimenter des listes suivant des critères précis | ||
| + | # ------------------------------ | ||
| + | set allowlistsys { | ||
| + | # Les ip autorisées à faire des trucs sur le réseau | ||
| + | # Ip internes et ip fixes de sysadmin | ||
| + | type ipv4_addr | ||
| + | flags interval | ||
| + | elements = { 109.190.202.194, | ||
| + | } | ||
| + | # Blocklist : ce qui est bloqué durablement. Alimenté par Reaction/ | ||
| + | # Interval : permet de bloquer des plages d' | ||
| + | set blocklist_v4 { | ||
| + | type ipv4_addr | ||
| + | flags interval | ||
| + | } | ||
| + | set blocklist_v6 { | ||
| + | type ipv6_addr | ||
| + | flags interval | ||
| + | } | ||
| + | # blocage temporaire à court terme en cas d' | ||
| + | # Sert à " | ||
| + | set tempblock_v4 { | ||
| + | type ipv4_addr | ||
| + | flags timeout | ||
| + | timeout 10s | ||
| + | size 1024 | ||
| + | } | ||
| + | set tempblock_v6 { | ||
| + | type ipv6_addr | ||
| + | flags timeout | ||
| + | timeout 10s | ||
| + | size 1024 | ||
| + | } | ||
| + | set martienne_v4 { | ||
| + | # Adresses non-routables ou réservées, | ||
| + | type ipv4_addr | ||
| + | flags interval | ||
| + | elements = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/ | ||
| + | } | ||
| + | set martienne_v6 { | ||
| + | type ipv6_addr | ||
| + | flags interval | ||
| + | elements = { ::/128, ::1/128, :: | ||
| + | } | ||
| + | # ------------------------------ | ||
| + | # Autorisations explicites | ||
| + | # TODO : Adapter au réel ;) | ||
| + | # ------------------------------ | ||
| + | chain confperso { | ||
| + | # Autoriser SSH si : | ||
| + | # - source = Bastion1 (externe). mettre son ip, c'est pas 101.1.1.1 | ||
| + | # - OU source dans le LAN 192.168.1.0/ | ||
| + | # SSH ne sera sans doute pas sur le port 22, adapter... | ||
| + | ip saddr @allowlistsys tcp dport 22 ct state new accept | ||
| + | # Autoriser certains ports quand les services liés sont actifs, ici le web | ||
| + | tcp dport { 80, 443 } ct state new accept | ||
| + | # Proxmox : autoriser l’accès à l’interface web uniquement depuis certaines ip (fixes, perso) | ||
| + | ip saddr @allowlistsys tcp dport 8006 accept | ||
| + | tcp dport 8006 drop # Refuser tout le reste | ||
| + | } | ||
| + | |||
| + | # ------------------------------ | ||
| + | # Règles génériques entrantes | ||
| + | # ------------------------------ | ||
| + | chain input_all { | ||
| + | # Par défaut, on rejette tout à moins de suivre une des règles ci-dessous. | ||
| + | type filter hook input priority 0; policy drop; | ||
| + | |||
| + | # Vérifie si l'IP est bannie durablement | ||
| + | ip saddr @blocklist_v4 drop | ||
| + | ip6 saddr @blocklist_v6 drop | ||
| + | # Ou dans la liste temporaire | ||
| + | ip saddr @tempblock_v4 drop | ||
| + | ip6 saddr @tempblock_v6 drop | ||
| + | |||
| + | # Autoriser le trafic de paquets " | ||
| + | ct state vmap { established : accept, related : accept, invalid : drop } | ||
| + | |||
| + | # Autorise le loopback | ||
| + | iifname " | ||
| + | |||
| + | # Spécial ipv6 | ||
| + | # Paquets ICMPv6 qui ne doivent pas être rejetés, voir https:// | ||
| + | ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, | ||
| + | # Protège contre certaines attaques de spoofing en s' | ||
| + | meta iifname $IFACES_LAN ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept | ||
| + | |||
| + | # Appelle les chaines utiles | ||
| + | jump confperso | ||
| + | jump fight | ||
| + | |||
| + | } | ||
| + | |||
| + | # ------------------------------ | ||
| + | # Mesures pour limiter diverses attaques | ||
| + | # ------------------------------ | ||
| + | chain fight { | ||
| + | # Empêcher le loopback reçu ailleurs que sur lo | ||
| + | ip saddr 127.0.0.0/8 iifname != " | ||
| + | ip6 saddr ::1 iifname != " | ||
| + | # Bloquer les IP martiennes si elles ne viennent pas de LAN | ||
| + | ip saddr @martienne_v4 iifname != $IFACES_LAN drop | ||
| + | ip6 saddr @martienne_v6 iifname != $IFACES_LAN drop | ||
| + | # Attention suivant le réseau local, il faut peut-être autoriser des ip explicitement (définir un set au besoin) | ||
| + | |||
| + | |||
| + | # Autorise le ping avec une limite pour les abus / Protection contre ICMP Flood (Ping Flood) | ||
| + | # Ping normal : 1/s. Attention des outils de monitorings peuvent être plus rapides (jusque 20/s). | ||
| + | # Ping IPv4 | ||
| + | ip protocol icmp icmp type echo-request limit rate 10/second accept | ||
| + | ip protocol icmp icmp type echo-request limit rate over 10/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | # Ping IPv6 | ||
| + | ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 10/second accept | ||
| + | ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second add @tempblock_v6 { ip6 saddr } counter log prefix " | ||
| + | |||
| + | # Protection contre UDP Flood | ||
| + | ip protocol udp limit rate over 200/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | ip6 nexthdr udp limit rate over 200/second add @tempblock_v6 { ip6 saddr } counter log prefix " | ||
| + | |||
| + | # Protection contre le DNS Query Flood | ||
| + | ip protocol udp th dport 53 limit rate over 50/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | |||
| + | # Protection contre le SYN Flood, ACK Flood & RST Flood | ||
| + | # Mais on ne rejette pas tout, faut bien que les serveurs puissent se saluer | ||
| + | # Les attaques sur syn sont plus fréquentes, | ||
| + | # mais ack bénéficie de valeurs plus hautes (jusque 200) | ||
| + | # Bref à adapter au trafic réel (=> monitoring !) | ||
| + | tcp flags syn,rst limit rate over 100/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | tcp flags ack limit rate over 100/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | |||
| + | ip6 nexthdr tcp tcp flags syn,rst limit rate over 50/second add @tempblock_v6 { ip6 saddr } counter log prefix " | ||
| + | ip6 nexthdr tcp tcp flags ack limit rate over 100/second add @tempblock_v6 { ip6 saddr } counter log prefix " | ||
| + | |||
| + | # Protection contre le Smurf Attack | ||
| + | # Autoriser ARP (sinon les VMs se retrouvent isolées) | ||
| + | meta iifname $IFACES_LAN ether type arp accept | ||
| + | # Autoriser DHCP (indispensable avec des VMs clients DHCP) | ||
| + | meta iifname $IFACES_LAN ip protocol udp udp dport { 67, 68 } accept | ||
| + | # Bloquer le broadcast limité uniquement sur le WAN | ||
| + | ip daddr { 255.255.255.255, | ||
| + | |||
| + | # Protection contre le SMTP/Email Bombing | ||
| + | ip protocol tcp th dport 25 limit rate over 10/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | |||
| + | # Protection contre les botnets sur les ports fréquemment ciblés (peuvent servir de honeypot) | ||
| + | # tcp : telnet (23, 2323), UPnP (7547) | ||
| + | # udp : Memcached (11211), SSDP (1900), LDAP (389), NTP (123), IoT (48101) | ||
| + | ip protocol tcp th dport { 23, 2323, 7547 } add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | ip protocol udp th dport { 11211, 1900, 389, 123, 48101 } add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | |||
| + | # Bloquer les scans de ports en cas de tentative de connexion rapide sur des ports multiples | ||
| + | ip protocol tcp limit rate over 50/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | ip protocol udp limit rate over 50/second add @tempblock_v4 { ip saddr } counter log prefix " | ||
| + | } | ||
| + | # ------------------------------ | ||
| + | # Règles génériques sortantes | ||
| + | # ------------------------------ | ||
| + | |||
| + | chain output { | ||
| + | # Par défaut, on rejette tout à moins de suivre une des règles ci-dessous. | ||
| + | type filter hook output priority 0; policy drop; | ||
| + | # Autoriser le trafic de paquets " | ||
| + | ct state established, | ||
| + | # Autorise le loopback sortant | ||
| + | oifname " | ||
| + | # Autorise le ping sortant | ||
| + | ip protocol icmp accept | ||
| + | ip6 nexthdr icmpv6 accept | ||
| + | # Autoriser d' | ||
| + | tcp dport { http, https } accept | ||
| + | udp dport domain accept | ||
| + | tcp dport domain accept | ||
| + | # Autoriser msmtp à envoyer ses mails | ||
| + | tcp dport { 25, 465, 587 } ct state new, | ||
| + | # Autoriser NTP | ||
| + | udp dport { 53, 123 } ct state new, | ||
| + | # Log de ce qui est bloqué | ||
| + | log prefix "[NFT OUTPUT DROP] " flags all drop | ||
| + | |||
| + | } | ||
| + | |||
| + | # ------------------------------ | ||
| + | # Règles génériques " | ||
| + | # ------------------------------ | ||
| + | chain forward { | ||
| + | # Par défaut, on rejette tout à moins de suivre une des règles ci-dessous. | ||
| + | type filter hook forward priority 0; policy drop; | ||
| + | # Autoriser le trafic de paquets " | ||
| + | ct state established accept | ||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | === Ports suivant les services === | ||
| + | |||
| + | Si serveur mail : remplacer | ||
| + | # Autoriser certains ports quand les services liés sont actifs (donc à adapter), ici le web et ssh | ||
| + | tcp dport { 22, 80, 443 } ct state new accept | ||
| + | Par | ||
| + | # Autoriser certains ports quand les services liés sont actifs : web (80/443), ssh (22), | ||
| + | # smtp (25), SMTP TLS (587), IMAPS (993), Sieve (4190) | ||
| + | tcp dport { 22, 80, 443, 25, 587, 993, 4190 } ct state new accept | ||
| + | |||
| + | === Todo === | ||
| + | Faire plus modulaire. Adapter quand c'est pour une VM, un dédié... Mais la config de l' | ||
| + | |||
| + | |||
| + | ===== Vérification et mise en place ===== | ||
| Pour vérifier ce fichier une fois modifié, avant de le mettre en place : | Pour vérifier ce fichier une fois modifié, avant de le mettre en place : | ||
| Ligne 51: | Ligne 508: | ||
| + | Pour lister les règles en place : | ||
| + | sudo nft list ruleset | ||
| + | |||
| + | Pour recharger le fichier de configuration : | ||
| + | nft -f / | ||
| + | |||
| + | Admirer en temps réel les bans ? Pour admirer le contenu d'un set (par exemple tempblock_v4), | ||
| + | sudo watch -n 1 'nft list set inet firewall tempblock_v4' | ||
| + | |||
| + | Et pour les logs, si on a activé les [[pratique: | ||
| + | tail -f / | ||
| + | ===== Sources ===== | ||
| + | |||
| + | * https:// | ||
| + | * https:// | ||
| - | ===== Organiser les règles ===== | ||
| {{tag> | {{tag> | ||