Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
pratique:informatique:parefeu:nftables [30/01/2025 15:50] – [nftables.conf] grosse maj, mais pas finie Zatalyzpratique:informatique:parefeu:nftables [25/06/2025 20:40] (Version actuelle) – [Sur hyperviseur exposé sur internet] Zatalyz
Ligne 42: Ligne 42:
     * Les type peuvent être : ''filter'', ''route'', ''nat''.     * Les type peuvent être : ''filter'', ''route'', ''nat''.
     * Les hook peuvent être : ''prerouting'', ''input'', ''forward'', ''output'', ''postrouting''.     * Les hook peuvent être : ''prerouting'', ''input'', ''forward'', ''output'', ''postrouting''.
 +    * S'il n'y a pas la règle ''type [x] hook [y]'', la chaine ne sera pas interprétée, sauf à y faire appel dans une autre chaine (cf détail de syntaxe plus bas). 
   * ''priority filter'' : quand tu ne sais pas, tu met filter, mais y'a d'autres options. ''filter'' ça précise les règles qui vont suivrent et qui ici sont donc de filtrer... Sinon il y a des chiffres (voir la doc) pour préciser dans quel ordre tout va s'appliquer.    * ''priority filter'' : quand tu ne sais pas, tu met filter, mais y'a d'autres options. ''filter'' ça précise les règles qui vont suivrent et qui ici sont donc de filtrer... Sinon il y a des chiffres (voir la doc) pour préciser dans quel ordre tout va s'appliquer. 
   * Peu importe l'ordre des ''chain'' et des ''table''. Par contre il faut déclarer le type de filtre dans les chaines, même si d'autres type de règles sont possibles.    * Peu importe l'ordre des ''chain'' et des ''table''. Par contre il faut déclarer le type de filtre dans les chaines, même si d'autres type de règles sont possibles. 
Ligne 48: Ligne 49:
  
 Quelque soit la version, je préfère une politique où je refuse tout, en dehors de ce qui est explicitement autorisé.  Quelque soit la version, je préfère une politique où je refuse tout, en dehors de ce qui est explicitement autorisé. 
 +
  
 ==== Options ==== ==== Options ====
Ligne 82: Ligne 84:
     * ''153'' MLD Multicast Router Termination : Un routeur annonce qu’il ne relaie plus le multicast     * ''153'' MLD Multicast Router Termination : Un routeur annonce qu’il ne relaie plus le multicast
  
-== Smurf Attack == +=== Smurf Attack === 
-C'est une attaque assez sournoise. En français "Attaque par rebond" mais c'est moins drôle comme nom.+C'est une attaque assez sournoise. En français "Attaque par rebond" mais c'est moins drôle comme nom. C’est une attaque par amplification où un attaquant envoie des paquets ICMP Echo Request (ping) avec une IP source usurpée (celle de la victime) à une adresse de diffusion (broadcast), souvent 255.255.255.255 (broadcast limité) ou 224.0.0.1 (multicast “all hosts”). Tous les hôtes qui reçoivent ça répondent à l’IP usurpée, il y a saturation du réseau et DoS ciblé.
  
 Il y a deux cas de figures. Il y a deux cas de figures.
Ligne 92: Ligne 94:
 ip daddr 224.0.0.1 drop</code> ip daddr 224.0.0.1 drop</code>
  
-Mais si on utilise un bridge réseau (cas classique quand on a un hyperviseur), on risque de mettre un sacré boxon dans le réseau interne, et il faut être plus fin. La solution basique consiste à utiliser le nom du réseau et donc à utiliser la règle suivante (si le bridge est br0) :  +Mais si on utilise un bridge réseau (cas classique quand on a un hyperviseur), on risque de mettre un sacré boxon dans le réseau interne, et il faut être plus fin.
-<code># Protection contre le Smurf Attack +
-iifname != "br0" ip daddr 255.255.255.255 drop +
-iifname != "br0" ip daddr 224.0.0.1 drop</code> +
-Ou même autoriser explicitement ARP (adresses MAC) et DHCP :  +
-<code># Protection contre le Smurf Attack +
-# Laisser passer ARP (sinon les VM ne pourront pas résoudre les adresses IP en MAC) +
-arp accept+
  
