Nftables

Les exemples de configuration doivent être validés par des personnes experimentées, je ne suis pas sûre de moi.

Passer de iptables à nftables

Déjà, sur toute nouvelle version de Debian, par défaut c'est nftables derrière (commande nft). Ensuite, même si on installe le paquet “iptables” en vrai c'est une surcouche à présent, qui traduira les règles de façon invisible pour l'utilisatrice. Ce qui permet de continuer à utiliser ses config iptables sans rien changer quand on n'a pas le temps, et c'est cool. Mais il faut aussi varier ;)

Installer le paquet iptables permet d'avoir accès à un outil intéressant : iptables-translate. Cette commande nous permet de savoir comment une règle iptable se traduit en terme de syntaxe pour nftables. Cela permet d'adapter les anciens tutoriels plus rapidement…

Plus d'infos ici : https://wiki.nftables.org/wiki-nftables/index.php/Moving_from_iptables_to_nftables

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.

Fichier par défaut et fonctionnement

Fichier par défaut sur ma Debian :

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input1 {
                type filter hook input priority filter;
        }
        chain forward1 {
                type filter hook forward priority filter;
        }
        chain output1 {
                type filter hook output priority filter;
        }
}

Organisation de ce fichier :

  • Il doit commencer par #!/usr/sbin/nft -f qui précise le programme à exécuter
  • On peut mettre une commande directement (pas n'importe quoi bien sûr). Généralement on commence avec flush ruleset qui purge tout vieux truc précédent.
  • table : c'est là qu'on déclare les tables, c'est à dire une catégorie pour organiser des lots de règles.
    • inet : famille d'adresses ipv4 ET ipv6. On peut aussi déclarer juste pour ipv4 avec ip et ipv6 avec ip6.
    • Ici “filter” est le nom de la table. On peut donner le nom qu'on veut à une table.
  • Les chaines sont une suite de règles à appliquer dans un contexte précis. Ici, les noms “input1, forward1 et output1” sont juste des conventions (auquel j'ai rajouté “1” pour éviter toute confusion), on peut aussi les appeler comme on veut. Là où elles agissent est défini ensuite avec type filter hook input (et là, par contre, les mots-clés sont importants et figés).
    • Les type peuvent être : filter, route, nat.
    • Les hook peuvent être : prerouting, input, forward, output, postrouting.
  • 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.

Ça c'est donc la version de base et terriblement trop permissive ; suivant les cas d'usages on va choisir diverses options.

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 comprendre1) :

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
  • 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 multicast2).

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.

ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept

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
    • 143MLD 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.

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 :

# Protection contre le Smurf Attack
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), 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) :

# Protection contre le Smurf Attack
iifname != "br0" ip daddr 255.255.255.255 drop
iifname != "br0" ip daddr 224.0.0.1 drop

Ou même autoriser explicitement ARP (adresses MAC) et DHCP :

# 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)
ip protocol udp th dport 67 accept
ip protocol udp th dport 68 accept

# Bloquer les broadcasts/multicasts seulement sur les interfaces externes
iifname != "br0" ip daddr 255.255.255.255 drop
iifname != "br0" ip daddr 224.0.0.1 drop

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.

Autres éléments de syntaxe

Je copie des “hook” pour comprendre ce que chaque petit morceau fait.

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 /usr/share/doc/nftables/examples/nat.nft:

