Ceci est une ancienne révision du document !
Table des matières
Commencer avec Nftables
Architecture de base
Nftables fournit 5 familles de tables qui correspondent finalement aux 5 commandes du groupe iptables:
- ip se rapprochant de l'ex «iptables»,
- ip6 se rapprochant de l'ex «ip6tables»,
- inet se rapproche de rien de connu. Les tables créées dans cette famille s'appliqueront à IPv4 et IPv6 (presque) sans distinction,
- arp se rapprochant de l'ex «arptables»,
- 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:7d6fCahier des charges:
- l'hôte doit être administré à distance par ssh (port TCP 22),
- un serveur http doit y être installé, accessible également par https (ports TCP 80 et 443),
- l'interface locale (lo) doit pouvoir tout accepter, pour les éventuels sockets Inet ouverts pour des communications internes,
- 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.
- 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
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.
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».