-# Laisser passer DHCP (car les requêtes DHCP utilisent 255.255.255.255) +La solution basique consiste à utiliser le nom du réseau (via un ''define IFACES_LAN = { "lo", "xenbr0" }''((Si le bridge est ''xenbr0'')) en début de table en général) et à utiliser la règle suivante : on bloque tout broadcast qui ne vient pas des interfaces internes, mais on autorise explicitement ARP((Adresses MAC)) et DHCP((les requêtes DHCP des VM utilisent 255.255.255.255)) à fonctionner en interne sinon on va être coincé.
-ip protocol udp th dport 67 accept +
-ip protocol udp th dport 68 accept+
  
-Bloquer les broadcasts/multicasts seulement sur les interfaces externes +<code bash>Autoriser ARP (sinon les VMs se retrouvent isolées) 
-iifname != "br0" ip daddr 255.255.255.255 drop +meta iifname $IFACES_LAN ether type arp accept 
-iifname != "br0" ip daddr 224.0.0.1 drop</code>+# 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.255224.0.0.1 } iifname != $IFACES_LAN drop</code>
  
 <WRAP center round info 100%> <WRAP center round info 100%>
-L'adaptation des règles dépend très fortement du type de pont. Je sens que ça va me filer des boutons. N'utilisez cette règle qu'en vérifiant son effet.+L'adaptation des règles dépend très fortement du type de pont. N'utilisez cette règle qu'en vérifiant son effet
 + 
 +Pour ipv6, ça a encore l'air d'être une autre affaire. Je ne maitrise pas.
 </WRAP> </WRAP>
  
-==== Autres éléments de syntaxe ====+=== Différence entre saddr et daddr === 
 +  * saddr : "Source address" soit l'ip source, permet de filtrer en fonction de l'expéditeur. 
 +  * daddr : "Destination address" soit l'ip de destination, permet de filtrer en fonction du destinataire. 
 + 
 +=== Autres éléments de syntaxe ===
 <WRAP center round info 60%> <WRAP center round info 60%>
 Je copie des "hook" pour comprendre ce que chaque petit morceau fait. Je copie des "hook" pour comprendre ce que chaque petit morceau fait.
Ligne 147: Ligne 149:
 }</code> }</code>
  
