Gestion des règles dans NFtables
Bien ! Maintenant que nous avons une bonne structure de table avec nos chaines, passons au plus intéressant, les règles nftables !
C'est réellement ici que nous pourrons avoir une vue fonctionnelle de l'utilisation de nftables. Commençons par voir comment ajouter des règles dans une chaine nftables, cela nous permettra d'avoir un premier aperçu de leur syntaxe.
Sommaire
I. Créer et gérer des règles dans nftables
Nous allons commencer par gérer nos règles HTTP et HTTPS, pour les autoriser en sortie et en entrée. Il faut donc agir sur nos chaines INPUT et OUTPUT puis refuser tous les autres flux.
Note : Dans un environnement de test, il sera utile d'installer un serveur web léger comme lighthttpd ou apache2 qui permet de rapidement voir si l'accès au service HTTP/HTTPS fonctionne ou non
Voici les commandes que nous aurons à saisir :
root@debian:~# nft add rule mon_filtreIPv4 input tcp dport 80 accept root@debian:~# nft add rule mon_filtreIPv4 input tcp dport 443 accept root@debian:~# nft add rule mon_filtreIPv4 input drop root@debian:~# nft add rule mon_filtreIPv4 output tcp sport 80 accept root@debian:~# nft add rule mon_filtreIPv4 output tcp sport 443 accept root@debian:~# nft add rule mon_filtreIPv4 output drop
On autorise donc les ports 80 et 443 en entrée grâce à tcp dport pour destination port qui permet de cibler le port de destination des paquets. Puis en sortie grâce à tcp sport pour source port qui permet de cibler le port source des paquets.
La directive add rule permet donc d'ajouter une règle, dans la table mon_filtreIPv4 et dans la chaine input ou output selon ce qui est précisé. On pourrait presque le traduire par "nftables, ajoute une règle dans la table mon_filtreIPv4, dans la chaine input qui dit :…". Rappelez vous que input et output sont ici les noms des chaines que nous avons nous même donné. Et non les noms des hooks. Si nous avions nommé nos chaines chain_in et chain_out, la syntaxe aurait été la suivante :
root@debian:~# nft add rule mon_filtreIPv4 chain_in dport 80 accept root@debian:~# nft add rule mon_filtreIPv4 chain_in dport 443 accept root@debian:~# nft add rule mon_filtreIPv4 chain_in drop root@debian:~# nft add rule mon_filtreIPv4 chain_out sport 80 accept root@debian:~# nft add rule mon_filtreIPv4 chain_out sport 443 accept root@debian:~# nft add rule mon_filtreIPv4 chain_out drop
On termine par une règle drop qui signifie "tomber", c’est-à-dire que les paquets seront bloqués. La position des drop a une importance. S'ils étaient positionnés en début de chaque chaine, cela ne fonctionnera pas correctement. Il faut bien penser à toujours autoriser, puis bloquer le reste en finissant par drop, cela pour chaque chaine.
A ce stade, vous pourrez vous rendre sur votre serveur web en HTTP (port 80 seulement) et en HTTPS (port 443 seulement), mais aucun autre port (TCP/22 pour du SSH par exemple).
Si l'on souhaite lister nos règles nftables pour voir où nous en sommes, la commande n'a pas changé
root@debian:~# nft list table ip mon_filtreIPv4
table ip mon_filtreIPv4 {
chain input {
type filter hook input priority filter; policy accept;
tcp dport 80 accept
tcp dport 443 accept
drop
}
chain output {
type filter hook output priority filter; policy accept;
tcp sport 80 accept
tcp sport 443 accept
drop
}
}
Nous voyons donc clairement la structure de notre table mon_filtreIPv4, de nos chaines input et output ainsi que nos règles.
II. Insérer une règle dans nftables
Nous allons maintenant essayer d'insérer les règles concernant l'acceptation du trafic SSH en entrée et sortie juste avant les lignes DROP. En effet, l'ordre des règles a une importance, il faut donc mettre les règles les plus restrictives en dernier. Nous allons commencer par essayer de voir où insérer nos règles, pour cela, il faut afficher les handles qui sont simplement les identifiants des règles. On utilisera pour cela l'option -a :
root@debian:~# nft -a list table ip mon_filtreIPv4 table ip mon_filtreIPv4 { # handle 4 chain input { # handle 1 type filter hook input priority filter; policy accept; tcp dport 80 accept # handle 4 tcp dport 443 accept # handle 5 drop # handle 6 } chain output { # handle 3 type filter hook output priority filter; policy accept; tcp sport 80 accept # handle 7 tcp sport 443 accept # handle 8 drop # handle 9 } }
Voilà qui est plutôt pratique ! On a désormais, pour chaque règle, un identifiant unique associé. Cela va nous permettre de cibler une règle précisément pour une suppression ou une insertion. Admettons que l'on veuille insérer notre ligne concernant SSH en entrée dans la chaine INPUT en dessous de la règle 5 (handle 5). Voici la ligne de commande qu'il faudra utiliser :
root@debian:~# nft add rule mon_filtreIPv4 input position 5 tcp dport 22 accept root@debian:~ #nft add rule mon_filtreIPv4 output position 8 tcp sport 22 accept
Pour expliquer cette syntaxe, l'insertion de la règle se fera juste après la position ciblée. Si je veux insérer ma règle dans la chaine INPUT après la règle qui possède le handle 5, je précise la position 5 de la chaine INPUT. Voici ce que l'on pourra voir ensuite lorsque l'on listera le contenu de notre table mon_filtreIPv4 :
root@debian:~# nft -a list table mon_filtreIPv4 table ip mon_filtreIPv4 { # handle 4 chain input { # handle 1 type filter hook input priority filter; policy accept; tcp dport 80 accept # handle 4 tcp dport 443 accept # handle 5 tcp dport 22 accept # handle 10 drop # handle 6 } chain output { # handle 3 type filter hook output priority filter; policy accept; tcp sport 80 accept # handle 7 tcp sport 443 accept # handle 8 tcp sport 22 accept # handle 11 drop # handle 9 } }
Une petite astuce, si l'on souhaite insérer une règle avant une position donnée (par exemple au-dessus de notre règle 11 dans la chaine output), on utilisera cette commande :
root@debian:~# nft insert rule mon_filtreIPv4 output position 11 tcp sport 23 accept
Ici, la seule différence à retenir est l'utilisation de la directive insert pour préciser "avant la position" et le mot add pour préciser "après la position".
III. Supprimer une règle dans une chaine nftables
Voyons maintenant comment supprimer une règle, toujours à l'aide de son identifiant (handle). Pour rappel, l'handle des règles peut se voir en ajoutant l'option -a à la commande permettant de visualiser notre table :
root@debian:~# nft -a list table ip mon_filtreIPv4
Par exemple, si je souhaite supprimer la règle ayant pour handle 22, il faut utiliser la ligne de commande suivante :
root@debian:~# nft delete rule mon_filtreIPv4 output handle 22
IV. Bannir une IP via nftables
Dernière étape pour répondre à notre objectif initial, bloquer une IP, ou une plage d'IP grâce à nftables. Nous souhaitons en effet empêcher toute communication, entrante ou sortante avec l'adresse IP 192.168.10.1. Ce sera l'occasion d'avoir un exemple de comment on peut travailler avec les IP dans nftables.
Voici comment nous pouvons bloquer une adresse IP précise avec nftables. Voici deux exemples :
root@debian:~# nft add rule mon_filtreIPv4 input ip saddr 192.168.10.1 drop root@debian:~# nft add rule mon_filtreIPv4 output ip daddr 192.168.10.1 drop
On voit donc qu'il faut préciser la chaine input ou output en fonction de celle visée puis utiliser ip suivi de saddr pour source address ou daddr pour destination address.
Note : Si vous suivez le cours depuis le début, n'oubliez pas d'insérer au bon endroit la règle que nous venons d'ajouter (indice : au-dessus du drop général de chaque chaine 😉 ). Vous devez donc passer par une suppression des deux règles que nous venons d'ajouter puis une insertion à une position précise. Tout est dans cette partie du cours, je vous laisse revenir aux bonnes section du cours si vous avez besoin de les revoir :).
Pour cibler une plage IP plutôt qu'une IP, la syntaxe CIDR (Classless Inter-Domain Routing, ce qui vous permet d'écrire /24 au lieu de 255.255.255.0.) peut être utilisée, comme suivant :
root@debian:~# nft add rule mon_filtreIPv4 input ip saddr 192.168.10.0/24 drop
Avec cette commande, nous venons de bloquer les paquets ayant comme IP source une IP de la plage 192.168.10.0/24.