Outils pour utilisateurs

Outils du site


Ceci est une ancienne révision du document !


Commencer avec Nftables

Architecture de base

Nftables fournit 5 familles de tables qui correspondent finalement aux 5 commandes du groupe iptables:

  1. ip se rapprochant de l'ex «iptables»,
  2. ip6 se rapprochant de l'ex «ip6tables»,
  3. inet se rapproche de rien de connu. Les tables créées dans cette famille s'appliqueront à IPv4 et IPv6 (presque) sans distinction,
  4. arp se rapprochant de l'ex «arptables»,
  5. bridge se rapprochant de l'ex «ebtables».

Dans ces familles nous pouvons créer des tables et dans ces tables des chaînes.

Franchir le Rubicon

Il faut maintenant activer le service nftables et ne plus jamais utiliser les outils iptables!

systemctl enable nftables.service
systemctl start nftables.service
apt purge iptables

En français:

  • activer le service nftables sur systemd,
  • démarrer ce service,
  • virer tout ce qu'avait installé le paquet Iptables.

Autrement-dit, si ça a foiré, il faudra tout reprendre à zéro, d'où l'intérêt d'y aller prudemment.

Le service «nftables» de systemd

Par curiosité, regardons ce que fait ce service. Le script se trouve dans /usr/lib/systemd/system/:

cat /usr/lib/systemd/system/nftables.service 
[Unit]
Description=nftables
Documentation=man:nft(8) http://wiki.nftables.org
Wants=network-pre.target
Before=network-pre.target shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
RemainAfterExit=yes
StandardInput=null
ProtectSystem=full
ProtectHome=true
ExecStart=/usr/sbin/nft -f /etc/nftables.conf
ExecReload=/usr/sbin/nft -f /etc/nftables.conf
ExecStop=/usr/sbin/nft flush ruleset

[Install]
WantedBy=sysinit.target

  • au démarrage (ou au re-démarrage) le fichier /etc/nftables.conf sera chargé;
  • à l'arrêt, la configuration est simplement détruite, mais pas sauvée.
  • notons que le «Reload» n'est pas un «Restart». Sans précaution particulière, tout l'ensemble des règles enregistrées pourrait être dupliqué !

Il revient donc à l'administrateur de maintenir à jour ce fichier /etc/nftables.conf et cette opération peut s'avérer compliquée, suivant le contexte.

Lors de l'installation de nftables, un fichier /etc/nftables.conf est créé par défaut et contient ceci:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority filter;
	}
	chain forward {
		type filter hook forward priority filter;
	}
	chain output {
		type filter hook output priority filter;
	}
}
Ce fichier est déjà par lui-même un script exécutable Il commence par purger l'ensemble des règles puis crée une table «filter» pouvant regrouper des chaînes de filtres IPv4 et IPv6 (inet) avec les trois chaînes de base pour le filtrage. Autrement dit, cd fichier de configuration ne fait que créer une structure de filtrage qui pour l'instant laisse tout passer.

Notons au passage que la description de la table «inet filter» est identique à la sortie de la commande «nft list ruleset».

La directive flush ruleset assure qu'en cas de redémarrage du service «nftables» tout ceci ne sera pas dupliqué.

Mais que va-t-il se passer si l'on ajoute à la volée quelques règles de filtrage ? Elles ne seront pas rapportées dans ce fichier de façon automatique et seront donc perdure sur un redémarrage du service. Il n'y a pas, comme avec «iptables» un paquet comparable à «iptables-persistent».

Pour l'instant, la solution qui semble la plus sûre consiste à modifier ce fichier /etc/nftables.conf en fonction de ses besoins puis de relancer le service.

Une configuration basique

Un serveur exposé sur le «net» :

Pour fixer les idées, l'hôte (virtuel) de test s'appelle «trixie-nft.home.nain-t.net». Il dispose de la double pile IP et la résolution DNS donne ceci:

host trixie-nft.home.nain-t.net

trixie-nft.home.nain-t.net has address 192.168.60.5
trixie-nft.home.nain-t.net has IPv6 address 2a01:e0a:875:b1d0:5054:ff:fe79:7d6f
Cahier des charges:

  1. l'hôte doit être administré à distance par ssh (port TCP 22),
  2. un serveur http doit y être installé, accessible également par https (ports TCP 80 et 443),
  3. l'interface locale (lo) doit pouvoir tout accepter, pour les éventuels sockets Inet ouverts pour des communications internes,
  4. les connexions établies ou relatives à des connexions établies doivent pouvoir entrer sur l'interface publique, de même qu'un minimum utile de signaux icmp, à l'exclusion de toute autre entrée.
  5. Tout ceci doit être vérifié pour IPv4 et IPv6.