-On peut aussi définir des variables avec ''define'' (au début du fichier plutôt) et ensuite les appeler. +On peut aussi définir des variables avec ''define'' (au début du fichier plutôt, mais dans la table) et ensuite les appeler. 
-<code>define tcp_ports = {80, 443}+<code>
 table inet firewall { table inet firewall {
-        chain inbound { +  define tcp_ports = {80, 443} 
-                type filter hook input priority 0; policy drop; +  chain inbound { 
-                tcp dport { $tcp_ports } ct state new accept+    type filter hook input priority 0; policy drop; 
 +    tcp dport { $tcp_ports } ct state new accept 
 +  } 
 +}
  
 </code> </code>
  
 +=== Modulariser : une ou plusieurs chaines/fichiers ? ===
 +Comme expliqué en intro, on peut donner n'importe quel nom à une chaine, mais il y a des conditions pour qu'elle soit exécutée. 
  
-==== Exemples de fichiers suivant les cas ====+  * Une chaine est exécutée si elle a l'élément ''type [x] hook [y]'' 
 +  * Ou si elle a été appelé depuis une autre chaine avec ''jump machaine''.
  
-=== Machine terminale ===+Par exemple :  
 +<code> 
 +table inet firewall { 
 +  chain inbound { 
 +    type filter hook input priority 0; policy drop; 
 +      jump machinssh 
 +  } 
 +  chain machinssh { 
 +    counter comment "Compteur SSH" 
 +  } 
 +
 +</code>
  
-Premier cas : serveur "seul". Ou encore config dans une vm après un proxy etcCette machine est placée derrière un routeur (boxproxy...) qui sera un peu plus complet, et surtout qui empêche déjà de rentrer n'importe comment. +Pourquoi faire "jumpet pas simplement tout mettre dans la même chaine ?  
-<code bash /etc/nftables.conf+  * Quand une règle doit être appelée plusieurs fois (par exemple pour input ET output) 
-#!/usr/sbin/nft -f+  * pour déclarer 
 +  * Pour clarifier les blocs et potentiellement n'intervenir que sur un boutCela pourrait être des fichiers séparésmodifiés par Ansible par exemple 
 +  * Il suffit de commenter un "jump" pour désactiver tout ce qui ne va pas avec ;) 
 + 
 +Exemple d'architecture avec des fichiers séparés :  
 +<code>/etc/nftables.d/ 
 +├── 00-definitions.nft 
 +├── 10-sets.nft 
 +├── 20-input.nft 
 +├── 30-fight.nft 
 +├── 40-confperso.nft 
 +└── 99-main.nft</code
 + 
 +Le nftables.conf ressemblera alors à ceci :  
 +<code bash nftables.conf>#!/usr/sbin/nft -f
  
 flush ruleset flush ruleset
  
-table inet firewall { +include "/etc/nftables.d/00-definitions.nft" 
-        # Règles spécifiques ipv6 +include "/etc/nftables.d/10-sets.nft" 
-        chain inbound_ipv6 { +include "/etc/nftables.d/20-input.nft" 
-            # accept neighbour discovery otherwise connectivity breaks +include "/etc/nftables.d/30-fight.nft
-            # source : https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server +include "/etc/nftables.d/40-confperso.nft"</code>
-            icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept +
-            # TODO comprendre ! ICMPv6 packets which must not be dropped, see https://tools.ietf.org/html/rfc4890#section-4.4.1 +
-            meta nfproto ipv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, echo-request, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept +
-            ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept +
-        } +
-  +
-        # Règles génériques entrantes +
-        chain inbound { +
-            # Par défaut, on rejette tout à moins de suivre une des règles ci-dessous. +
-            type filter hook input priority 0; policy drop; +
-            # Autoriser le trafic de paquets "etablished" et associés, supprimer les paquets non valides +
-            ct state vmap { established : accept, related : accept, invalid : drop } +
-            # Autorise le loopback +
-            iifname "lo" accept +
-            # Autorise le ping avec une limite pour les abus +
-            icmp type echo-request limit rate 5/second accept +
-            # Applique les règles en plus suivant le protocole(ici ipv6, on pourrait ajouter des trucs sur ipv4) +
-            meta protocol vmap { ip6 : jump inbound_ipv6 } +
-            # 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 +
-            # Uncomment to enable logging of denied inbound traffic +
-            # log prefix "[nftables] Inbound Denied: " counter drop +
-            # TODO ! count and drop any other traffic +
-            #counter drop +
-        } +
-        # En sortie (output) par défaut ça autorise tout et en théorie c'est ok. +
-        # forward, nat etc : pas utile dans ce cas de figure. +
-}+
  
-</code>+Cela permet alors de ne recharger/modifier qu'un seul des fichiers. Ils peuvent même être générés dynamiquement (par des scripts, Fail2ban ou Reaction). 
  
-Si serveur mail : remplacer +=== Ips martiennes === 
-  # Autoriser certains ports quand les services liés sont actifs (donc à adapter), ici le web et ssh +Quand j'ai lu dans une doc de pare-feu "pensez aussi aux plages privées et martiennes", j'ai cru à une blague. Mais on dirait que non. Ce sont des adresses réservées à certains usages et qui viennent d'interfaces précises ou alors... c'est du spoofing. Doncdans les règles nftableson vérifie si l'usage de ces ip arrivent du bon endroit et sinon on interdit. 
-  tcp dport { 2280, 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+
  
 +^ Plage IPv4           ^ Description                               ^
 +| '0.0.0.0/8'          | Adresses "This network" (source invalide) |
 +| '10.0.0.0/8'         | Adresse privées réseau interne (RFC1918)  |
 +| '100.64.0.0/10'      | Carrier-grade NAT (RFC6598), non publique |
 +| '127.0.0.0/8'        | Loopback (localhost)                      |
 +| '169.254.0.0/16'     | Link-local (APIPA)                        |
 +| '172.16.0.0/12'      | Adresse privées réseau interne (RFC1918)  |
 +| '192.0.0.0/24'       | IETF Protocol Assignments                 |
 +| '192.0.2.0/24'       | TEST-NET-1 (documentation et test)        |
 +| '192.88.99.0/24'     | 6to4 Relay Anycast                        |
 +| '192.168.0.0/16'     | Adresse privées réseau interne (RFC1918)  |
 +| '198.18.0.0/15'      | Benchmarking (RFC2544)                    |
 +| '198.51.100.0/24'    | TEST-NET-2 (documentation et test)        |
 +| '203.0.113.0/24'     | TEST-NET-3 (documentation et test)        |
 +| '224.0.0.0/4'        | Multicast                                 |
 +| '240.0.0.0/4'        | Adresses réservées pour futur usage       |
 +| '255.255.255.255/32' | Broadcast limité                          |
  
-=== Machine proxy, configuration sécuritaire === +^ Plage IPv6      ^ Description                         ^ 
-Cette machine redirige une partie du trafic vers d'autres machines (probablement localement, mais ça peut être ailleurset on va donc ajouter NAT et Forward. Cas typique des proxy, xen, proxmox, etc. +'::1/128'       | Loopback                            | 
 +| '::/128'        | Adresse non spécifiée (unspecified
 +| '::ffff:0:0/96' | IPv4-mapped IPv6 addresses          | 
 +| '64:ff9b::/96'  | IPv4/IPv6 translation (NAT64)       | 
 +| '100::/64'      | Discard prefix (RFC6666)            | 
 +| '2001::/23'     | IETF protocol assignments           | 
 +| '2001:db8::/32' | Documentation prefix                | 
 +| '2002::/16'     | 6to4 tunneling                      | 
 +| 'fc00::/7'      | Unique local addresses (ULA)        | 
 +| 'fe80::/10'     | Link-local addresses                | 
 +| 'ff00::/8'      | Multicast                           |
  
-Ici on va desservir l'ip interne (une VM) ''10.10.10.69'' (adresse à adapter suivant les machines derrière le proxydonc). L'adresse ipv4 externe d'exemple est 66.66.66.66+Maintenant, on bloque quoi et quand ? Ça me donne mal au crâneparce que bloquer le mauvais truc peut créer des bugs bizarres
  
-<WRAP center round todo 60%> +On commence par "ip a" pour voir les interfaces actives sur notre serveur, qu'on déclarera avec "define" dans nftables
-Faudra améliorer sur ipv6. +
-</WRAP>+
  
 +Un exemple sur un hyperviseur xen : 
 +  * ''lo'' (loopback) associé aux ip du type ''127.0.0.1'' / ''::1'' : cela ne doit concerner que le local.
 +  * ''enp2s0'' : l'interface physique, mais aucune ip directe ne transitera par là dans notre cas, cela sera via le bridge.
 +  * ''xenbr0'' : le bridge. Indique l'ip officielle de l'hyperviseur. 
 +  * ''vif1.0'', ''vif2.0'' : interface des VM, aucun impact en terme d'ip par rapport au nftables de l'hyperviseur.
 +
 +
 +
 +===== 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'hyperviseur est derrière une box, on peut permettre ssh en direct sur le réseau local (adresses en 192.168.1.*). Mais il ne faut pas permettre de le faire depuis les VM (10.0.0.*)... 
 +
 +<WRAP center round important 100%>
 +Ça <del>compile</del> ne génère pas d'erreur avec ''sudo nft -cof nftables.conf''. Ça ne veux pas dire que tout va marcher. J'ai pas encore assez testé certaines des règles. 
 +</WRAP>
  
-L'exemple est assez parano sur le trafic sortant et ce qui passe par l'autre machine, par défaut rien n'est permis sauf ce qui est explicite. On peut évidement être plus souple sur output/forward suivant les cas d'usage.  
  
 <code bash /etc/nftables.conf> <code bash /etc/nftables.conf>
Ligne 229: Ligne 272:
 flush ruleset flush ruleset
  
-# Table sur le trafic de type input/output/forward. De base on rejette tout, sauf ce qui est explicitement autorisé.+# Table sur le trafic de type input/output/forward.  
 +De base on rejette tout, sauf ce qui est explicitement autorisé. 
 +# Séparer ipv4 et ipv6 simplifie le travail... 
 table inet firewall { table inet firewall {
-        Règles spécifiques ipv6 +    # ------------------------------ 
-        chain input_ipv6 { +    Define des trucs à déclarer une fois ici 
-            # accept neighbour discovery otherwise connectivity breaks +    # ------------------------------ 
-            # source : https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server +    Le nom de nos interfaces 
-            icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept +    define IFACES_LAN = "lo", "xenbr0} 
-            TODO comprendre ! ICMPv6 packets which must not be dropped, see https://tools.ietf.org/html/rfc4890#section-4.4.1 +    define IFACES_WAN = { "enp2s0} 
-            meta nfproto ipv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, echo-request, nd-router-solicit,> +    # ------------------------------ 
-            ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept +    SETS - alimenter des listes suivant des critères précis 
-        } +    ------------------------------ 
-  +    set allowlistsys 
-        Règles génériques entrantes (valables pour ipv6 et ipv4) +        # Les ip autorisées à faire des trucs sur le réseau  
-        chain input_all { +        Ip internes et ip fixes de sysadmin 
-            # Par défauton rejette tout à moins de suivre une des règles ci-dessous. +        type ipv4_addr 
-            type filter hook input priority 0; policy drop; +        flags interval 
-            # Autoriser le trafic de paquets "etablishedet associés, supprimer les paquets non valides +        elements = 109.190.202.194192.168.1.0/24 }
-            ct state vmap established : accept, related : accept, invalid : drop } +
-            # Autorise le loopback +
-            iifname "loaccept +
-            Autorise le ping avec une limite pour les abus +
-            icmp type echo-request limit rate 5/second accept +
-            Applique les règles en plus suivant le protocole(ici ipv6, on pourrait ajouter des trucs sur ipv4) +
-            meta protocol vmap { ip6 : jump input_ipv6 } +
-            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 +
-            # Uncomment to enable logging of denied inbound traffic +
-            # log prefix "[nftables] Inbound Denied: " counter drop +
-            # TODO ! count and drop any other traffic +
-            #counter drop +
-        } +
-        # 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 "etablished" et associés, supprimer les paquets non valides +
-            ct state established accept +
-            # Autorise le loopback sortant +
-            oifname "lo" accept +
-            # Autorise le ping sortant +
-            ip protocol icmp accept +
-            # Autoriser d'aller sur internet et de contacter les dns (domain) +
-            tcp dport { http, https } accept +
-            udp dport domain accept +
-        } +
-        # Règles génériques "forward" (ce qui circule vers les autres adresses routées) +
-        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 "etablished" et associés, supprimer les paquets non valides +
-            ct state established accept +
-            # transfère le web ? TODO différence daddr/saddr +
-            ip daddr 10.10.10.69 tcp dport { httphttps } accept +
-            ip saddr 10.10.10.69 udp dport domain accept +
-            ip saddr 10.10.10.69 tcp dport { http, https accept+
     }     }
-} +    # Blocklist : ce qui est bloqué durablement. Alimenté par Reaction/Fail2ban. 
-Table sur le trafic de type prerouting/postrouting, par défaut sur accept pour que les connexions puissent s'initialiser +    Interval : permet de bloquer des plages d'ip. 
-table ip nat { +    set blocklist_v4 
-    chain prerout +        type ipv4_addr 
-        type nat hook prerouting priority 0; policy accept; +        flags interval
-        # ce qui va sur les ports web doit être redirigé vers la VM +
-        tcp dport { http, https } dnat to 10.10.10.69+
     }     }
 +    set blocklist_v6 {
 +        type ipv6_addr
 +        flags interval
 +    }
 +    # blocage temporaire à court terme en cas d'excès, timeout court (10s). 
 +    # Sert à "tamponner". Et à alimenter Blocklist au besoin.
 +    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, si ça ne vient pas du bon port, c'est une attaque.
 +        type ipv4_addr
 +        flags interval
 +        elements = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.88.99.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4 }
 +    }
 +    set martienne_v6 {
 +        type ipv6_addr
 +        flags interval
 +        elements = { ::/128, ::1/128, ::ffff:0:0/96, 64:ff9b::/96, 100::/64, 2001::/23, 2001:db8::/32, 2002::/16, fc00::/7, fe80::/10, ff00::/8 }
 +    }
 +    # ------------------------------
 +    # 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/24 (UNIQUEMENT quand on est derrière une box)
 +        # 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 "etablished" et associés, supprimer les paquets non valides
 +        ct state vmap { established : accept, related : accept, invalid : drop }
 +        
 +        # Autorise le loopback
 +        iifname "lo" accept
 +
 +        # Spécial ipv6
 +        # Paquets ICMPv6 qui ne doivent pas être rejetés, voir https://tools.ietf.org/html/rfc4890#section-4.4.1 et https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server
 +        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, echo-request, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept
 +        # Protège contre certaines attaques de spoofing en s'assurant que ces messages viennent bien d’un hôte local.
 +        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
  