table ip nat {
        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:1234
                # % iptables -t nat -A PREROUTING -p udp --dport 2000 -j DNAT --to-destination 2.2.2.2:2345
                # % iptables -t nat -A PREROUTING -p tcp --dport 3000 -j DNAT --to-destination 3.3.3.3:3456

                # 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 define (au début du fichier plutôt) et ensuite les appeler.

define tcp_ports = {80, 443}
table inet firewall {
        chain inbound {
                type filter hook input priority 0; policy drop;
                tcp dport { $tcp_ports } ct state new accept

Exemples de fichiers suivant les cas

Machine seule

Pour un dédié, une machine exposé directement à internet, voici la configuration de base. On va adapter un peu dans les chapitres suivants pour les fonctionnements avec hyperviseurs et machines derrière des proxy.

C'est abondament commenté pour s'y retrouver…

Ce qui suit demande à être relu et adapté suivant le contexte !

D'autant que je suis en train de bidouiller, j'ai pas encore tout “validé” et j'ai des restes de la version proxy, là :P

/etc/nftables.conf
#!/usr/sbin/nft -f
 
flush ruleset
 
# Table sur le trafic de type input/output/forward. De base on rejette tout, sauf ce qui est explicitement autorisé.
table inet firewall {
    # Liste pour bannir les IP malveillantes temporairement
    set blocklist {
        type addr
        # Ceci va ajuster le temps de bannissement suivant les récidives
        flags timeout
    }
    # Et ceci est le compteur pour les récidivistes
    set offender_count {
        type addr
        counters
    }
    # Set dynamique pour suivre les (plages) IP suspectes en temps réel
    set realtime_block {
        type addr family inet hash
        size 1024
        timeout 10s  # Timeout après 10 secondes
    }
 
    # ------------------------------
    # Règles spécifiques IPv6
    # ------------------------------
    chain input_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
        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
        # Protège contre certaines attaques de spoofing en s'assurant que ces messages viennent bien d’un hôte local.
        ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept
 
        # Vérifie si l'IP est bannie
        # On différencie ipv4 et ipv6 parce que si les règles sont les mêmes (cf plus bas), 
		# visiblement ça va aider de filtrer par type d'ip
        ip6 saddr @blocklist drop
        # Mise à jour du compteur de récidive IPv6
        # Ces temps (10m, 30m, 1h) suffisent à limiter les attaques sans trop grossir la BL
        # et ne bloquent pas un humain de façon trop violente.
        ip6 saddr @offender_count update counter
        ip6 saddr @offender_count counter > 5 add @blocklist { ip6 saddr timeout 1h }
        ip6 saddr @offender_count counter > 3 add @blocklist { ip6 saddr timeout 30m }
        ip6 saddr @offender_count counter > 1 add @blocklist { ip6 saddr timeout 10m }
 
        # Protection contre les attaques IPv6 (flood udp, syn, ack, rst, ping (on accepte)
        ip6 nexthdr udp limit rate over 200/second add @offender_count { ip6 saddr } drop
        tcp flags syn limit rate over 100/second add @offender_count { ip6 saddr } drop
        tcp flags ack limit rate over 100/second add @offender_count { ip6 saddr } drop
        tcp flags rst limit rate over 50/second add @offender_count { ip6 saddr } drop
        icmpv6 type echo-request limit rate 10/second accept
        icmpv6 type echo-request limit rate over 10/second add @offender_count { ip6 saddr } drop
    }
 
    # ------------------------------
    # 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
        ip saddr @blocklist drop
        # Mise à jour du compteur de récidive IPv4
        ip saddr @offender_count update counter
        ip saddr @offender_count counter > 5 add @blocklist { ip saddr timeout 1h }
        ip saddr @offender_count counter > 3 add @blocklist { ip saddr timeout 30m }
        ip saddr @offender_count counter > 1 add @blocklist { ip saddr timeout 10m }
 
        # 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
 
        ## Mesures anti-DDoS
        # 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).
        icmp type echo-request limit rate 10/second accept
        icmp type echo-request limit rate over 10/second add @offender_count { ip saddr } drop
 
        # Protection contre UDP Flood
        ip protocol udp limit rate over 200/second add @offender_count { ip saddr } drop
 
        # Protection contre le DNS Query Flood
        ip protocol udp th dport 53 limit rate over 50/second add @offender_count { ip saddr } drop
 
        # Protection contre le SYN Flood, ACK Flood & RST Flood
        tcp flags syn limit rate over 100/second add @offender_count { ip saddr } drop
        tcp flags ack limit rate over 100/second add @offender_count { ip saddr } drop
        tcp flags rst limit rate over 50/second add @offender_count { ip saddr } drop
 
        # Protection contre le Smurf Attack
        ip daddr 255.255.255.255 drop
        ip daddr 224.0.0.1 drop
        # Attention en cas d'utilisation d'un bridge, ça va mettre le boxon
        # Dans ce cas exclure spécifiquement d'après le nom du bridge
        #iifname != "br0" ip daddr 255.255.255.255 drop
        #iifname != "br0" ip daddr 224.0.0.1 drop
 
        # Protection contre le SMTP/Email Bombing
        ip protocol tcp th dport 25 limit rate over 10/second add @offender_count { ip saddr } drop
 
        # Protection contre les botnets sur les ports fréquemment ciblés
        # 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 @offender_count { ip saddr } drop
        ip protocol udp th dport { 11211, 1900, 389, 123, 48101 } add @offender_count { ip saddr } 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 counter add @offender_count { ip saddr } drop
        ip protocol udp limit rate over 50/second counter add @offender_count { ip saddr } drop
        # Règle de détection de scan de port via compteur (connexions multiples sur des ports distincts, ici 50 ports/seconde)
        ip protocol tcp sport != 0 limit rate over 50/second add @offender_count { ip saddr } drop
 
        # Gestion des IP malveillantes (liste noire)
        ip saddr @blocklist drop
 
        # Applique les règles en plus suivant le protocole (ici ipv6)
        meta protocol vmap { ip6 : jump input_ipv6 }
 
        # Realtime Blocking pour détecter les attaques basées sur des plages d'IP
        ip saddr @realtime_block counter add @realtime_block { ip saddr } drop
        ip saddr @realtime_block limit rate over 200/second add @realtime_block { ip saddr } drop
 
        # 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
 
        # Logging des connexions bloquées
        log prefix "[nftables] Inbound Denied: " 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
        # Redirection des connexions web vers la VM 69 (si c'est le proxy). TODO différence daddr/saddr
        ip daddr 10.10.10.69 tcp dport { http, https } accept
        ip saddr 10.10.10.69 udp dport domain accept
        ip saddr 10.10.10.69 tcp dport { http, https } accept
    }
}
 
# Table sur le trafic de type prerouting/postrouting, par défaut sur accept pour que les connexions puissent s'initialiser
table ip nat {
    chain prerout {
        type nat hook prerouting priority 0; policy accept;
        # ce qui va sur les ports web doit être redirigé vers la VM
        tcp dport { http, https } dnat to 10.10.10.69
    }
 
    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...
        ip saddr 10.10.10.69 snat to 66.66.66.66
    }
}