Nous pourrions ajouter des filtres dans la chaîne «input» de la table «inet filter» puisqu'elle existe déjà, mais dans un but purement pédagogique, nous repartons de zéro.

Créer une table

Donc:

nft flush ruleset

pour faire table rase. Puis nous (re)créons une table «inet filter»:

nft add table inet filter
La documentation concernant ce type de table (inet) n'est pas si claire que ça. Faire accepter les ports 22, 80 et 443 aussi bien en IPv4 qu'en IPv6 n'est pas vraiment intuitif et il faudra faire appel à des notions avancées (formules magiques ?) présentes dans nftables.

Ceci étant dit, allons-y quand même.

Après de très nombreux essais plus que décevants concernant le filtrage simultané des ports tcp entrants en ipv4 comme en ipv6, et dont une lecture à de nombreuses reprises de la documentation qui n'a pas réussi à m'éclairer, voici un exemple qui fonctionne, inspiré d'ailleurs de la documentation officielle.

Ajoutons deux chaînes supplémentaires:

Créer une chaîne dans la table

Dans cette table, ajoutons une chaîne:

nft add chain inet filter input '{type filter hook input priority 0 ;  }'

nft list ruleset

table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
	}
}

Jusque là, tout va bien;nft a mis par défaut la «policy» “accept”.

Ajout d'une règle dans la chaîne

qui va explicitement laisser l'entrée ouverte sur les ports TCP 22, 80 et 443:

nft add rule inet filter input  tcp dport {22, 80, 443} accept

nft list ruleset

table inet filter {
	chain input {
		type filter hook input priority filter; policy accept;
		tcp dport { 22, 80, 443 } accept
	}
}
Maintenant que nous sommes capables d'utiliser ssh pour la suite, nous changeons la politique par défaut du filtre input:
 
nft chain inet filter input '{policy drop; }'

nft list ruleset

table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		tcp dport { 22, 80, 443 } accept
	}
}

Reste à traiter le cas des connexions établies et relatives:

nft add rule inet filter input ct state established, related accept

tout laisser entrer par l'interface locale:

nft add rule inet filter input iif lo accept

autoriser certains signaux icmp:

nft add rule inet filter input icmp type {echo-request, destination-unreachable, time-exceeded, parameter-problem} accept
nft add rule inet filter input icmpv6 type { echo-request, destination-unreachable, time-exceeded, nd-router-advert, nd-neighbor-advert } accept

Et vérifier le résultat:

nft list ruleset

table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		tcp dport { 22, 80, 443 } accept
		ct state established,related accept
		iifname "lo" accept
		icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, nd-router-advert, nd-neighbor-advert } accept
	}
}
Compte tenu du cahier des charges, il n'y a aucune restriction sur les sorties donc pas de chaîne «outout», ce n'est pas un routeur donc il n'y a pas non plus de chaîne «forward».

Pérenniser ces règles

À ce niveau, il est assez simple de créer un fichier /etc/nftables.conf viable:

echo  '#!/usr/sbin/nft -f' > /etc/nftables.conf
echo 'flush ruleset' >> /etc/nftables.conf
nft list ruleset >> /etc/nftables.conf

Et vérifions le résultat:

cat /etc/nftables.conf 

#!/usr/sbin/nft -f
flush ruleset
table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		tcp dport { 22, 80, 443 } accept
		ct state established,related accept
		iif "lo" accept
		icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, nd-router-advert, nd-neighbor-advert } accept
	}
}

Vérifier le travail

Après de nombreux essais, voici une solution efficiente, mais pas évidente:

cat /etc/nftables.conf

#!/usr/sbin/nft -f
flush ruleset

table inet filter {

    chain input_ipv4 {
        icmp type echo-request  limit rate 5/second accept
    }

    chain input_ipv6 {
        icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
        icmpv6 type echo-request limit rate 5/second accept
    }

    chain input {
        type filter hook input priority 0; policy drop;
        iifname lo accept
        ct state vmap { established : accept, related : accept, invalid : drop }
        meta protocol vmap { ip : jump input_ipv4, ip6 : jump input_ipv6 }
        tcp dport { 22, 80, 443} accept
    }
}
Solution extraite de la documentation officielle.

  • limit rate permet de limiter la fréquence de réception des paquets icmp «echo-request», ici à 5 paquets pas seconde. S'ils arrivent à une fréquence plus élevée, les paquets «en trop» sont jetés, ceci afin d'éviter le déni de service par «ping flood».
  • vmap pourrait être comparé à un dictionnaire, un ensemble de couples clé:valeur,
  • jump c'est un saut vers quelque chose, ici une autre chaîne, et lorsque cette autre chaîne a été entièrement parcourue, revient à la ligne qui suit le «jump».
Commencer avec Nftables: Dernière modification le: 27/06/2025 à 14:17 par prof