-    chain postrout +    
-        type nat hook postrouting priority 0; policy accept; + 
-        # Ce qui vient de la VM et qui tente de se connecter au web doit sortir par l'ip de notre proxy +    # ------------------------------ 
-        # Sinon on est redirigé sur nous-même... +    # Mesures pour limiter diverses attaques 
-        ip saddr 10.10.10.69 snat to 66.66.66.66+    # ------------------------------ 
 +    chain fight 
 +        # Empêcher le loopback reçu ailleurs que sur lo 
 +        ip saddr 127.0.0.0/8 iifname != "lo" drop 
 +        ip6 saddr ::1 iifname != "lo" drop 
 +        # 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/sAttention 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 "[TEMPBLOCK PING]" drop 
 +        # 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 "[TEMPBLOCK PING6]" drop 
 + 
 +        # Protection contre UDP Flood 
 +        ip protocol udp limit rate over 200/second add @tempblock_v4 { ip saddr } counter log prefix "[TEMPBLOCK UDP]" drop 
 +        ip6 nexthdr udp limit rate over 200/second add @tempblock_v6 { ip6 saddr } counter log prefix "[TEMPBLOCK UDP6]" drop 
 +         
 +        # 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 "[TEMPBLOCK DNS]" drop 
 + 
 +        # 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, valeur entre 50 et 100, rst répond donc idem, 
 +        # 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 "[TEMPBLOCK SYN]" drop 
 +        tcp flags ack limit rate over 100/second add @tempblock_v4 { ip saddr } counter log prefix "[TEMPBLOCK ACK]" drop 
 + 
 +        ip6 nexthdr tcp tcp flags syn,rst limit rate over 50/second add @tempblock_v6 { ip6 saddr } counter log prefix "[TEMPBLOCK SYN6]" drop 
 +        ip6 nexthdr tcp tcp flags ack limit rate over 100/second add @tempblock_v6 { ip6 saddr } counter log prefix "[TEMPBLOCK ACK6]" drop 
 +         
 +        # 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, 224.0.0.1 } iifname != $IFACES_LAN drop 
 + 
 +        # 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 "[TEMPBLOCK SMTP]" drop 
 + 
 +        # 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 "[TEMPBLOCK BADPORT]" drop 
 +        ip protocol udp th dport { 11211, 1900, 389, 123, 48101 } add @tempblock_v4 { ip saddr } counter log prefix "[TEMPBLOCK BADPORT]" drop 
 + 
 +        # 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 "[TEMPBLOCK SCAN]" drop 
 +        ip protocol udp limit rate over 50/second add @tempblock_v4 { ip saddr } counter log prefix "[TEMPBLOCK SCAN]" drop 
 +    } 
 +    # ------------------------------ 
 +    # 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 "etablished" et associés, supprimer les paquets non valides 
 +        ct state established,related accept 
 +        # Autorise le loopback sortant 
 +        oifname "lo" accept 
 +        # Autorise le ping sortant 
 +        ip protocol icmp accept 
 +        ip6 nexthdr icmpv6 accept 
 +        # Autoriser d'aller sur internet et de contacter les dns (domain) 
 +        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,established accept 
 +        # Autoriser NTP 
 + udp dport { 53, 123 } ct state new,established accept 
 +        # Log de ce qui est bloqué 
 +        log prefix "[NFT OUTPUT DROP] " flags all drop 
 +        
 +    } 
 + 
 +    # ------------------------------ 
 +    # Règles génériques "forward" (ce qui circule vers les autres adresses routées) 
 +    # ------------------------------ 
 +    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 "etablished" et associés, supprimer les paquets non valides 
 +        ct state established accept
     }     }
 } }
 +
  
 </code> </code>
  
 +=== Ports suivant les services ===
  
-==== Vérification et mise en place ====+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'hyperviseur doit être une bonne base 
 + 
 + 
 +===== 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 323: Ligne 511:
   sudo nft list ruleset   sudo nft list ruleset
  
-==== Sources ====+Pour recharger le fichier de configuration :  
 +  nft -f /etc/nftables.conf 
 + 
 +Admirer en temps réel les bans ? Pour admirer le contenu d'un set (par exemple tempblock_v4), c'est  
 +  sudo watch -n 1 'nft list set inet firewall tempblock_v4' 
 + 
 +Et pour les logs, si on a activé les [[pratique:informatique:systemd_error#avoir_des_vrais_journaux_de_log|logs lisibles]] (sinon, débrouillez vous avec journalctl) : 
 +  tail -f /var/log/kern.log  
 +===== Sources =====
  
   * https://wiki.nftables.org et en particulier   * https://wiki.nftables.org et en particulier
pratique/informatique/parefeu/nftables.1738248650.txt.gz · Dernière modification : 30/01/2025 15:50 de Zatalyz