Machine terminale

À reprendre

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.

/etc/nftables.conf
#!/usr/sbin/nft -f
 
flush ruleset
 
table inet firewall {
        # Règles spécifiques ipv6
        chain inbound_ipv6 {
            # accept neighbour discovery otherwise connectivity breaks
            # source : https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server
            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.
}

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

Machine proxy, configuration sécuritaire

À reprendre ; mieux vaut utiliser ma première config !

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 Forward. Cas typique des proxy, xen, proxmox, etc.

Ici on va desservir l'ip interne (une VM) 10.10.10.69 (adresse à adapter suivant les machines derrière le proxy, donc). L'adresse ipv4 externe d'exemple est 66.66.66.66.

Faudra améliorer sur ipv6.

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.

/etc/nftables.conf
#!/usr/sbin/nft -f
 
flush ruleset
 
# Table sur le trafic de type input/output/forward. De base on rejette tout, sauf ce qui est explicitement autorisé.
table inet firewall {
        # Règles spécifiques ipv6
        chain input_ipv6 {
            # accept neighbour discovery otherwise connectivity breaks
            # source : https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server
            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,>
            ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept
        }
 
        # Règles génériques entrantes (valables pour ipv6 et ipv4)
        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;
            # 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 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 { http, https } accept
            ip saddr 10.10.10.69 udp dport domain accept
            ip saddr 10.10.10.69 tcp dport { http, https } accept
    }
}
# Table sur le trafic de type prerouting/postrouting, par défaut sur accept pour que les connexions puissent s'initialiser
table ip nat {
    chain prerout {
        type nat hook prerouting priority 0; policy accept;
        # ce qui va sur les ports web doit être redirigé vers la VM
        tcp dport { http, https } dnat to 10.10.10.69
    }
 
    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...
        ip saddr 10.10.10.69 snat to 66.66.66.66
    }
}

Vérification et mise en place

Pour vérifier ce fichier une fois modifié, avant de le mettre en place :

sudo nft -cof /etc/nftables.conf 

La commande va donner des informations si y'a besoin.

  • -c : vérifier s'il y a des erreurs syntaxes
  • -o : optimiser les règles
  • -f : indique le fichier à lire (ici l'emplacement par défaut sur debian).

Une fois qu'on a configuré son fichier :

sudo systemctl enable nftables.service
sudo service nftables start

Pour lister les règles en place :

sudo nft list ruleset

Sources

CC Attribution-Noncommercial-Share Alike 4.0 International Driven by DokuWiki
pratique/informatique/parefeu/nftables.txt · Dernière modification : 30/01/2025 20:17 de Zatalyz