Ma méthode pour gérer les règles IpTables

Date: 10/06/2013 | Catégories: Open-source,Planet-libre,Systeme | Tags: ,,

iptables"Ooopsss..."

Cette phrase a été prononcée au moins une fois par toute personne ayant administré les règles de Firewall d'un serveur. Les conséquences vont du simple blocage d'une application critique (dont on s’aperçoit de l'indisponibilité au prochain "check" sur son serveur de monitoring) à la perte de connexion pure et simple vers la machine (même pour corriger sa boulette).

Pour éviter de se retrouver dans cette situation et ainsi éviter les rires et moqueries des collègues, voici quelques pistes que j'utilise pour administrer mes règles IpTables sur mes serveurs Debian.

1. Regrouper la sécurité dans un script de démarrage

Il y a plusieurs écoles pour gérer les règles de Firewall. Celle proposée par le wiki officiel de Debian repose sur l'utilisation exclusive des commandes iptables-save et iptables-restore qui permettent respectivement de sauvegarder et de restaurer une configuration IpTables existante.

Pour ma part, je préfère inclure ces commandes dans un script de plus haut niveau que je positionne dans le répertoire /etc/init.d et qui sera donc lancé au démarrage du serveur. Ce fichier firewall.sh est disponible sur mon GitHub DebianPostInstall ou via Gist.

En voici une version à ce jour:


Par défait le script met en place les règles suivantes:

  • autorise les connexions SSH entrantes (pour administrer son serveur à distance)
  • autorise les connexions HTTP, HTTPs et DNS sortante (pour l'installation et mise à jour du système et des logiciels)
  • interdiction et log des autres flux, entrant et sortant
  • et en cadeau bonux (ce qui on plus de 35 ans peuvent comprendre) sécurise un peu plus le kernel Linux

L'utilisation de ce script est standard, ainsi pour appliquer les règles de Firewall:

sudo service firewall.sh start

Pour supprimer les règles de Firewall (attention votre serveur sera ainsi exposé aux attaques extérieures puisqu'aucunes restriction d'accès ne sera appliquée):

sudo service firewall.sh clear

Attention: Il est également possible d'utiliser cette commande avec l'option stop (sudo service firewall.sh stop), mais il faut être conscient que toutes les connexions, entrantes et sortantes seront alors interdites (même votre SSH !!!). Cette commandes est donc à éviter bannir si l'on utilise une connexion à distance pour administrer son serveur...

2. Modifier les règles

On entre ici dans le vif du sujet de ce billet: Comment procéder quand on doit modifier les règles de sécurité ?

La première chose à faire est d'être sûr d'avoir les connaissances nécessaires avant de toucher à quoi que ce soit. Cela peut sembler évident, mais faire des copier/coller de règles trouver sur le net et que l'on ne maîtrisent pas est, sans aucun doute, le meilleur moyen de tout faire planter. Pour modifier les tables IpTables, il faut donc avoir un verni de connaissance général sur le protocole TCP/IP (notamment les notions d'adresses et de port sources/destinations). On trouve pour cela quelques très bon cours en ligne comme celui de chez Developpez.com ou bien la bible de Tanenbaum: Réseaux 5em édition aux éditions Pearson. Bien évidemment, il faut également connaitre les rudiments de la commande IpTables en lisant la documentation officielle (disponible en Français) et notamment la section sur le filtrage de paquets.

On peut passer aux choses sérieuses en identifiant les règles courantes grâce à la commande:

sudo iptables -n -L -v --line-numbers

On obtiendra alors une sortie dépendante des règles actives (exemple pour un de mes serveurs):

Chain INPUT (policy DROP 13 packets, 1398 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1     381M  138G fail2ban-ALL  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           
2     495K   83M fail2ban-SSH  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 
3     251M   23G fail2ban-HTTP  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80 
4     380M  138G fail2ban-ALL  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           
5     606M  241G ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
6    64473 3711K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 
7      12M  653M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80 
8        1    44 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:1337 
9    55724 3343K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:4949 
10      85  4064 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:5001 
11   53603 3216K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:61209 
12      13   532 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:123 
13    224K   21M ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:161 
14       0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:5001 
15       0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 
16    230K   22M ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
17   4822K  289M ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
18   3684K  435M LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0           LOG flags 0 level 4 
19       0     0 ACCEPT     tcp  --  *      *       88.190.254.200       0.0.0.0/0           tcp spt:20 

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1      98M  183G ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
2     253M  912G ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
3        1    84 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
4        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            195.20.242.89       tcp dpt:80 
5        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            212.211.132.32      tcp dpt:80 
6        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            212.211.132.250     tcp dpt:80 
7      179 10740 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:21 
8      276 14700 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 
9     1254 75180 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:25 
10   91789 5507K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80 
11   12940  776K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:443 
12    688K   46M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpts:1024:65534 
13     90M 5705M ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:53 
14   30171 2293K ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:123 
15       0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            88.190.254.200      tcp dpt:21 
16      78  3120 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0           LOG flags 0 level 4 
17      78  3120 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-port-unreachable 

Chain fail2ban-ALL (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
1     761M  277G RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           
2        0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain fail2ban-HTTP (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1     251M   23G RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain fail2ban-SSH (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1       10  1568 DROP       all  --  *      *       61.155.150.217       0.0.0.0/0           
2     408K   77M RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Une fois que vous avez identifié la règle IpTables à ajouter dans votre configuration,  il est maintenant temps de passer à l'action.

Ne jamais, jamais, modifier directement la table avec une commande IpTables sur un serveur en production...

Plusieurs solutions sont possibles, personnellement, j'utilise la méthodologie suivantes:

  1. je commence par copier le script firewall.sh dans un autre répertoire (par exemple dans /tmp/firewall.sh)
  2. j'ajoute la règle IpTables dans la copie du script (/tmp/firewall.sh)
  3. je teste les nouvelles règles en utilisant l'option "test" du script ainsi modifié qui va sauvegarder les règles actuelles, appliquer les nouvelles, attendre 30 secondes puis ré-appliquer les règles actuelles (donc au pire au fait une boulette de 30 secondes...)
  4. si tout se passe comme attendu pendant les 30 secondes, alors je copie le fichier /tmp/firewall.sh sous /etc/init.d
  5. et j'applique les règles en production le moment voulu

Les lignes de commandes correspondantes sont:

sudo cp /etc/init.d/firewall.sh /tmp/
sudo vim /tmp/firewall.sh
sudo sh /tmp/firewall.sh test
sudo cp /tmp/firewall.sh /etc/init.d/
sudo service firewall.sh restart

Ainsi, en cas de problème dans les règles, le serveur ne sera indisponible que pendant 30 secondes. Dans le cas "pas de bol" ou le serveur crache durant ces 30 secondes alors les anciennes règles seront rechargées au redémarrage.

Pas de script ?

Si vous ne souhaitez pas mettre en place un tel script de démarrage des règles de Firewall, il est quand même possible (même si je ne le conseille pas pour avoir une vue d'ensemble des règles à appliquer) de reproduire la méthodologie d'écrite dans le chapitre précédant.

Ainsi, il est tout à fait possible d'utiliser une commande du type:

sudo iptables-save > /etc/iptables.backup && sudo iptables <nouvelle regle a appliquer> && sleep 30 && sudo iptables-restore < /etc/iptables.backup

Conclusion

Comment gérez-vous vos règles de Firewall sur vos serveurs GNU/Linux ? Des astuces à partager avec nous dans les commentaires ?

Partager ce billet