<p><em>Un pare-feu (de l’anglais firewall) est un logiciel et/ou un matériel permettant de faire respecter la politique de sécurité du réseau, celle-ci définissant quels sont les types de communications autorisés sur ce réseau informatique. Il surveille et contrôle les applications et les flux de données (paquets).<ahref="https://fr.wikipedia.org/wiki/Pare-feu_(informatique)">Définition Wikipédia</a></em></p>
<p><strong>Article original :</strong><ahref="https://www.debian-fr.org/t/pare-feu-ipv4-ipv6-versions-bureau-et-serveur/68665">Pare-feu IPv4/IPv6, versions bureau et serveur</a></p>
<p>Sur Debian, iptables et ip6tables (tous deux empaquetés dans le paquet iptables) vous permettront de mettre assez facilement en place un pare-feu basique pour IPv4 et IPv6.<br>
Après installation, le pare-feu est ouvert , une configuration est nécessaire.<br>
Le lancement du pare-feu, avec sa configuration, se fera au démarrage de la machine.</p>
<p><strong>IPv4/IPv6</strong> Une adresse IP sert à identifier une machine dans un réseau. Deux normes coexistent ,IPV4 et IPV6 (plus certaines spécificités) , pour une protction sur les deux fronts.</p>
<blockquote>
<p><em>iptables</em> est normalement installé par défaut sur les serveurs debian.</p>
<p>La cible LOG peut être utilisée pour enregistrer les paquets qui respectent une règle. Contrairement à d’autres cibles comme ACCEPT ou DROP, le paquet continuera à se déplacer dans la chaîne après avoir atteint une cible LOG. Cela signifie que pour permettre l’enregistrement de tous les paquets abandonnés, vous devez ajouter une règle LOG en double avant chaque règle DROP. Comme cela réduit l’efficacité et rend les choses moins simples, il est possible de créer une chaîne d’enregistrement à la place.</p>
<p>La chaîne de <codeclass="language-plaintext highlighter-rouge">logdrop</code> ci-dessus utilise le module limit pour empêcher que le log d’iptables ne devienne trop important ou ne provoque des écritures inutiles sur le disque dur. Sans limiter, un service configuré de façon erronée qui tente de se connecter, ou un attaquant, pourrait remplir le disque (ou au moins la partition /var) en provoquant des écritures dans le journal d’iptables.</p>
<p>Le module limit est appelé avec <codeclass="language-plaintext highlighter-rouge">-m limit</code>. Vous pouvez alors utiliser <codeclass="language-plaintext highlighter-rouge">--limit</code> pour définir un taux moyen et <codeclass="language-plaintext highlighter-rouge">--limit-burst</code> pour définir un taux de salves initial. Dans l’exemple de logdrop ci-dessus : <codeclass="language-plaintext highlighter-rouge">iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG</code> ajoute une règle qui enregistre tous les paquets qui passent par elle. Les 10 premiers paquets consécutifs seront enregistrés, et à partir de ce moment, seuls 5 paquets par minute seront enregistrés. Le compte de “Limit Burst” est réinitialisé chaque fois que le “taux limite” n’est pas dépassé, c’est-à-dire que l’activité de journalisation revient automatiquement à la normale.</p>
<h3id="enregistrer-tous-les-paquets-dentrée-supprimés-input-drop">Enregistrer tous les paquets d’entrée supprimés (INPUT DROP)</h3>
<p>Nous devons d’abord comprendre comment enregistrer tous les paquets d’entrée supprimés d’iptables dans syslog.</p>
<p>Si vous avez déjà tout un tas de règles de pare-feu iptables, ajoutez-les en bas, qui enregistrera tous les paquets d’entrée perdus (entrants) dans / var / log / messages</p>
<p>Dans l’exemple ci-dessus, il effectue les opérations suivantes:</p>
<ul>
<li>
<codeclass="language-plaintext highlighter-rouge">iptables -N LOGGING</code>: Créez une nouvelle chaîne appelée LOGGING</li>
<li>
<codeclass="language-plaintext highlighter-rouge">iptables -A INPUT -j LOGGING</code>: Tous les paquets entrants restants iront à la chaîne LOGGING</li>
<li>
<strong>ligne n° 3</strong>: connectez les paquets entrants à syslog (/ var / log / messages). Cette ligne est expliquée ci-dessous en détail.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">iptables -A LOGGING -j DROP</code>: Enfin, supprimez tous les paquets qui sont arrivés à la chaîne LOGGING. c’est-à-dire que maintenant il supprime vraiment les paquets entrants.</li>
</ul>
<p>Dans la ligne # 3 ci-dessus, il a les options suivantes pour enregistrer les paquets perdus:</p>
<ul>
<li>
<codeclass="language-plaintext highlighter-rouge">-m limit</code>: Ceci utilise le module de correspondance de limite. En utilisant cela, vous pouvez limiter la journalisation en utilisant l’option –limit.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">--limit 2/min</code>: indique le taux de correspondance moyen maximum pour la journalisation. Dans cet exemple, pour les paquets similaires, il limitera la journalisation à 2 par minute. Vous pouvez également spécifier 2 / seconde, 2 / minute, 2 / heure, 2 / jour. Cela est utile lorsque vous ne voulez pas encombrer vos messages de journal avec des messages répétés des mêmes paquets abandonnés.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">-j LOG</code>: cela indique que la cible de ce paquet est LOG. c’est-à-dire écrire dans le fichier journal.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">--log-prefix «IPTables-Dropped:»</code> Vous pouvez spécifier n’importe quel préfixe de journal, qui sera ajouté aux messages de journal qui seront écrits dans le fichier / var / log / messages</li>
<li>
<codeclass="language-plaintext highlighter-rouge">–-log-level 4</code> Il s’agit des niveaux syslog standard. 4 est un avertissement. Vous pouvez utiliser un nombre compris entre 0 et 7. 0 correspond à l’urgence et 7 au débogage.</li>
</ul>
<h3id="consigner-tous-les-paquets-sortants-supprimés-output-drop">Consigner tous les paquets sortants supprimés (OUTPUT DROP)</h3>
<p>C’est la même chose que ci-dessus, mais la 2e ligne ci-dessous a OUTPUT au lieu de INPUT.</p>
<h3id="enregistrer-tous-les-paquets-supprimés-entrants-et-sortants-input-output-drop">Enregistrer tous les paquets supprimés (entrants et sortants INPUT OUTPUT DROP)</h3>
<p>C’est la même chose qu’avant, mais nous allons prendre la ligne numéro 2 des deux exemples précédents et l’ajouter ici. c’est-à-dire que nous aurons une ligne séparée pour INPUT et OUTPUT qui passera à la chaîne LOGGING.</p>
<p>Pour consigner les paquets perdus entrants et sortants, ajoutez les lignes suivantes au bas de vos règles de pare-feu iptables existantes.</p>
<p>De plus, comme nous l’avons expliqué précédemment, par défaut, les iptables utiliseront /var/log/messages pour enregistrer tout le message. Si vous souhaitez le modifier dans votre propre fichier journal personnalisé, ajoutez la ligne suivante à /etc/syslog.conf</p>
<h3id="comment-lire-le-journal-iptables">Comment lire le journal IPTables</h3>
<p>Ce qui suit est un échantillon des lignes qui ont été enregistrées dans /var/log/messages lors de la suppression d’un paquet entrant et sortant.</p>
<strong>IPTables-Dropped</strong>: il s’agit du préfixe que nous avons utilisé dans notre journalisation en spécifiant l’option -log-prefix</li>
<li>
<strong>IN = em1</strong> Ceci indique l’interface qui a été utilisée pour ces paquets entrants. Ce sera vide pour les paquets sortants</li>
<li>
<strong>OUT = em1</strong> Ceci indique l’interface qui a été utilisée pour les paquets sortants. Ce sera vide pour les paquets entrants.</li>
<li>
<strong>SRC =</strong> l’adresse IP source d’où provient le paquet</li>
<li>
<strong>DST =</strong> l’adresse IP de destination à laquelle les paquets ont été envoyés</li>
<li>
<strong>LEN =</strong> Longueur du paquet</li>
<li>
<strong>PROTO =</strong> Indique le protocole (comme vous le voyez ci-dessus, la 1ère ligne est pour le protocole ICMP sortant, la 2ème ligne est pour le protocole TCP entrant)</li>
<li>
<strong>SPT =</strong> Indique le port source</li>
<li>
<strong>DPT =</strong> Indique le port de destination. Dans la 2ème ligne ci-dessus, le port de destination est 443. Cela indique que les paquets HTTPS entrants ont été abandonnés</li>
</ul>
<p><strong>Visualisation des paquets enregistrés (journalctl)</strong><br>
Les paquets enregistrés sont visibles sous forme de messages du noyau dans le journal systemd.<br>
Pour voir tous les paquets qui ont été enregistrés depuis le dernier démarrage de la machine :</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>journalctl -k | grep "IN=.*OUT=.*" | less
</code></pre></div></div>
<h2id="tutoriel---configurer-un-pare-feu-avec-iptables">Tutoriel - Configurer un pare-feu avec Iptables</h2>
<p><strong>COPIE de l’article publié par <ahref="https://www.microlinux.fr/author/kikinovak/">kikinovak</a> le 1 février 2019</strong></p>
<p>Cet article décrit pas à pas la configuration d’un pare-feu sur un système Linux. Il s’agit là d’une introduction détaillée sous forme d’atelier pratique, et qui s’adresse aux administrateurs en herbe aussi bien qu’aux experts qui souhaitent réviser leurs bases. Tous les exemples de cette présentation ont été mis en pratique sur une machine tournant sous CentOS 7, et j’ai fait de mon mieux pour m’affranchir des spécificités de cette distribution.</p>
<h3id="généralités">Généralités</h3>
<p>Le terme de « pare-feu » (ou firewall) peut désigner plusieurs choses.</p>
<ul>
<li>Tout type de matériel qui agit comme une passerelle entre Internet et le réseau local.</li>
<li>Une application installée sur la machine et censée améliorer la sécurité.</li>
</ul>
<p>En ce qui nous concerne, il s’agira très précisément d’un filtre de paquets pour la sécurisation du trafic TCP/IP. Ce filtre devra analyser tous les paquets réseau qui entrent dans la machine et qui la quittent. Une série de tests décidera si les paquets ont le droit de passer ou s’ils doivent être bloqués.</p>
<h3id="netfilter">Netfilter</h3>
<p>Le système de gestion de paquets réseau du noyau Linux s’appelle Netfilter. La commande utilisée pour le configurer est iptables.</p>
<p>Voici un schéma simplifié du cheminement d’un paquet TCP/IP dans le kernel.</p>
<li>Traditionnellement, les schémas de pare-feu montrent l’Internet « dangereux » à gauche, puis le pare-feu, et enfin à droite le réseau local « sécurisé ». Ce n’est pas le cas dans ce schéma, où les paquets entrant dans la machine depuis la gauche peuvent provenir aussi bien d’Internet que du réseau local. Il en est de même pour les paquets qui sortent du pare-feu à droite.</li>
<li>
<em>Routing</em> : En fonction de l’adresse IP et du numéro de port du paquet, le kernel décide si le paquet doit être traité localement ou s’il doit être transmis vers une interface réseau et donc vers une autre machine du réseau local ou même de l’Internet.</li>
<li>
<em>Filter Input</em> : Une série de tests basés sur un certain nombre de règles décident si le paquet est accepté pour être traité par des applications locales ou non.</li>
<li>
<em>Local Process</em> : Il s’agit là tout simplement de l’ensemble des applications qui traitent – ou qui produisent – des paquets IP sur la machine locale, c’est-à-dire tous les services réseau : sshd, httpd, etc.</li>
<li>
<em>Filter Output</em> : Une autre série de tests basés sur une autre série de règles établit si le paquet a le droit de quitter le kernel.</li>
<li>
<em>Filter Forward</em> : Ce filtre effectue des tests sur les paquets qui sont transmis sans être traités et décide s’ils ont le droit de continuer leur chemin.</li>
<li>
<em>NAT Postrouting</em> : Au cas où la machine locale assure la connexion Internet pour d’autres machines grâce au relais de paquets (Masquerading), cette étape gère la manipulation nécessaire des paquets.</li>
<li>Le filtre de paquets gèrera les étapes <em>Filter Input, Filter Output, Filter Forward</em> et, le cas échéant, <em>NAT Postrouting</em>.</li>
<li>Les parties <em>Routing</em> et <em>Local Process</em> du schéma concernent les fonctions réseau du kernel ou des services réseau communs et n’ont rien à voir avec le filtre de paquets.</li>
<p>C’est le kernel qui gère la transmission des paquets provenant d’une interface réseau ou générés par une application locale. À chacune des étapes du système de filtrage, il a respectivement trois alternatives.</p>
<ul>
<li>
<strong>DENY</strong> : la transmission du paquet est tout bonnement refusée, sans message d’erreur. Le paquet tombe à la trappe, dans le nirvana numérique. Il n’existe plus.</li>
<li>
<strong>REJECT</strong> : la transmission du paquet est refusée, avec un message d’erreur. Les conséquences pour le paquet sont les mêmes que pour un DENY. La différence, c’est que le destinataire est informé par un paquet ICMP (Internet Control Message Protocol) du fait que son paquet a été refusé.</li>
<li>
<strong>ACCEPT</strong> : le paquet est transmis.</li>
</ul>
<h3id="les-tables">Les tables</h3>
<p>L’idée de base d’un système Netfilter, c’est qu’un paquet IP traverse différents endroits dans le kernel, qui testent à partir d’une série de règles si le paquet est autorisé ou non. Si c’est le cas, le paquet est transmis. Si ce n’est pas le cas, le paquet est supprimé ou renvoyé au destinataire. Trois tables contrôlent le filtre Netfilter.</p>
<ul>
<li>La table <strong>filter</strong> : cette table contient généralement l’ensemble des règles pour le filtre de paquets à proprement parler.</li>
<li>La table <strong>nat</strong> : cette table est active uniquement si la fonction de relais des paquets du kernel (IP Masquerading) a été activée. Elle permet de modifier l’adresse des paquets qui entrent dans le kernel depuis l’extérieur ou alors qui en sortent à nouveau (Network Address Translation).</li>
<li>La table <strong>mangle</strong> : elle permet de procéder à diverses manipulations des paquets IP. Cette table est réservée à une série d’opérations très spécifiques, et nous ne la traiterons pas ici.</li>
</ul>
<h3id="les-chaînes">Les chaînes</h3>
<p>Chacune de ces trois tables prévoit à son tour une série de chaînes de règles.</p>
<ul>
<li>Table <strong>filter</strong> : INPUT, FORWARD et OUTPUT</li>
<li>Table <strong>nat</strong> : PREROUTING, INPUT, OUTPUT et POSTROUTING</li>
<li>Table <strong>mangle</strong> : PREROUTING, INPUT, FORWARD, OUTPUT et POSTROUTING</li>
</ul>
<p>Ces chaînes de règles sont indépendantes les unes des autres. Il existe donc bien trois chaînes INPUT, deux chaînes FORWARD, deux chaînes PREROUTING, deux chaînes POSTROUTING et trois chaînes OUTPUT.</p>
<p>Lorsqu’une documentation se réfère à « la chaîne OUTPUT » sans plus de précisions de la table à laquelle appartient la chaîne, il s’agit dans tous les cas de la table filter, qui est de loin la plus importante.</p>
<p>La même chose vaut d’ailleurs pour la commande <codeclass="language-plaintext highlighter-rouge">iptables</code>. L’option -t permet d’indiquer la table pour laquelle on souhaite définir des règles. Si l’on omet cette option, c’est automatiquement la table filter qui est sélectionnée.</p>
<h3id="fonctionnement-de-base">Fonctionnement de base</h3>
<p>Lorsqu’un paquet IP rencontre une chaîne de règles dans son cheminement à travers le kernel, celui-ci vérifie les règles en question l’une après l’autre.</p>
<ul>
<li>Dès qu’une règle s’applique à un paquet, l’action prévue dans la règle est effectuée : transmettre le paquet, le supprimer ou le renvoyer au destinataire.</li>
<li>Lorsqu’aucune des règles ne peut s’appliquer pour le paquet, c’est la politique par défaut qui entre en vigueur. Là encore, on peut se retrouver avec les trois cas de figure : transmettre, supprimer, rejeter.</li>
</ul>
<p>La configuration d’un pare-feu consiste donc à définir la politique par défaut ainsi qu’une série de règles pour chacune des chaînes de filtres essentielles.</p>
<h3id="avant-de-mettre-la-main-à-la-pâte">Avant de mettre la main à la pâte</h3>
<p>Tous les exemples qui suivent ont été mis en pratique sur une machine tournant sous CentOS 7. Depuis la version 7, CentOS utilise <codeclass="language-plaintext highlighter-rouge">firewalld</code>, une couche d’abstraction supplémentaire à la sauce Red Hat, dont on peut se demander à quoi elle peut bien servir, vu qu’elle utilise <codeclass="language-plaintext highlighter-rouge">iptables</code> sous le capot. Quoi qu’il en soit, pour éviter que <codeclass="language-plaintext highlighter-rouge">firewalld</code> ne nous tire dans les pattes, nous allons désactiver le service et supprimer le paquet correspondant.</p>
<p>Veillez à ce que le paquet <em>iptables-services</em> ne soit pas présent sur le système. Il s’agit là d’une autre idiosyncrasie de Red Hat, que nous utiliserons par la suite pour une configuration persistante. Pour l’instant, ne l’installez pas.</p>
<p>Enfin, je me suis servi de la <strong>machine physique</strong><amandine.microlinux.lan> dans mon réseau pour tous mes tests. Avec une machine virtuelle, on risque tôt ou tard de se tirer dans le pied lorsqu’on s’amuse à fermer toutes les écoutilles et qu’elle devient dure de la feuille à tel point qu’il faut l’éteindre à coups de pieds. Pour simplifier les choses, j’ai également désactivé le protocole IPv6 sur cette machine.</amandine.microlinux.lan></p>
<h3id="afficher-létat-du-pare-feu">Afficher l’état du pare-feu</h3>
<p>L’option <codeclass="language-plaintext highlighter-rouge">-L</code> (ou <codeclass="language-plaintext highlighter-rouge">--list</code>) permet d’afficher l’état du pare-feu. Sans autre option, elle affiche les règles de la table filter.</p>
<p>L’option <codeclass="language-plaintext highlighter-rouge">-t</code> (ou <codeclass="language-plaintext highlighter-rouge">--table</code>) permet de sélectionner la table. Par défaut, c’est la table filter qui est affichée. La commande précédente est donc identique à celle-ci.</p>
pkts bytes target prot opt in out source destination
</code></pre></div></div>
<ul>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-v</code> (ou <codeclass="language-plaintext highlighter-rouge">--verbose</code>) permet d’afficher plus de détails.</li>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-n</code> (ou <codeclass="language-plaintext highlighter-rouge">--numeric</code>) peut s’avérer pratique dans la mesure où elle permet un formatage numérique de l’affichage pour les adresses IP et les ports.</li>
<li>Dans certains cas, on ajoutera l’option <codeclass="language-plaintext highlighter-rouge">--line-numbers</code> pour ajouter des numéros de ligne au début de chaque règle, ce qui permet d’identifier sa position dans la chaîne.</li>
</ul>
<p>Pour afficher la table <strong>nat</strong> avec des numéros de ligne, on invoquera donc la commande suivante.</p>
<h3id="définition-manuelle-des-premières-règles">Définition manuelle des premières règles</h3>
<p>L’option <codeclass="language-plaintext highlighter-rouge">-P</code> (ou <codeclass="language-plaintext highlighter-rouge">--policy</code>) permet de définir la politique par défaut. Pour commencer, nous allons bloquer les connexions entrantes.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>$ sudo iptables -P INPUT DROP
</code></pre></div></div>
<p>Notre machine devient injoignable depuis l’extérieur.</p>
<p>Non content de cela, elle devient également injoignable pour elle-même. Et si jamais vous avez effectué vos tests sur une machine virtuelle en faisant fi de ma mise en garde initiale, c’est là le moment précis où vous vous êtes tiré dans le pied.</p>
<p>On va donc autoriser les paquets entrants sur la boucle locale.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>$ sudo iptables -A INPUT -i lo -j ACCEPT
</code></pre></div></div>
<ul>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-A</code> (ou <codeclass="language-plaintext highlighter-rouge">--append</code>) permet d’ajouter une règle à la fin de la chaîne sélectionnée.</li>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-i</code> (ou <codeclass="language-plaintext highlighter-rouge">--in-interface</code>) permet de spécifier l’interface réseau par laquelle un paquet a été reçu.</li>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-j</code> (ou <codeclass="language-plaintext highlighter-rouge">--jump</code>) spécifie la cible de règle, autrement dit, elle indique ce qu’il faut faire si le paquet correspond à la règle.</li>
<p>On peut décider d’autoriser les pings en provenance de l’extérieur. Pour ce faire, on pourrait par exemple autoriser le protocole ICMP en utilisant l’option <codeclass="language-plaintext highlighter-rouge">-p</code> (comme <codeclass="language-plaintext highlighter-rouge">--protocol</code>).</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>$ sudo iptables -A INPUT -p icmp -j ACCEPT
</code></pre></div></div>
<p>Nous sommes peut-être allés un peu trop loin dans la définition de la règle précédente. En effet, le protocole ICMP comprend toute une série de types de paquets. La commande suivante permet de les afficher.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>$ sudo iptables -p icmp -h | less
...
Valid ICMP Types:
any
echo-reply (pong)
destination-unreachable
network-unreachable
host-unreachable
protocol-unreachable
port-unreachable
fragmentation-needed
source-route-failed
network-unknown
host-unknown
network-prohibited
host-prohibited
TOS-network-unreachable
TOS-host-unreachable
communication-prohibited
host-precedence-violation
precedence-cutoff
source-quench
redirect
network-redirect
host-redirect
TOS-network-redirect
TOS-host-redirect
echo-request (ping)
router-advertisement
router-solicitation
time-exceeded (ttl-exceeded)
ttl-zero-during-transit
ttl-zero-during-reassembly
parameter-problem
ip-header-bad
required-option-missing
timestamp-request
timestamp-reply
address-mask-request
address-mask-reply
</code></pre></div></div>
<p>Au lieu d’accepter tout ce fatras « à la louche », nous allons uniquement autoriser ce qu’il faut pour que la machine soit « pingable ». Avant d’aller plus loin, je vais d’abord supprimer la règle que je viens de définir.</p>
<p>Dans un premier temps, j’affiche les règles avec l’option <codeclass="language-plaintext highlighter-rouge">--line-numbers</code>.</p>
<p>Ensuite, je supprime la règle n° 2 de la chaine INPUT en utilisant l’option <codeclass="language-plaintext highlighter-rouge">-D</code> (comme <codeclass="language-plaintext highlighter-rouge">--delete</code>).</p>
<h3id="retour-à-la-case-départ">Retour à la case départ</h3>
<p>Avant d’aller plus loin dans la définition des règles de filtrage, nous allons voir comment arrêter le pare-feu. À l’état brut tel que nous l’utilisons, iptables n’est pas un démon qu’on peut démarrer et arrêter. C’est donc un peu plus compliqué d’arrêter le filtrage des paquets dans l’état actuel des choses.</p>
<p>Comme nous l’avons vu un peu plus haut, l’option <codeclass="language-plaintext highlighter-rouge">-P</code> (ou <codeclass="language-plaintext highlighter-rouge">--policy</code>) se charge de définir la politique par défaut. Puisque nous souhaitons arrêter le pare-feu, cela équivaut à définir partout une politique par défaut <strong>ACCEPT</strong>.</p>
<p>Sur toutes les chaînes de la table <strong>filter</strong> :</p>
<p>Ensuite, il faut remettre à zéro tous les compteurs de paquets et d’octets dans toutes les chaînes. Pour ce faire, on utilise l’option <codeclass="language-plaintext highlighter-rouge">-Z</code> (ou <codeclass="language-plaintext highlighter-rouge">--zero</code>).</p>
<p>Il ne reste plus qu’à supprimer toutes les règles et toutes les chaînes.</p>
<ul>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-F</code> (ou <codeclass="language-plaintext highlighter-rouge">--flush</code>) se charge de supprimer les chaînes d’une table.</li>
<li>L’option <codeclass="language-plaintext highlighter-rouge">-X</code> (ou <codeclass="language-plaintext highlighter-rouge">--delete-chain</code>) supprime les chaînes personnalisées définies par l’utilisateur.</li>
</ul>
<p>Pour supprimer tous les jeux de règles sur toutes les tables, on invoquera donc la série de commandes suivante.</p>
<h3id="scripter-les-règles-de-filtrage">Scripter les règles de filtrage</h3>
<p>Vous trouvez sans doute que toutes ces règles de filtrage sont fastidieuses à taper. Pour cette raison, nous allons ranger tout cela soigneusement dans un script avant d’aller plus loin.</p>
<p>Éditez un script <strong>firewall.sh</strong> (avec les droits de <strong>root</strong>, bien sûr), rangez-le dans un endroit approprié comme <em>/usr/local/sbin</em> et définissez les permissions qui vont bien (rwx——).</p>
<li>Dans un premier temps, le script prend soin de supprimer toutes les règles existantes.</li>
<li>Notez que la politique par défaut consiste à rejeter (<strong>DROP</strong>) les paquets entrants (<strong>INPUT</strong>) et relayés (<strong>FORWARD</strong>) et à accepter (<strong>ACCEPT</strong>) les paquets sortants.</li>
<li>Pour l’instant, la machine ne peut pas faire grand-chose, si ce n’est se connecter à elle-même et accepter le <codeclass="language-plaintext highlighter-rouge">ping</code> depuis l’extérieur.</li>
<p>Vérifiez depuis une machine extérieure si la machine se comporte bien comme prévu. Normalement, vous devez pouvoir envoyer un <codeclass="language-plaintext highlighter-rouge">ping</code>. En revanche, il ne vous sera pas possible de vous connecter via SSH.</p>
<p>À présent, redémarrez la machine et affichez à nouveau les règles du pare-feu. Vous constatez qu’elles ne sont plus en vigueur.</p>
<h3id="configurer-un-pare-feu-persistant">Configurer un pare-feu persistant</h3>
<p>La prochaine étape consistera à rendre les règles de filtrage persistantes. Le moyen le plus simple et le plus sûr consiste ici à utiliser le paquet <strong>iptables-services</strong>, qui est spécifique aux distributions de la famille Red Hat.</p>
<p>À présent, si vous affichez les règles du pare-feu (<codeclass="language-plaintext highlighter-rouge">sudo iptables -L -vn</code>), vous serez sans doute surpris de voir apparaître un jeu de règles inédit, et vous vous demanderez probablement d’où il peut bien sortir.</p>
<p>En effet, le paquet iptables-services installe son propre jeu de règles par défaut, défini dans le fichier <strong>/etc/sysconfig/iptables</strong>, et dont la syntaxe rappelle vaguement ce que nous avons vu un peu plus haut.</p>
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
</code></pre></div></div>
<p>Pour remplacer ce nouveau jeu de règles de filtrage par notre propre panoplie de règles, il suffit de relancer le script que nous avons édité tout à l’heure.</p>
<p>Pour enregistrer nos règles personnalisées, utilisez la commande suivante.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>$ sudo service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [OK]
</code></pre></div></div>
<p>Éventuellement, jetez un oeil dans <strong>/etc/sysconfig/iptables</strong>. Vous y reconnaîtrez notre jeu de règles traduit dans la syntaxe propre à Red Hat. Cette fois-ci, la configuration du pare-feu persiste même après un redémarrage de la machine.</p>
<h3id="ajouter-quelques-règles-de-base">Ajouter quelques règles de base</h3>
<p>Notre pare-feu est désormais plus confortable à manier. Nous n’avons plus à taper une myriade de commandes pour le démarrer ou pour l’arrêter, et la configuration persiste après un redémarrage. Partant de là, nous allons ajouter une poignée de règles de filtrage pour disposer d’un pare-feu opérationnel.</p>
<p>La règle suivante autorise les paquets provenant de connexions déjà établies.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
</code></pre></div></div>
<p>Ensuite, nous allons ouvrir le port 22 pour pouvoir nous connecter en SSH. Notez qu’ici nous précisons non seulement le protocole TCP avec l’option <codeclass="language-plaintext highlighter-rouge">-p</code> (comme <codeclass="language-plaintext highlighter-rouge">--protocol</code>), mais aussi l’interface réseau <strong>enp2s0</strong> avec l’option <codeclass="language-plaintext highlighter-rouge">-i</code> (comme <codeclass="language-plaintext highlighter-rouge">--in-interface</code>).</p>
<spanclass="nv">$IPT</span><spanclass="nt">-A</span> INPUT <spanclass="nt">-m</span> state <spanclass="nt">--state</span> ESTABLISHED <spanclass="nt">-j</span> ACCEPT
<spanclass="c"># Enregistrer la configuration</span>
<spanclass="nv">$SERVICE</span> iptables save
</code></pre></div></div>
<p>Dans l’état actuel, notre pare-feu est déjà utilisable sur une machine <em>standalone</em>, c’est-à-dire qui ne fait pas office de passerelle entre deux réseaux.</p>
<h3id="tester-le-pare-feu">Tester le pare-feu</h3>
<p>Le moment est venu de soumettre notre pare-feu à quelques tests. Installez <strong>nmap</strong>, un excellent outil qui permet de voir à quoi ressemble notre pare-feu depuis une machine extérieure, et lancez-le.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>Starting Nmap 7.70 ( https://nmap.org ) at 2019-02-01 09:29 CET
Nmap scan report for amandine (192.168.2.5)
Host is up (0.00018s latency).
rDNS record for 192.168.2.5: amandine.microlinux.lan
Not shown: 999 filtered ports
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 00:19:BB:E3:31:CE (Hewlett Packard)
Nmap done: 1 IP address (1 host up) scanned in 4.70 seconds
</code></pre></div></div>
<p>Sur le pare-feu, <codeclass="language-plaintext highlighter-rouge">netstat</code> permet de voir toutes les sockets réseau ouvertes et à l’écoute de nouvelles connexions.</p>
Active Internet connections (servers and established)
... Local Address Foreign Address State PID/Program name
... 0 0.0.0.0:22 0.0.0.0:* LISTEN 831/sshd
... 192.168.2.5:22 192.168.2.2:41304 ESTABLISHED 1419/sshd: root@pts
</code></pre></div></div>
<p>L’outil <codeclass="language-plaintext highlighter-rouge">netstat</code> vous permettra plus généralement de traquer et désactiver les services inutiles.</p>
<h3id="enregistrer-les-paquets-refusés">Enregistrer les paquets refusés</h3>
<p>Au stade actuel, ce n’est peut-être pas une mauvaise idée de garder une trace de tous les paquets refusés par notre pare-feu. Ajoutez la règle suivante vers la fin du script, après toutes les autres règles de filtrage.</p>
<p>Relancez le script pour prendre en compte les modifications.</p>
<p>Un moyen très simple pour effectuer un test, c’est d’installer un serveur Apache (<codeclass="language-plaintext highlighter-rouge">sudo yum install httpd</code>) et de le lancer (<codeclass="language-plaintext highlighter-rouge">sudo systemctl start httpd</code>). Ensuite, on ouvre un navigateur Web sur une machine du réseau local, et on tente de se connecter au serveur. Comme il faut s’y attendre, la page par défaut ne s’affiche pas. Jetons un oeil dans les logs.</p>
ID=53498 DF PROTO=TCP SPT=59416 DPT=80 WINDOW=29200 RES=0x00 SYN
URGP=0
...
</code></pre></div></div>
<p>Nous voyons que la machine <strong>192.168.2.2</strong> dans le réseau local a tenté vainement d’initier une connexion sur le port 80 du serveur.</p>
<p>L’enregistrement des paquets peut être amélioré comme ceci.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code># Enregistrer les connexions refusées
$IPT -A INPUT -m limit --limit 2/min -j LOG \
--log-prefix "++ IPv4 packet rejected ++ "
$IPT -A INPUT -j DROP
</code></pre></div></div>
<ul>
<li>Le souci avec la journalisation des paquets refusés, c’est qu’on risque de se faire submerger les logs par les tentatives de connexion quelque peu insistantes. On va donc limiter la journalisation à deux enregistrements par minute pour un même type de paquet.</li>
<li>La deuxième ligne sert à clôturer la configuration. À partir de là, les paquets entrants sont définitivement refusés.</li>
</ul>
<h3id="autoriser-les-services-de-base">Autoriser les services de base</h3>
<p>Nous disposons à présent d’un pare-feu minimal fonctionnel qui autorise les connexions locales en SSH, en bloquant tout le reste et en gardant une trace des connexions refusées. À partir de là, notre politique consistera à autoriser juste les services nécessaires, en les ajoutant au script <strong>firewall.sh</strong>.</p>
<p>Si nous souhaitons autoriser notre serveur Web local, il suffit d’ajouter la ligne suivante pour ouvrir le port 80 en TCP.</p>
<p>Le serveur Dnsmasq utilise le port 53 en TCP et en UDP, ainsi que les ports 67 et 68 en UDP. Voici comment nous autorisons l’accès à ce service.</p>
<p>Dans l’état actuel des choses, les machines du sous-réseau <strong>192.168.3.0/255.255.255.0</strong> ne peuvent pas communiquer avec le réseau <strong>192.168.2.0/255.255.255.0</strong>. Pour ce faire, nous devons configurer le relais des paquets.</p>
<p>Dans un premier temps, nous devons modifier la politique par défaut de notre pare-feu existant quant aux paquets relayés.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code># Politique par défaut
$IPT -P INPUT DROP
$IPT -P FORWARD ACCEPT
$IPT -P OUTPUT ACCEPT
</code></pre></div></div>
<p>Ensuite, le relais des paquets doit être activé au niveau du noyau. Concrètement, c’est le paramètre <codeclass="language-plaintext highlighter-rouge">net.ipv4.ip_forward</code> qui active (1) ou désactive (0) cette fonctionnalité.</p>
<p>À partir de là, toutes les machines du réseau <strong>192.168.3.0/24</strong> peuvent se connecter au serveur <strong>192.168.2.1</strong> en amont et partager la connexion Internet.</p>
<p>Au total, le script de pare-feu ressemblera à quelque chose comme ceci sur une passerelle.</p>
<spanclass="nv">$IPT</span><spanclass="nt">-A</span> INPUT <spanclass="nt">-m</span> state <spanclass="nt">--state</span> ESTABLISHED <spanclass="nt">-j</span> ACCEPT
<spanclass="nv">$IPT</span><spanclass="nt">-A</span> INPUT <spanclass="nt">-j</span> DROP
<spanclass="c"># Enregistrer la configuration</span>
<spanclass="nv">$SERVICE</span> iptables save
</code></pre></div></div>
<h3id="limiter-laccès-à-ssh">Limiter l’accès à SSH</h3>
<p>Sur une machine comportant une ouverture frontale sur Internet, <codeclass="language-plaintext highlighter-rouge">iptables</code> peut être utilisé pour limiter les tentatives de connexion à SSH.</p>
<p>Concrètement, lorsqu’on essaie d’initier une connexion SSH et que l’on se trompe à trois reprises en saisissant le mot de passe, il faudra attendre au moins une minute (<codeclass="language-plaintext highlighter-rouge">--seconds 60</code>) avant la prochaine tentative.</p>
<p>Sur mes <ahref="https://www.microlinux.fr/dedibox-centos-7/">serveurs dédiés publics</a>, j’utilise la configuration suivante.</p>
<li>Le délai d’attente avant la prochaine tentative de connexion est augmenté de 1 à 5 minutes (<codeclass="language-plaintext highlighter-rouge">--seconds 300</code>).</li>
<li>Les deux premières lignes définissent une exception pour les connexions en provenance de mon bureau et du serveur de sauvegardes (qui utilise <codeclass="language-plaintext highlighter-rouge">rsync</code> en combinaison avec <codeclass="language-plaintext highlighter-rouge">ssh</code> pour se connecter).</li>
</ul>
<h3id="documentation">Documentation</h3>
<ul>
<li>Antoine Le Morvan – Iptables, <ahref="https://formatux.fr/fr">Formatux</a>
</li>
<li>Carla Schroder – Building a Linux Firewall, <ahref="https://www.amazon.fr/Linux-Networking-Cookbook-Carla-Schroder/dp/0596102488">Linux Networking Cookbook</a>
</li>
<li>Michael Kofler, Firewalls mit Iptables selbst gebaut, <ahref="https://kofler.info/buecher/linux/">Linux 2017</a>
<p>Mon dépôt Github fournit quelques modèles de scripts <codeclass="language-plaintext highlighter-rouge">firewall-*.sh</code> pour différents contextes, dans le répertoire <strong>centos/el7/config/firewall</strong>.</p>
<codeclass="language-plaintext highlighter-rouge">firewall-gateway.sh</code> pour un serveur LAN faisant office de passerelle</li>
<li>
<codeclass="language-plaintext highlighter-rouge">firewall-standalone.sh</code> pour un serveur standalone dans un LAN</li>
<li>
<codeclass="language-plaintext highlighter-rouge">firewall-dedibox.sh</code> pour une machine publique</li>
</ul>
<p>Le sous-répertoire <strong>services</strong> fournit quelques exemples de règles de filtrage pour les services les plus répandus.</p>
<h2id="supprimer-une-règle-précise-dans-iptables">Supprimer une règle précise dans IPtables</h2>
<h3id="présentation">Présentation</h3>
<p>Dans ce court tutoriel, nous allons apprendre à supprimer une règle spécifique dans IPtables. Dans IPtables, le pare-feu présent par défaut sur la plupart des distributions Linux, les règles sont traitées et gérées par ligne à la suite, autrement dit quand on ajoute une règle, elle se met à la suite des autres et ne les remplace pas.</p>
<h3id="procédure">Procédure</h3>
<p>Heureusement, il est possible de gérer les règles indépendantes lorsque l’on souhaite en supprimer une, nous ne sommes pas obligé de tout supprimer puis de réécrire toutes nos règles mise à part celle(s) dont nous ne voulons plus. Il faut commencer par lister nos règles avec une option supplémentaire qui nous permettra d’afficher des numéros de lignes :</p>
<p>Suite à cela, on va pouvoir identifier précisément une règle ou une autre et on va pouvoir en supprimer une précisément avec la commande suivante :</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>iptables -D [TABLE] X
</code></pre></div></div>
<p>ou “TABLE” est la table visée et “X” le numéro de ligne.
Par exemple si nous voulons supprimer la ligne 9 de la table INPUT :</p>
<li><ahref="https://www.thegeekstuff.com/2011/02/iptables-add-rule/">Linux IPTables: How to Add Firewall Rules (With Allow SSH Example)</a></li>
<li><ahref="https://www.thegeekstuff.com/2011/03/iptables-inbound-and-outbound-rules/">Linux IPTables: Incoming and Outgoing Rule Examples (SSH and HTTP)</a></li>
<li><ahref="https://www.thegeekstuff.com/2012/08/iptables-log-packets/">How to Log Linux IPTables Firewall Dropped Packets to a Log File</a></li>
<li><ahref="https://www.thegeekstuff.com/2011/06/iptables-rules-examples/">25 Most Frequently Used Linux IPTables Rules Examples</a></li>