Avertissement :
La version originale de cet article a été publiée sur IBM developerWorks
et est la propriété de Westtech Information Services. Ce document est une
traduction de la mise à jour de la version originale de l'article
réalisée par l'équipe de documentation Gentoo et contient quelques
améliorations proposées par l'équipe de documentation de Gentoo Linux. |
Ce guide vous montre comment utiliser NetFilter pour configurer un puissant pare-feu avec suivi de connexion (en anglais, « firewall stateful »). Tout ce dont vous aurez besoin est d'un système Linux existant utilisant une version 2.4 ou supérieure du noyau Linux. Un portable, PC de bureau, routeur ou serveur avec un Linux 2.4 ou plus fera l'affaire.
Vous devez être assez familier avec le vocabulaire réseau, comme les adresses IP, les ports source et destination, TCP, UDP ou ICMP, etc. Après avoir suivi ce guide jusqu'au bout, vous aurez compris le fonctionnement d'un firewall stateful sous Linux. De nombreux exemples de configurations vous seront également exposés.
Pour toute question technique sur le contenu de ce guide, contactez l'auteur, Daniel Robbins, à l'adresse suivante : drobbins@gentoo.org.
Résidant à Albuquerque, dans le Nouveau Mexique, Daniel Robbins a été le PDG de Gentoo Technologies, Inc., le créateur de Gentoo Linux, un système d'exploitation Linux moderne pour PC et du système Portage, un gestionnaire de ports nouvelle génération pour Linux. Il a également été un des auteurs contributeurs pour les livres Caldera OpenLinux Unleashed, SuSE Linux Unleashed, et Samba Unleashed, parus aux éditions Macmillan. Daniel a été au contact de l'informatique depuis l'école élémentaire quand il fut confronté au langage de programmation Logo ainsi qu'à une dose potentiellement dangereuse de Pac Man. Cela explique sans doute pourquoi il a depuis été employé en tant que Chef Infographiste chez SONY Electronic Publishing/Psygnosis. Daniel aime passer son temps libre avec sa femme, Mary et sa fille, Hadassah.
Dans ce guide, nous allons bâtir un pare-feu avec suivi de connexion pour Linux. Notre firewall va s'exécuter sur un ordinateur portable, de bureau, serveur ou routeur sous Linux ; son but principal est d'autoriser seulement certains types de trafic réseau à le traverser. Pour augmenter la sécurité, nous allons configurer le firewall pour ignorer ou rejeter le trafic qui ne nous intéresse pas ainsi que le trafic potentiellement dangereux pour la sécurité.
Avant de commencer à bâtir le pare-feu, il faut faire deux choses. Tout d'abord, il faut s'assurer que la commande iptables est disponible sur la machine. Pour cela, en tant que super-utilisateur, tapez iptables et vérifiez ce que vous répond le shell. Si la commande n'existe pas, alors il faut l'installer. Voilà comment faire :
Exemple de code 2.1 : Installation de iptables |
# emerge iptables
|
Une fois installée, la commande iptables est disponible, ainsi que la page de manuel qui lui correspond (man iptables). Ensuite, il faut nous assurer que les fonctionnalités nécessaires sont bien activées dans le noyau. Ce guide suppose que vous compilez vos propres noyaux. Dans le répertoire /usr/src/linux, tapez make menuconfig ou make xconfig ; nous allons choisir certaines fonctionnalités pour notre noyau.
Dans la section "Networking options" (dans le menu "Networking->Networking Options" pour le noyau 2.6), assurez-vous d'activer au moins les options suivantes :
Exemple de code 2.2 : Fonctionnalités noyaux nécessaires |
<*> Packet socket [*] Network packet filtering (replaces ipchains) <*> Unix domain sockets [*] TCP/IP networking [*] IP: advanced router [*] IP: policy routing [*] IP: use netfilter MARK value as routing key [*] IP: fast network address translation [*] IP: use TOS value as routing key |
Ensuite, dans le menu "IP: Netfilter Configuration ->", activez toutes les options, afin d'avoir toutes les fonctionnalités NetFilter disponibles pour votre pare-feu. Elles ne sont pas toutes nécessaires, mais vous pourrez ainsi mener quelques expériences avec ces options plus tard.
Il y a une fonctionnalité dans la section "Networking options" que vous ne devriez pas activer : la notification explicite de congestion. Laissez cette option décochée.
Exemple de code 2.3 : L'option à désactiver |
[ ] IP: TCP Explicit Congestion Notification support |
Si cette option est activée, votre machine Linux ne sera pas capable de supporter des communications réseau avec environ 8% de l'Internet. Quand l'ECN est activée, certains paquets envoyés par votre machine Linux auront le bit ECN à 1. En pratique, ce bit engendre des comportements bizarres sur certains routeurs Internet, aussi vaut-il mieux garder l'ECN désactivée.
Maintenant que le noyau est configuré correctement, compilez-le, installez-le et rebootez. Nous pouvons maintenant nous amuser avec NetFilter :)
Pour construire un pare-feu, la commande iptables sera votre meilleure alliée. Elle permet d'interagir avec les règles de filtrage de paquets au niveau du noyau. Nous utiliserons la commande iptables pour créer de nouvelles règles, afficher les règles existantes, en supprimer et choisir la politique de filtrage par défaut. Ce qui signifie que la création d'un pare-feu se résume à entrer une série de commandes iptables, comme par exemple (ATTENTION, ne pas la taper tout de suite !)
Exemple de code 2.4 : Choisir la politique par défaut DROP |
# iptables -P INPUT DROP
|
Si vous voulez créer un pare-feu quasiment parfait et que vous entrez cette commande, vous serez absolument bien protégé contre toutes formes d'attaques malicieuses. En effet, cette commande ordonne au noyau d'ignorer tous les paquets réseau entrants. Cependant, même si ce firewall est extrêmement sécurisé, il est également un peu mauvais. Mais avant de continuer, essayons de comprendre comment cette commande peut faire ce qu'elle fait.
Modifier la politique par défaut
La commande iptables -P est utilisée pour selectionner la politique par défaut pour une chaîne de filtrage de paquets. Dans cet exemple, iptables -P est utilisé pour changer la politique par défaut de la chaîne INPUT, une chaîne préinstallée qui est appliquée à chaque paquet entrant. En sélectionnant la potique par défaut DROP, on indique au noyau que chaque paquet qui atteint la fin de la chaîne INPUT doit être « droppé » (c'est-à-dire ignoré, supprimé de la mémoire). Et comme nous n'avons pas encore ajouté de règles dans la chaîne INPUT, tous les paquets atteignent la fin de la chaîne et donc tous les paquets sont ignorés.
Encore une fois, à elle seule, cette commande est totalement inutile. Cependant, elle montre une bonne stratégie pour la construction d'un pare-feu. On commence par ignorer tous les paquets par défaut, puis on ouvre au fur et à mesure les ports dont on a besoin. Cela garantit que le pare-feu est aussi sécurisé que possible.
Dans cet exemple, nous supposons que nous construisons un pare-feu pour une machine avec deux interfaces réseau, nommées eth0 et eth1. L'interface eth0 est connectée sur notre LAN, tandis que eth1 est branchée sur notre routeur DSL qui mène vers Internet. Dans une telle situation, nous améliorerons notre pare-feu ultime en rajoutant une ligne :
Exemple de code 3.1 : Améliorons notre pare-feu ultime |
# iptables -P INPUT DROP # iptables -A INPUT -i ! eth1 -j ACCEPT |
Cette ligne supplémentaire iptables -A ajoute une nouvelle règle de filtrage de paquets à la fin de la chaîne INPUT. Après avoir ajouté cette règle, la chaîne INPUT consiste en une règle unique et une règle DROP par défaut. Maintenant, voyons ce que fait notre pare-feu désormais à moitié terminé.
Quand un paquet arrive sur l'une des interfaces (lo, eth0 ou eth1), le code de NetFilter l'envoie sur la chaîne INPUT et vérifie s'il correspond à la première règle. Si c'est le cas, il est accepté et le traitement de ce paquet est terminé. Sinon, la règle par défaut de INPUT est appliquée et le paquet est effacé (DROP).
Voilà pour le point de vue conceptuel. Plus concrètement, la première règle correspond à tous les paquets arrivant sur les interfaces eth0 et lo, et les laisse passer. Tous les paquets arrivant sur l'interface eth1 sont droppés. Donc, si nous activons ce firewall sur notre machine, il pourra interagir avec notre LAN, mais ne pourra pas communiquer avec Internet. Voyons comment autoriser le trafic Internet, et ce de deux manières différentes.
Évidemment, pour que notre firewall serve à quelque chose, il nous faut sélectionner quels paquets seront autorisés à atteindre notre machine en passant par Internet. Il y a deux approches pour faire cela : l'une utilise des règles statiques, tandis que l'autre utilise des règles dynamiques, avec suivi de connexion.
Prenons pour exemple le cas du téléchargement de pages Web. Si nous voulons que notre machine soit capable de recevoir les paquets correspondants au téléchargement, nous pouvons ajouter une règle statique qui sera toujours vraie pour les paquets HTTP entrants, quelle que soit leur origine :
Exemple de code 3.2 : Acceptons tous les paquets HTTP entrants |
# iptables -A INPUT --sport 80 -j ACCEPT
|
Comme tout le trafic Web standard provient d'un serveur avec port source 80, cette règle permet effectivement à votre machine de télécharger des pages Web. Cependant, cette approche traditionnelle, bien qu'acceptable dans certains cas, engendre de nombreux problèmes.
Problèmes des pare-feu traditionnels
Voilà le premier problème : bien que la plupart du trafic Web ait pour origine un port 80, ce n'est quelquefois pas vrai. Donc, cette règle marche, mais seulement la plupart du temps. Par exemple, vous avez peut-être déjà vu une URL du genre "http://www.foo.com:81". Cette URL pointe vers un serveur Web hébergé sur un serveur écoutant sur le port 81 plutôt que le port 80 par défaut, et est donc inaccessible derrière notre pare-feu. Prendre en compte toutes les exceptions de ce genre va vite faire de notre firewall sécurisé un sac de n¿uds et remplira notre chaîne INPUT avec un tas de règles pour gérer chaque cas particulier.
Cependant, le problème majeur de ce genre de règle est lié à la sécurité. Évidemment, il est vrai que seulement le trafic avec un port source 80 sera autorisé à passer notre pare-feu, mais le port source d'un paquet est un élément facilement manipulable par un attaquant. Par exemple, si un intrus connaît la façon dont notre pare-feu est conçu, il peut le contourner simplement en s'assurant que toutes ses connexions entrantes viennent d'un port 80 de l'une de ses machines ! Puisque cette règle statique est trop facile à contourner, il nous faut une approche plus sécurisée et dynamique. Heureusement, iptables et le noyau 2.4 et supérieurs incluent tout ce dont nous avons besoin pour construire un pare-feu dynamique avec suivi de connexion.
4. Pare-feu dynamique avec suivi de connexion
Quelques mots sur le suivi de connexion
Plutôt que de creuser des trous dans notre pare-feu en se basant sur des caractéristiques statiques des protocoles, on peut utiliser les nouvelles fonctionnalités de suivi de connexion de Linux pour baser les décisions du pare-feu sur l'état dynamique des paquets par rapport à la connexion. Conntrack fonctionne en associant chaque paquet avec une et une seule communication bidirectionnelle, ou connexion.
Par exemple, imaginons ce qui se passe lorsque vous utilisez telnet ou ssh pour vous connecter sur une machine distante. Si vous regarder le trafic réseau au niveau des paquets, tout ce que vous verrez sera un tas de paquets passant d'une machine sur l'autre. Cependant, à un niveau d'abstraction plus élevé, cet échange de paquets est en fait une communication bidirectionnelle entre votre machine locale et la machine distante. Les pare-fxu traditionnels ne font que regarder chaque paquet indépendamment les uns des autres, sans se soucier qu'ils fassent en réalité partie d'un tout, d'une connexion.
C'est là que la technologie de suivi de connexion entre en jeu. La fonctionnalité conntrack de Linux peut voir les connexions de haut niveau lorsqu'elles ont lieu, reconnaissant votre session SSH comme une seule entité logique. Conntrack peut aussi reconnaître les échanges de paquets UDP et ICMP comme des connexions logiques, même si UDP et ICMP sont sans connexion par nature ; cela est très utile puisque cela permet d'utiliser conntrack pour gérer des échanges de paquets ICMP et UDP.
Si vous avez déjà redémarré avec votre nouveau noyau avec NetFilter activé, vous pouvez voir une liste des connexions réseau actives auxquelles votre machine participe en entrant cat /proc/net/ip_conntrack. Même sans pare-feu configuré, conntrack fonctionne en arrière-plan, en gardant trace des connexions établies ou reçues par votre machine.
Conntrack ne fait pas que reconnaître les connexions, il classe également chaque paquet qu'il voit dans l'un des quatres états de connexion. Le premier état dont nous allons parler est appelé NEW (nouveau). Quand vous tapez ssh hote.distant.com, le premier paquet ou la première rafale de paquets qui sortent de votre machine et sont destinés à hote.distant.com sont dans l'état NEW. Cependant, dès que vous aurez reçu ne serait ce qu'un seul paquet de hote.distant.com, tous les futurs paquets que vous enverrez à hote.distant.com dans cette connexion ne seront plus considérés comme des packets NEW. Pour résumer, un paquet est considéré NEW lorsqu'il sert à établir une nouvelle connexion, et qu'aucun trafic n'a été reçu de l'hôte distant en retour (dans le cadre de cette connexion précise, évidemment).
J'ai décrit les paquets NEW sortants, mais il est également tout à fait possible (et normal) d'avoir des paquets NEW entrants. Les paquets NEW entrants viennent généralement d'une machine distante et servent à établir une connexion avec vous. Le(s) premier(s) paquet(s) que votre serveur Web reçoit pour une requête HTTP sont considérés comme des paquets NEW entrants ; cependant, une fois que vous aurez répondu à un seul de ces paquets, tous les autres paquets que vous recevrez ne seront plus considérés dans l'état NEW.
Une fois qu'une connexion a vu du trafic dans les deux sens, tous les nouveaux paquets de cette connexion sont considérés dans l'état ESTABLISHED (établi). La distinction entre les états NEW et ESTABLISHED est très importante, comme nous le verrons dans un instant.
Le troisième état de connexion est appelé RELATED (en rapport avec). Les paquets RELATED sont ceux qui établissent une nouvelle connexion, mais qui sont en rapport avec une connexion déjà existante. L'état RELATED peut être utilisé pour filtrer des connexions qui font partie d'un protocole multi-connexion, comme FTP, ainsi que les paquets d'erreur en rapport avec des connexions existantes (comme les paquets d'erreur ICMP).
Pour terminer, il existe aussi les paquets INVALID : ce sont ceux qui ne peuvent être classés dans aucune des trois précédentes catégories. Il est important de noter qu'un paquet considéré comme INVALID n'est pas automatiquement ignoré ; c'est à vous de choisir les règles appropriées et d'ajuster les politiques pour que ces paquets soient gérés de la manière que vous préférez.
Bien, maintenant que nous avons compris le suivi de connexion, il est temps de jeter un ¿il à une simple règle supplémentaire qui va transformer notre pare-feu non-fonctionnel en quelque chose de plutôt utile.
Exemple de code 4.1 : Ajout d'une règle stateful |
# iptables -P INPUT DROP # iptables -A INPUT -i ! eth1 -j ACCEPT # iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT |
Cette simple règle, insérée à la fin de votre chaîne INPUT existante, va nous permettre d'établir des connexions avec des machines distantes. Elle fonctionne comme ceci : disons que l'on veuille faire du ssh vers hote.distant.com. Après avoir lancé ssh hote.distant.com, notre machine envoie un paquet pour établir la connexion. Ce paquet particulier est dans l'état NEW, et notre pare-feu le laisse passer, puisque nous bloquons seulement les paquets qui entrent dans notre firewall, pas ceux qui en sortent.
Quand nous recevons une réponse de hote.distant.com, ce paquet passe par notre chaîne INPUT. Il ne correspond pas à la première règle (puisqu'il arrive de eth1), donc il passe à la seconde et dernière règle. S'il correspond à cette règle, il sera accepté, et sinon, il arrivera à la fin de la chaîne INPUT et la politique par défaut lui sera appliquée (DROP). Alors, ce paquet entrant sera-t-il accepté ou droppé ?
Réponse : accepté. Quand le noyau examine ce paquet entrant, il reconnaît en premier qu'il fait partie d'une connexion existante. Ensuite, le noyau doit décider s'il s'agit d'un paquet NEW ou ESTABLISHED. Puisqu'il s'agit d'un paquet entrant, il vérifie si cette connexion a déjà eu du trafic sortant et trouve que c'est le cas (le paquet NEW initial que nous avons envoyé). Ensuite, le paquet entrant est classé ESTABLISHED, comme le seront tous les futurs paquets reçus ou envoyés qui seront associés avec cette connexion.
Maintenant, considérons ce qui ce passe si quelqu'un sur une machine distante essaie de se connecter en ssh chez nous. Le premier paquet que nous recevons est marqué NEW et ne correspond pas à la règle 1, donc il passe à la règle 2. Puisque ce paquet n'est pas dans l'état ESTABLISHED ou RELATED, il arrive à la fin de la chaîne INPUT et la politique par défaut, DROP, est appliquée. Notre demande d'établissement de connexion ssh entrante est donc ignorée sans même une réponse (ou un paquet TCP reset) de notre part.
Un pare-feu proche de la perfection
Alors, quel genre de pare-feu avons-nous jusqu'à présent ? Un excellent choix pour un portable ou un poste de travail si vous voulez que personne ne puisse se connecter depuis Internet vers vous, mais avec lequel vous pouvez quand même vous connecter à des sites sur Internet. Vous pourrez utiliser Netscape, Konqueror, ftp, ping, faire des recherches DNS, et bien plus. Toutes les connexions dont vous êtes l'initiateur pourront passer votre firewall. Cependant, les connexions non sollicitées qui viennent depuis Internet seront ignorées, à moins d'être en relation avec une connexion existante que vous avez initiée. Tant que vous ne devez pas fournir un service réseau vers l'extérieur, c'est un pare-feu pratiquement parfait.
Voilà un script simple qui peut être utilisé pour configurer notre premier firewall de station de travail :
Exemple de code 4.2 : Un script de pare-feu simple |
#!/bin/bash
# Un script de firewall simple pour une station de travail ou un portable
# qui ne fournit aucun service réseau comme un serveur web, ftp, smtp, etc.
if [ "$1" = "start" ]
then
echo "Démarrage du firewall..."
iptables -P INPUT DROP
iptables -A INPUT -i ! eth1 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
elif [ "$1" = "stop" ]
then
echo "Arrêt du firewall..."
iptables -F INPUT
iptables -P INPUT ACCEPT
fi
|
En utilisant ce script, vous pouvez désactiver le pare-feu en tapant ./firewall stop et le relancer en tapant ./firewall start. Pour désactiver le firewall, on supprime les règles de la chaîne INPUT en faisant iptables -F INPUT, puis reprenons la politique par défaut de INPUT en ACCEPT avec la commande iptables -P INPUT ACCEPT. Maintenant, voyons tout un tas d'améliorations que nous pouvons faire sur notre pare-feu. Après avoir expliqué chaque amélioration, je présenterai un script avancé pour un poste de travail. Ensuite, nous commencerons à modifier notre pare-feu pour des serveurs.
5. Améliorations du suivi de connexion
Désactication explicite de l'ECN
J'ai parlé plus haut de l'importance de désactiver l'ECN (explicit congestion notification) pour que les communications Internet fonctionnent correctement. Même si vous avez désactivé l'ECN dans le noyau en suivant ma suggestion, il est possible que vous l'oubliez dans le futur. Ou, comme c'est possible, vous allez passer votre script de pare-feu à quelqu'un qui a activé l'ECN. Pour ces raisons, c'est une bonne idée d'utiliser l'interface /proc pour désactiver explicitement l'ECN, comme ceci :
Exemple de code 5.1 : Désactivation explicite de l'ECN |
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
|
Si vous utilisez votre machine Linux comme un routeur, alors vous voudrez activer l'IP forwarding, ce qui donnera la permission au noyau de transmettre des paquets de l'interface eth0 à eth1, et inversement. Dans notre exemple de configuration, oú eth0 est connecté à notre LAN, et eth1 à Internet, activer l'IP forwarding est une étape nécessaire pour permettre à notre LAN de se connecter à Internet en passant par notre machine Linux. Pour activer l'IP forwarding, utilisez cette ligne :
Exemple de code 5.2 : Forwarding |
# echo 1 > /proc/sys/net/ipv4/ip_forward
|
Jusqu'à présent, nous avons ignoré tout le trafic non sollicité venant d'Internet. Bien que celà soit un moyen efficace pour contrer l'activité réseau non désirable, cela engendre également quelques inconvénients. Le plus gros problème avec cette approche est qu'il est facile pour un intrus de détecter que nous utilisons un pare-feu puisque notre machine ne répond pas avec les réponses standards TCP reset et ICMP port-unreachable, c'est-à-dire les réponses qu'une machine normale devrait renvoyer pour indiquer une tentative de connexion échouée vers un service non existant.
Plutôt que de laisser des intrus potentiels savoir que nous utilisons un pare-feu (ce qui peut leur laisser penser que nous fournissons des services précieux auquels ils ne peuvent pas accéder), il serait à notre avantage de faire croire que nous n'utilisons pas de firewall. En ajoutant ces deux règles à la fin de la chaîne INPUT, on peut facilement accomplir cette tâche :
Exemple de code 5.3 : Gestion des rejets |
# iptables -A INPUT -p tcp -i eth1 -j REJECT --reject-with tcp-reset # iptables -A INPUT -p udp -i eth1 -j REJECT --reject-with icmp-port-unreachable |
La première règle s'occupe de rejeter correctement les connexions TCP, alors que la seconde s'occupe de l'UDP. Avec ces deux règles, il devient difficile pour un intrus de détecter que nous sommes derrière un pare-feu ; avec de la chance, l'intrus se détournera de notre machine pour chercher d'autres cibles potentiellement plus intéressantes.
En plus de rendre notre firewall plus discret, ces règles éliminent aussi le délai lors de la connexion à certains serveurs FTP et IRC. Ce délai est dû au serveur qui tente de faire une requête ident sur votre machine (en se connectant sur le port 113), qui échoue après un timeout d'environ 15 secondes. Maintenant, notre firewall va renvoyer un TCP reset et la requête ident va échouer immédiatement plutôt que de réssayer pendant 15 secondes (alors que vous attendez patiemment une réponse du serveur).
Dans plusieurs distributions, quand une interface réseau est activée, plusieurs vieilles règles ipchains sont également ajoutées au système. Ces règles spéciales avaient été ajoutées par les créateurs de la distribution pour contrer un problème appelé spoofing dans lequel les adresses sources des paquets ont été trafiqués pour contenir une valeur invalide (c'est une des choses que les script kiddies font). Bien que l'on pourrait créer des règles iptables similaires pour bloquer ces paquets spoofés, il y a une manière de faire plus facile. De nos jours, le noyau a la fonctionnalité intégrée d'ignorer les paquets spoofés ; il suffit de l'activer par le biais de l'interface /proc. Voilà comment :
Exemple de code 5.4 : Protection contre le spoofing |
for x in lo eth0 eth1
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
|
Ce script shell va indiquer au noyau d'ignorer tous les paquets spoofés sur les interfaces lo, eth0 et eth1. Vous pouvez soit ajouter ces lignes à votre script de firewall, soit dans le script qui active vos interfaces lo, eth0 et eth1.
Le NAT (network address translation) et l'IP masquerading, bien que non directement en rapport avec les pare-feu, sont souvent utilisés en complément. Nous allons voir deux configurations répandues de NAT/Masquerading que vous pourrez devoir utiliser. La première règle servira dans les situations où vous utilisez un lien non permanent vers Internet (ppp0) avec une adresse IP dynamique.
Exemple de code 5.5 : Masquerading |
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
|
Si vous êtes dans cette situation, vous voudrez également convertir mes scripts de firewall pour que les références à "eth1" (le routeur DSL dans notre exemple) soient changées en "ppp0". Et il est tout à fait possible d'ajouter des règles qui font références à "ppp0" alors que cette interface n'existe pas encore. Dès que ppp0 est activée, tout fonctionnera à merveille. Vérifiez quannd même que vous avez activé l'IP forwarding.
Si vous utilisez une ligne DSL pour vous connecter à Internet, vous avez probablement une des deux configurations suivantes. Dans la première, votre routeur DSL ou modem a sa propre adresse IP et s'occupe de la translation d'adresse pour vous. Si vous êtes dans cette situation, vous n'avez pas besoin de faire du NAT puisque votre routeur DSL le fait déjà.
Cependant, si vous voulez avoir plus de contrôle sur vos fonctionnalités NAT, vous pouvez eventuellement, si votre fournisseur d'accès le permet, configurer votre routeur DSL en mode "bridge" (pont). Dans ce mode, votre pare-feu devient un élément officiel du réseau de votre fournisseur d'accès et le routeur DSL s'occupe de relayer le trafic de et vers votre machine Linux de manière transparente. Il n'a plus besoin d'une adresse IP ; à la place, eth1 (dans notre exemple) en a une. Si quelqu'un envoie un ping à votre adresse IP depuis Internet, il recevra une réponse de votre machine Linux et pas de votre routeur.
Avec ce genre de configuration, vous devrez utiliser SNAT (source NAT) plutôt que le Masquerading. Voici la ligne que vous devriez rajouter à votre firewall :
Exemple de code 5.6 : SNAT |
# iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 1.2.3.4
|
Dans cet exemple, remplacez eth1 par l'interface Ethernet connectée sur votre routeur DSL ainsi que 1.2.3.4 par votre adresse IP statique (l'IP de votre interface Ethernet). Encore une fois, n'oubliez pas l'IP forwarding.
Heureusement pour nous, le NAT et le masquerading s'entendent bien sur notre pare-feu. Quand vous écrivez vos règles de firewall, ignorez simplement que vous utilisez du NAT. Vos règles doivent accepter, ignorer ou rejeter les paquets en se basant sur leur "véritables" adresses source et destination. Le code de filtrage du pare-feu prend en compte l'adresse source d'origine et l'adresse de destination finale. C'est tant mieux pour nous, puisque cela permet à notre firewall de fonctionner correctement même si on désactive temporairement le NAT ou le masquerading.
Dans les exemples de NAT/masquerading précédents, on a ajouté des règles à une chaîne, mais nous avons également fait des choses un peu différemment. Remarquez l'option "-t". L'option "-t" permet de choisir la table à laquelle appartient notre chaîne. Quand cette option n'est pas spécifiée, la table par défaut est la table "filter". Par conséquent, toutes les commandes précédentes sans rapport avec le NAT ont modifié la chaîne INPUT qui fait partie de la table "filter". La table "filter" contient toutes les règles associées à l'acceptation/rejet de paquets, tandis que la table "nat" (comme vous pouvez le deviner) contient les règles concernant la translation d'adresse. Il existe d'autres chaînes iptables qui sont décrites en détail dans la page de manuel iptables, ainsi que dans les HOWTO de Rusty Russel (cf. dans la section Ressources plus bas pour les liens).
Maintenant que nous avons vu tout un tas d'améliorations possibles, il est temps de voir un second script plus souple d'activation/désactivation du firewall :
Exemple de code 5.7 : Notre script amélioré |
#!/bin/bash # Un pare-feu avec suivi de connexion amélioré pour une station de travail, portable ou # routeur qui ne fourni aucun service réseau (comme serveur web, smtp, ftp, etc.) # Cette variable définit le nom de l'interface qui est connectée à Internet) UPLINK="eth1" # Si vous êtes un routeur, vous devez forwarder les paquets IP entre les interfaces, # mettez ROUTER="yes" ; sinon, ROUTER="no" ROUTER="yes" # Changez la prochaîne ligne pour mettre l'adresse IP statique de votre interface # uplink pour faire du SNAT statique, ou "dynamic" si vous avez une IP dynamique # Si vous n'avez pas besoin de NAT, laissez NAT="" pour le désactiver. NAT="1.2.3.4" # Changez cette variable pour lister toutes vos interfaces réseau, y compris lo INTERFACES="lo eth0 eth1" if [ "$1" = "start" ] then echo "Demarrage du firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable # Desactivation explicite de l'ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi # Désactiver le spoofing sur toutes les interfaces for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then # Activation de l'IP forwarding pour le routage echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then # Adresse IP dynamique, utilisation du masquerading echo "Activation du masquerading (IP dynamique)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then # IP statique, utilisation du SNAT echo "Activation SNAT (IP statique)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Arret du firewall..." iptables -F INPUT iptables -P INPUT ACCEPT # Désactive le NAT/masquerading iptables -t nat -F POSTROUTING fi |
6. Serveurs avec suivi de connexion
Avant de commencer à modifier notre pare-feu pour pouvoir l'utiliser sur un serveur, je dois vous montrer comment afficher les règles actives sur votre pare-feu. Pour voir les règles dans la chaîne INPUT de la table filter, tapez :
Exemple de code 6.1 : Voir les règles |
# iptables -v -L INPUT
|
L'option -v nous donne une sortie verbeuse afin que l'on puisse voir le nombre total de paquets et d'octets transférés par règle. On peut aussi voir la chaîne POSTROUTING de la table nat avec la commande suivante :
Exemple de code 6.2 : Voir les règles de la chaîne POSTROUTING de la table nat |
# iptables -t nat -v -L POSTROUTING
Chain POSTROUTING (policy ACCEPT 399 packets, 48418 bytes)
pkts bytes target prot opt in out source destination
2728 170K SNAT all -- any eth1 anywhere anywhere
to:215.218.215.2
|
À l'heure actuelle, notre firewallare-feu ne permet pas au public de se connecter aux services sur notre machine, car elle accepte seulement les paquets entrants dans l'état ESTABLISHED ou RELATED. Comme il ignore tous les paquets NEW entrants, toutes les tentatives de connexion sont systématiquement rejetées. Cependant, en autorisant sélectivement certains paquets à traverser notre pare-feu, on peut permettre au public de se connecter aux services que nous offrons.
Bien que l'on veuille accepter quelques connexions entrantes, on ne souhaite tout de même pas les accepter toutes. Il est préférable de partir d'une politique "rejet par défaut" (comme nous l'avons configuré actuellement) et d'ouvrir l'accès aux seuls services que l'on souhaite rendre publics. Par exemple, si nous avons un serveur Web, nous allons autoriser les paquets NEW vers notre machine, mais seulement s'ils sont destinés au port 80 (HTTP). C'est tout ce qu'il suffit de faire. Dès que nous autorisons le paquet NEW à passer, on autorise l'établissement de connexion. Une fois la connexion établie, la règle existante qui autorise les paquets entrants ESTABLISHED et RELATED entre en scène, laissant se dérouler la connexion HTTP sans accrocs.
Jetons un ¿il au c¿ur de notre pare-feu et à la nouvelle règle qui autorise les connexion HTTP entrantes :
Exemple de code 6.3 : Exemple d'HTTP avec suivi |
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Notre nouvelle règle
iptables -A INPUT -p tcp --dport http -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable
|
Cette nouvelle règle autorise les paquets TCP NEW entrants destinés au port 80 (HTTP) de notre machine à entrer. Remarquez la place de cette règle. Il est important qu'elle soit placée avant notre règle REJECT. Comme iptables applique seulement la première règle qui correspond, la mettre derrière les lignes REJECT serait sans effets.
Notre script de pare-feu avancé
Maintenant, voyons notre dernier script de pare-feu qui peut être utilisé sur un portable, station de travail, routeur ou serveur (ou une quelconque combinaison !)
Exemple de code 6.4 : Notre script de pare-feu avancé |
#!/bin/bash # Notre script de firewall complement stateful. Ce firewall peut être adapté # pour un portable, station de travail, routeur ou même un serveur. # Changez cette variable pour le numéro de l'interface "uplink" # (connexion vers Internet) UPLINK="eth1" # Si vous êtes routeur (et donc souhaitez forwarder les paquets IP entre # les interfaces), mettez ROUTER="yes"; sinon, ROUTER="no" ROUTER="yes" # Changez la ligne qui suit vers l'adresse IP statique de votre interface # uplink pour du SNAT statique, ou "dynamic" si vous avez une IP dynamique. # Si vous ne voulez pas de NAT, mettez NAT="" pour le désactiver. NAT="1.2.3.4" # Changez cette ligne pour lister toutes vos interfaces réseau, y compris lo INTERFACES="lo eth0 eth1" # Changez cette ligne pour lister les numéros de ports ou noms symboliques # (de /etc/services) de tous les services que vous souhaiter rendre publics. # Si vous ne souhaitez publiez aucun service, laissez "" SERVICES="http ftp smtp ssh rsync" if [ "$1" = "start" ] then echo "Démarrage du firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Activer l'accès publics aux services for x in ${SERVICES} do iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT done iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable # Désactivation explicite de l'ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi # Protection anti-spoofing for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then # Activation de l'IP forwarding echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then # IP dynamique => masquerading echo "Activation du masquerading (ip dynamique)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then # IP statique => SNAT echo "Activation du SNAT (ip statique)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Arrêt du firewall..." iptables -F INPUT iptables -P INPUT ACCEPT # Arrêt du masquerading iptables -t nat -F POSTROUTING fi |
7. Construire un meilleur pare-feu pour serveur
Il est souvent possible de rendre son pare-feu toujours un peu mieux. Bien sûr, la signification de mieux dépend de vos besoins spécifiques. Notre script existant peu combler exactement les vôtres, ou peut-être que quelques retouches seront nécessaires. Cette section est sensée servir de livre à idées pour vous montrer plusieurs moyens d'améliorer notre pare-feu.
Jusqu'à présent, nous n'avons pas vu comment logger des événements. Il y a une cible spéciale appelée LOG que vous pouvez utiliser. Associée à LOG, il y a une option spéciale appelée --log-prefix qui permet de choisir le texte qui apparaîtra devant le descriptif du paquet dans les logs du système. Voilà un exemple de règle LOG :
Exemple de code 7.1 : Exemple de règle LOG |
# iptables -A INPUT -j LOG --log-prefix "Anomalie INPUT:"
|
Vous ne voudrez certainement pas ajouter cette règle en premier dans votre chaîne INPUT, car elle entraînerait qu'une entrée dans les logs soit créée pour chaque paquet que vous recevez ! À la place, placez cette règle assez bas dans la chaîne INPUT pour logguer uniquement les paquets bizarres et autres anomalies.
Une remarque importante sur la cible LOG. Normalement, quand une règle correspond à un paquet, ce paquet est soit accepté, rejeté ou ignoré, et les règles suivantes ne sont pas vérifiées. Cependant, quand une règle LOG correspond, ce paquet est loggué. Il n'est ni accepté, ni rejeté, ni ignoré. À la place, le paquet est confronté à la règle suivante, ou bien la règle par défaut est appliquée s'il n'y a pas de règle suivante.
La cible LOG peut également être combinée avec le module "limit" (décrit dans la page de manuel iptables) pour éviter d'avoir trop d'entrées dupliquées. Voilà un exemple :
Exemple de code 7.2 : Limiter la taille des logs |
# iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute -j LOG --log-prefix "Etat INVALID:"
|
iptables vous permet de créer vos propres chaînes qui peuvent être ensuite spécifiée comme cibles dans vos règles. Pour en apprendre plus à ce sujet, étudiez le Packet filtering HOWTO hebergé sur le site du projet netfilter/iptables (http://www.netfilter.org/).
Politique de restriction d'usages
Les pare-feu offrent une grande puissance à ceux qui veulent restreindre les usages d'un réseau dans une entreprise ou un réseau académique. Vous pouvez contrôler quels paquets votre machine relaie en ajoutant des règles dans la chaîne FORWARD. En ajoutant des règles à la chaîne OUTPUT, vous pouvez également contrôler ce qui arrive aux paquets générés localement, par les utilisateurs sur la machine Linux elle-même. iptables a aussi l'incroyable capacité de filtrer les paquets générés localement en fonction de leur propriétaire (UID ou GID). Pour plus d'informations à ce sujet, cherchez "owner" (propriétaire) dans la page de manuel iptables.
Dans notre exemple de pare-feu, nous avons supposé que tout le trafic du LAN interne est digne de confiance et que seul le trafic Internet devait être filtré avec soin. Selon votre réseau interne, cela peut être ou ne pas être le cas. Rien ne vous empêche de configurer votre firewall pour vous protéger également du coté du LAN. Envisagez les autres angles de votre réseau que vous voulez protéger. Il peut être aussi approprié de configurer deux zones de sécurité différentes dans votre LAN, chacune avec sa propre politique de sécurité.
Dans cette section, je vous indique des ressources variées que vous trouverez certainement utiles pour vous aider à mettre au point votre pare-feu. Commençons par un outil important...
tcpdump est un outil essentiel pour l'exploration bas niveau des echanges de paquets et pour vérifier que votre pare-feu fonctionne correctement. Si vous ne l'avez pas, installez-le. Si vous l'avez, commencez à l'utiliser.
Visitez le site web du projet netfilter/iptables (http://www.netfilter.org). Il fournit un grand nombre de ressources, y compris les sources de iptables et une FAQ netfilter. De plus le Rusty's Remarkably Guides est excellent. Il décit les concepts de base des réseaux et ajoute des guides netfilter (iptables), NAT et un « netfilter hacking HOWTO » pour les développeurs.
Heureusement, de nombreuses ressources sont disponibles en ligne à propos de Netfilter ; cependant, n'oubliez pas les bases. La page de manuel iptables est très détaillée et est un excellent exemple de ce à quoi une page de manuel devrait ressembler. C'est une lecture passionnante.
Guide du routage et du contrôle de trafic avancé
Le Advanced Linux Routing and Traffic Control HOWTO est disponible (également en français). Il contient tout un chapitre sur l'utilisation d'iptables pour le marquage de paquets, puis sur l'utilisation des fonctionnalités de routage de Linux pour router les paquets en fonction de ces marques.
Note : Ce guide contient des références vers la fonction de contrôle de trafic (qualité de service) de Linux (accessible via la commande tc). Cette nouvelle fonctionnalité, bien que très puissante, est très peu documentée, et essayer de cerner tous les aspects du contrôle de trafic peut être une tâche très frustrante pour le moment. |
Les utilisateurs qui ont des questions sur l'utilisation, l'installation ou la configuration de Netfilter/iptables, ou qui veulent aider les autres utilisateurs en partageant leurs experience et connaissances, peuvent contacter la mailing-list des utilisateurs de Netfilter.
Les développeurs Netfilter/iptables qui ont des questions, suggestions ou contributions pour le developpement de Netfilter/iptables peuvent contacter la mailing-list des développeurs de Netfilter.
Vous pouvez aussi parcourir les archives sur ces URL.
« Building Internet Firewalls, Second Edition »
En juin 2000, O'Reilly a publié un excellent livre : Building Internet Firewalls, Second Edition. C'est un bon manuel de référence, en particulier dans les cas où vous voulez configurer votre pare-feu pour accepter (ou rejeter) un protocole peu connu avec lequel vous n'êtes pas familier.
Voilà, c'était la liste de nos ressources et ce guide est terminé. J'espère qu'il vous a été utile et j'attends vos remarques.
Nous acceptons volontier vos remarques sur ce tutoriel. De plus, n'hésitez pas à contacter l'auteur, Daniel Robbins, à l'adresse Daniel Robbins.