Un grand classique : la gestion des règles IpTables. Tant qu’on est à la maison, pas de souci, par contre, sur une machine où on ne dispose que d’un accès distant, mieux vaut être prudent et prévoir de pouvoir tester ses règles avant de les appliquer (et éviter de se retrouver par erreur coincé sans accès à son serveur).
Ceux à qui c’est déjà arrivé se reconnaitront !
Je vais vous détailler ici ma configuration, sachant qu’on peut faire beaucoup plus robuste, selon son état de paranoïa et les besoins de sécurité de sa machine. Dans mon cas, je protège ici un serveur dédié qui héberge quelques sites web.
Plusieurs écoles cohabitent pour la gestion des règles du Firewall IpTables. Celle défendue sur le wiki officiel de Debian repose sur l’utilisation des commandes iptables-save et iptables-restore qui permettent respectivement de sauvegarder et de restaurer une configuration IpTables existante.
De mon côté je suis parti sur l’écriture de scripts et sous-scripts appelés via une entrée dans les processus de démarrage positionnés dans /etc/init.d/
.
1. Le script de démarrage /etc/init.d/firewall
Le script de démarrage n’a rien de sorcier. La seule chose que j’ai prévu c’est de pouvoir tester mes règles IpTables, en utilisant le paramètre “test”, qui va automatiquement remettre à zéro mes règles 5 minutes après. Pour cela il s’appuie sur l’utilisation de la commande at now + 5 min
. D’autres exemples sur le web utilisent la commande sleep
. Même si cela ne fonctionne évidemment pas de la même manière, la philosophie est la même.
### BEGIN INIT INFO # Provides: firewall # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Demarrage du script lors de la sequence boot # Description: Ajout des regles de parefeu iptables ### END INIT INFO case $1 in start) /usr/local/bin/firewall/fw-start.sh ;; status) echo "- Liste des règles :" /sbin/iptables -n -L ;; stop) /usr/local/bin/firewall/fw-reset.sh ;; restart) /usr/local/bin/firewall/fw-start.sh ;; test) /usr/local/bin/firewall/fw-start.sh echo "Vous avez 5 minutes pour tester vos règles avant réinitialisation automatique du firewall." echo /usr/local/bin/firewall/fw-reset.sh | at now + 5 min ;; *) echo "usage: iptables {start|status|stop|restart|test}" exit 1 ;; esac exit 0
Comme vous le voyez, pour faire propre, ce script de démarrage appelle lui-même deux sous-scripts (vous pouvez évidemment adapter les chemins) :
/usr/local/bin/firewall/fw-start.sh
qui contiendra mes règles IpTables,
/usr/local/bin/firewall/fw-reset.sh
qui ouvrira à tous les vents ma machine.
2. Mon script fw-start.sh
Ce script contient tout ce qui est nécessaire pour mon serveur. Je l’ai construit en m’appuyant sur celui proposé sur le site de documentation d’Ubuntu. Il vous faudra adapter les règles proposées en fonction des services pour lesquels vous souhaitez ouvrir un accès. Je vous conseille la lecture de l’article IpTables sur le site du zéro, qui constitue une bonne base de connaissance.
Si vous le souhaitez, modifiez ce script puis faites un petit sudo /etc/init.d/firewall test
. Si vos règles fonctionnent correctement, après les 5 minutes, sudo /etc/init.d/firewall start
.
La seule originalité de ce script se situe à la fin, puisqu’il appelle à nouveau des sous-scripts, tous situés dans /usr/local/bin/firewall/
et portant pour nom *-firewall.sh
. En effet, j’utilise des sous script pour créer des boucles de filtrage de certains ports en fonction de l’IP. Cela me permet par exemple de n’autoriser l’accès au server MySQL que depuis le bureau et chez moi. Je vous montrerai plus bas un exemple de ces scripts.
Egalement, j’appelle un script anti-pollution, que vous verrez plus bas.
#! /bin/bash echo "- Initialisation du firewall :" # Flush /sbin/iptables /sbin/iptables -F 2>/dev/null # Suppression des chaînes utilisateurs /sbin/iptables -X 2>/dev/null echo "- Vidage des regles et des tables : [OK]" # Interdire toutes connexions entrantes et sortantes /sbin/iptables -t filter -P INPUT DROP /sbin/iptables -t filter -P FORWARD DROP /sbin/iptables -t filter -P OUTPUT DROP echo "- Interdire toutes les connexions entrantes et sortantes : [OK]" ## Permettre à une connexion ouverte de recevoir du trafic en entrée. /sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ## Permettre à une connexion ouverte de recevoir du trafic en sortie. /sbin/iptables -A OUTPUT -m state ! --state INVALID -j ACCEPT echo "- Ne pas casser les connexions établies : [OK]" ########## Regles ########## # On accepte la boucle locale en entrée. /sbin/iptables -A INPUT -i lo -j ACCEPT # Autoriser le ping /sbin/iptables -t filter -A INPUT -p icmp -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p icmp -j ACCEPT # Autoriser SSH /sbin/iptables -t filter -A INPUT -p tcp --dport 22 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p tcp --dport 22 -j ACCEPT # Autoriser DNS /sbin/iptables -t filter -A OUTPUT -p tcp --dport 53 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p udp --dport 53 -j ACCEPT /sbin/iptables -t filter -A INPUT -p tcp --dport 53 -j ACCEPT /sbin/iptables -t filter -A INPUT -p udp --dport 53 -j ACCEPT # Autoriser NTP /sbin/iptables -t filter -A OUTPUT -p udp --dport 123 -j ACCEPT # Autoriser FTP /sbin/modprobe ip_conntrack_ftp /sbin/iptables -t filter -A INPUT -p tcp --dport 20:21 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p tcp --dport 20:21 -j ACCEPT # FTP Spécifique sortant /sbin/iptables -t filter -A OUTPUT -p tcp --dport 10020:10021 -j ACCEPT # Autoriser HTTP et HTTPS /sbin/iptables -t filter -A OUTPUT -p tcp --dport 80 -j ACCEPT /sbin/iptables -t filter -A INPUT -p tcp --dport 80 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p tcp --dport 443 -j ACCEPT /sbin/iptables -t filter -A INPUT -p tcp --dport 443 -j ACCEPT /sbin/iptables -t filter -A INPUT -p tcp --dport 8443 -j ACCEPT # Autoriser SMTP /sbin/iptables -t filter -A INPUT -p tcp --dport 25 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p tcp --dport 25 -j ACCEPT # Autoriser VNC /sbin/iptables -t filter -A INPUT -p tcp --dport 5901 -j ACCEPT /sbin/iptables -t filter -A OUTPUT -p tcp --dport 5901 -j ACCEPT # Filtrage en INPUT par IP de ports spécifiques FILTRES=$(find /usr/local/bin/firewall -type f -name "*-firewall.sh") if [[ -z $FILTRES ]] then echo " Aucun sous-script à exécuter de type /usr/local/bin/firewall/*-firewall.sh." else for FILE in $FILTRES do $FILE done fi # On log les paquets en entrée + apple script anti-pollution [ -e /usr/local/bin/firewall/anti-pollution-fw.sh ] /usr/local/bin/firewall/anti-pollution-fw.sh echo "- Initialisation des règles : [OK]" # Relançons fail2ban [ -e /etc/init.d/fail2ban ] && /etc/init.d/fail2ban restart exit 0
3. Mon script fw-reset.sh
Le boulot de ce script est de vider toutes les règles :
#! /bin/bash echo "Reset des règles iptables :" # Flush iptables /sbin/iptables -F 2>/dev/null # Suppression des chaînes utilisateurs /sbin/iptables -X 2>/dev/null echo "- Vidage des règles et des tables : [OK]" /sbin/iptables -P INPUT ACCEPT /sbin/iptables -P FORWARD ACCEPT /sbin/iptables -P OUTPUT ACCEPT echo "- Autoriser toutes les connexions entrantes et sortantes : [OK]" # Relançons fail2ban [ -e /etc/init.d/fail2ban ] && /etc/init.d/fail2ban restart exit 0
Vous remarquerez, comme sur le précédent script que je termine par redémarrer fail2ban
si il est configuré, de manière à ce que les règles de fail2ban
puissent être prises en compte correctement après avoir appliqué les miennes.
4. Le script anti-pollution.sh
Juste pour éviter de surcharger en logant tous les paquets en entrée :
#! /bin/bash /sbin/iptables -N CLEANUP /sbin/iptables -A CLEANUP -p udp -m udp --dport 67 -j DROP /sbin/iptables -A INPUT -j CLEANUP /sbin/iptables -A INPUT -j LOG
exit 0
5. Le sous-script de filtrage par IP
Cette fonction est assez intéressante. Dans mon script /usr/local/bin/firewall/fw-start.sh
je liste tous les scripts situés dans /usr/local/bin/firewall/
et portant pour nom *-firewall.sh
. Je mets en place un sous-script par port que je souhaite filtrer.
Voici un exemple, utilisé pour MySQL (mysql-firewall.sh
) :
#! /bin/bash /sbin/iptables -F MYSQL-WL >/dev/null 2>&1 /sbin/iptables -N MYSQL-WL >/dev/null 2>&1 /sbin/iptables -D INPUT -p tcp -m tcp --dport 3306 -j MYSQL-WL >/dev/null 2>&1 /sbin/iptables -A INPUT -p tcp -m tcp --dport 3306 -j MYSQL-WL if [ ! -e /etc/firewall/mysql-firewall.conf ]; then echo echo "ERROR: Le fichier de configuration /etc/firewall/mysql-firewall.conf n'existe pas !!!" >&2 echo echo "Voici un exemple de configuration:" cat <<-LISTE_DES_IPS # Format des lignes: # ip commentaire pouvant être inséré dans le firewall # Liste des ips autorisées à accéder à MySQL 123.167.256.78 adresse.ou.commmentaire 213.186.33.4 Cluster OVH LISTE_DES_IPS exit 1 fi cat /etc/firewall/mysql-firewall.conf | \ while read ip comment do [ -z "$ip" -o -z "${ip###*}" ] && continue if [ -n "$comment" ]; then /sbin/iptables -A MYSQL-WL -s $ip -m comment --comment "$comment" -j ACCEPT else /sbin/iptables -A MYSQL-WL -s $ip -j ACCEPT fi done < /etc/firewall/mysql-firewall.conf exit 0
et voici le fichier de configuration qui va avec (/etc/firewall/mysql-firewall.conf
). Vous pouvez mettre autant de lignes d’adresse à autoriser que nécessaire :
# Format des lignes: # ip commentaire pouvant être inséré dans le firewall (adresse, dns, commentaire) # Une ligne de commentaire débute par une dièse # Liste des ips autorisées à accéder à MySQL 213.186.33.4 Cluster OVH 123.167.256.78 adresse.ou.commmentaire
Une fois que vous avez mis en place ce sous-script, faites un petit sudo /etc/init.d/firewall test
. Si vos règles fonctionnent correctement, après les 5 minutes, sudo /etc/init.d/firewall start
.
Pour les amateurs, je vous incite aussi à voir ce que propose nicolargo sur son blog, c’est un poil différent. Tous vos commentaires et pistes d’améliorations sont les bienvenus !