Nftables fournit 5 familles de tables qui correspondent finalement aux 5 commandes du groupe iptables:
Dans ces familles nous pouvons créer des tables et dans ces tables des chaînes.
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:
Autrement-dit, si ça a foiré, il faudra tout reprendre à zéro, d'où l'intérêt d'y aller prudemment.
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
/etc/nftables.conf
sera chargé;
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.
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:7d6fCahier des charges:
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.
Donc:
nft flush ruleset
pour faire table rase. Puis nous (re)créons une table «inet filter»:
nft add table inet filter
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.
nft add chain inet filter input_ipv4 '{type filter hook input priority 0 ; }' nft add chain inet filter input_ipv6 '{type filter hook input priority 0 ; }' nft add chain inet filter input '{type filter hook input priority 0 ; }' nft list ruleset table inet filter { chain input_ipv4 { type filter hook input priority filter; policy accept; } chain input_ipv6 { type filter hook input priority filter; policy accept; } chain input { type filter hook input priority filter; policy accept; } }Jusque là, tout va bien;
nft
a mis par défaut la «policy» “accept”.
Nous allons ajouter des filtres pour icmp (v4) pour accepter icmp-request
, mais avec une limitation sur le débit:
nft add rule inet filter input_ipv4 icmp type echo-request limit rate 5/second accept
nft list ruleset
table inet filter {
chain input_ipv4 {
type filter hook input priority filter; policy accept;
icmp type echo-request limit rate 5/second accept
}
chain input_ipv6 {
type filter hook input priority filter; policy accept;
}
chain input {
type filter hook input priority filter; policy accept;
}
}
Ici, il faut en plus autoriser les types «nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert» nécessaires à l'auto-configuration IPv6 :
nft add rule inet filter input_ipv6 icmpv6 type echo-request limit rate 5/second accept nft add rule inet filter input_ipv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept nft list ruleset table inet filter { chain input_ipv4 { type filter hook input priority filter; policy accept; icmp type echo-request limit rate 5/second accept } chain input_ipv6 { type filter hook input priority filter; policy accept; icmpv6 type echo-request limit rate 5/second accept icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept } chain input { type filter hook input priority filter; policy accept; } }
C'est ici que le destin de notre pare-feu se joue… Concernant l'interface locale:
nft add rule inet filter input iifname "lo" accept
Concernant le suivi des connexions :
nft add rule inet filter input ct state vmap { established : accept, related : accept, invalid : drop }
Mettre en œuvre les chaînes «input_ipv4» et «input_ipv6»
</pre></html> 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:
Ajout de règles dans la chaîne «input_ipv6»
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».
À 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 } }
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.