Mon CV

Mon script IpTables avec fonction de test

22 juin 2013

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 !

 

 

 

 

 

Posted in Unix et LinuxTags: