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 [22/07/2024 17:30] – [Vérification et mise en place] Zatalyzpratique:informatique:parefeu:nftables [25/06/2025 20:40] (Version actuelle) – [Sur hyperviseur exposé sur internet] Zatalyz
Ligne 13: Ligne 13:
 ===== nftables.conf ===== ===== nftables.conf =====
 Ce fichier ''/etc/nftables.conf'' est un peu l'équivalent du fichier  de conf de "iptable-persistant". Il faut quand même déclarer qu'il faut le charger automatiquement, mais une fois fait, il va lire les règles là lors du redémarrage du serveur.  Ce fichier ''/etc/nftables.conf'' est un peu l'équivalent du fichier  de conf de "iptable-persistant". Il faut quand même déclarer qu'il faut le charger automatiquement, mais une fois fait, il va lire les règles là lors du redémarrage du serveur. 
 +
 +==== Fichier par défaut et fonctionnement ====
  
 Fichier par défaut sur ma Debian : Fichier par défaut sur ma Debian :
Ligne 40: 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 47: Ligne 50:
 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é. 
  
-==== Autres éléments de syntaxe ====+ 
 +==== 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://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server]])) : 
 + 
 +<code>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</code> 
 + 
 +  * ''meta nfproto ipv6'' : Vérifie la famille de protocole et l'applique uniquement sur IPv6. 
 +  * ''icmpv6 type {...} accept'' : Filtre les types ICMPv6 spécifiques et les accepte. Ces types ont à la fois des "noms" (ci-dessous) et des chiffres (entre parenthèses) pour les identifier, on peut utiliser l'un ou l'autre indifférement.  
 +    * ''destination-unreachable'' (1) : hôte ou réseau inaccessible. 
 +    * ''packet-too-big'' (2) : "paquet trop grand", essentiel pour un truc appelé PMTUD (Path MTU Discovery). 
 +    * ''time-exceeded'' (3) : le réassemblage d’un paquet fragmenté échoue ou le TTL arrive à zéro, utilisé par Traceroute. 
 +    * ''parameter-problem'' (4) : erreur dans l'en-tête du paquet IPv6, évite que des paquets malformés circulent. 
 +    * ''echo-request'' (128) et ''echo-reply'' (129) : un ping entrant et sortant 
 +    * ''nd-router-solicit'' (133) : Neighbour Discovery (ND). Demande aux routeurs IPv6 présents sur le réseau de s'annoncer. ''nd-router-advert'' (134) est la réponse à la demande.  
 +    * ''nd-neighbor-solicit'' (135) : Permet de savoir quelle machine possède une adresse IPv6 donnée. ''nd-neighbor-advert '' (136) est la réponse. 
 +    * ''148, 149'' : fait référence aux types "ICMPv6 MLD Report (Multicast Listener Report)" et "ICMPv6 MLD Done (Multicast Listener Done)", le premier gérant les groupes multicast IPv6 et le second pour indiquer qu'un hôte ne veut plus écouter un groupe multicast((Je ne prétendrais pas tout comprendre)). 
 + 
 +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'avoir une mauvaise connectivité ou d'empêcher des fonctionnalités. Certains vont êtres limités (comme le ping) et d'autres simplement acceptés sans restrictions. 
 + 
 +<code>ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept</code> 
 +Cette règle protège contre certaines attaques de spoofing en s'assurant que ces messages viennent bien d’un hôte local. 
 +  * ''ip6 saddr fe80::/10'' : adresses utilisées en local (sans routeur). On s'évite des soucis en évitant de les bloquer trop. 
 +  * ''icmpv6 type { 130, 131, 132, 143, 151, 152, 153 }'' : Accepte uniquement certains types ICMPv6, liés principalement à la gestion du multicast et de la découverte du réseau. Plus précisément :  
 +    * ''130'', MLD Query : Demande aux hôtes IPv6 quels groupes multicast ils écoutent 
 +    * ''131'', MLD Report v1 : Un hôte répond pour dire qu’il écoute un groupe multicast 
 +    * ''132'',MLD Done : Un hôte indique qu’il quitte un groupe multicast 
 +    * ''143''MLD Report v2 : Version améliorée du MLD Report (avec plusieurs groupes) 
 +    * ''151'',MLD Multicast Router Advertisement : Indique la présence d’un routeur multicast 
 +    * ''152'' MLD Multicast Router Solicitation : Un routeur demande aux autres s’ils sont multicast routers 
 +    * ''153'' MLD Multicast Router Termination : Un routeur annonce qu’il ne relaie plus le multicast 
 + 
 +=== 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 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. 
 + 
 +On est sur un dédié, pas de réseau sous forme de bridge, on met ces lignes :  
 +<code># Protection contre le Smurf Attack 
 +ip daddr 255.255.255.255 drop 
 +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 (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é. 
 + 
 +<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, 224.0.0.1 } iifname != $IFACES_LAN drop</code> 
 + 
 +<WRAP center round info 100%> 
 +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> 
 + 
 +=== 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 81: 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 
- +
-Premier cas serveur "seul". Ou encore config dans une vm après un proxy etc. Cette machine est placée derrière un routeur (box, proxy...) qui sera un peu plus complet, et surtout qui empêche déjà de rentrer n'importe comment.+
 <code> <code>
-#!/usr/sbin/nft -f+table inet firewall { 
 +  chain inbound { 
 +    type filter hook input priority 0; policy drop; 
 +      jump machinssh 
 +  } 
 +  chain machinssh { 
 +    counter comment "Compteur SSH" 
 +  } 
 +
 +</code> 
 + 
 +Pourquoi faire "jump" et pas simplement tout mettre dans la même chaine ?  
 +  * 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'intervenir que sur un bout. Cela pourrait être des fichiers séparés, modifié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). 
  
-=== Machine proxy, configuration sécuritaire === +=== Ips martiennes === 
-Cette machine redirige une partie du trafic vers d'autres machines (probablement localement, mais ça peut être ailleurs) et on va donc ajouter NAT et ForwardCas typique des proxyxenproxmox, etc+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 nonCe 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
  
-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+^ 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é                          |
  
-<WRAP center round todo 60%> +^ Plage IPv6      ^ Description                         ^ 
-Faudra améliorer sur ipv6. +| '::1/128'       | Loopback                            | 
-</WRAP>+| '::/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                           |
  
 +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. 
  
-L'exemple est assez parano sur le trafic sortant et ce qui passe par l'autre machinepar 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+On commence par "ip a" pour voir les interfaces actives sur notre serveurqu'on déclarera avec "define" dans nftables
  
-<code>+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> 
 + 
 + 
 +<code bash /etc/nftables.conf>
 #!/usr/sbin/nft -f #!/usr/sbin/nft -f
  
 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 248: 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.1721662224.txt.gz · Dernière modification : 22/07/2024 17:30 de Zatalyz