Ceci est une ancienne révision du document !
IPTables - Installation et gestion de pare-feu
Création — Nicolas THOREZ 2022/07/20 08:47
Un pare-feu est un élément indispensable à la sécurité d'un serveur. Il permet de de contrôler les flux réseaux entrants, sortants et/ou transitant par ce serveur en autorisant ou interdisant ces dît flux.
Le principe est simple : le pare-feu est composé de règles et de politiques globales. Lorsqu'un flux passe sur le serveur, il est automatiquement analysé par ce dernier selon son trajet (entrant, sortant, transit). Le pare-feu va comparer ce flux à chacune de ces règles jusqu'à la dernière (si tout est bien configuré, cette dernière règle est la politique globale). Dès qu'il trouve une correspondance, il applique la règle et passe au flux suivant.
Ordre des règles
L'ordre des règles de pare-feu est extrêmement importante, ce dernier traitant la première règle correspondante trouvée. Ainsi, si votre 1ère règle autorise ou refuse tous les flux, les suivantes ne seront jamais traitées. Il est donc indispensable de commencer la liste des règles par les plus spécifiques possibles et de terminer par les règles plus générales, la dernière devant toujours être la politique par défaut.Politique par défaut
Pour des raisons de sécurité, les politiques par défaut sont généralement desrefus (DROP).
Il est toujours préférable de tout interdire et de n'autoriser que les flux identifiés comme utiles ou nécessaires. Cependant, il arrive qu'une exception pour le flux sortant soit faite. La politique par défaut pour ce flux devient alors autorisé (ACCEPT), considérant que les flux de l'intérieur vers l'extérieur sont maitrisés et légitimes (ce qui n'est pas toujours le cas).
Installation de IPTables
Droits
Attention, l'installation et le paramétrage de IPTables nécessitent des droitsroot. La plus grande prudence est donc requise.- L'installation est assez simple :
apt update && apt upgrade -y iptables
- On s'assure d'utiliser le bon programme de pare-feu :
update-alternatives --set iptables /usr/sbin/iptables-legacy
Le service iptables est désormais installé, on peut vérifier les règles actuelles avec la commande :
iptables -L -n
Ce qui nous donne :
Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
Comme on peut le voir, par défaut le pare-feu autorise absolument tout, le rendant de fait particulièrement inutile. Il nous faut donc le paramétrer avant de pouvoir correctement l'utiliser.
Paramétrage
Service
Le fichier principal du service est /etc/init.d/iptables. On va donc le modifier pour qu'il ressemble à cela :
#!/bin/bash -e
### BEGIN INIT INFO
# Provides: iptables
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Set firewall rules at boot
# Description: Set firewall rules at boot from /etc/iptables-base.conf and /etc/iptables.d
### END INIT INFO
PATH=/sbin:/usr/sbin:/bin:/usr/bin
do_start () {
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables-restore < /etc/iptables-base.conf
find /etc/iptables.d/ -type f | sort | while read f
do
iptables-restore -n < $f
done
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
}
do_stop () {
iptables -P INPUT ACCEPT
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
}
case "$1" in
start)
do_start
;;
restart|reload|force-reload)
do_start
;;
stop)
do_stop
;;
*)
echo "Usage: iptables [start|stop]" >&2
exit 3
;;
esac
:
Quelques explication pour do_start :
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
On supprime les règles existantes dans les tables NAT (qui permet le routage d'une adresse vers une autre) et MANGLE (qui permet la modification des paquets). A noter qu'on ne touche pas aux règles dynamiques afin de ne pas couper les connexions en cas de recharge du pare-feu.
iptables-restore < /etc/iptables-base.conf
On recharge les règles de base contenues dans le fichier /etc/iptables-base.conf.
find /etc/iptables.d/ -type f | sort | while read f
do
iptables-restore -n < $f
done
On recharge les règles spécifiques contenues dans le dossier /etc/iptables.d/.
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
On applique les politiques par défaut pour les chaînes d'entrée (INPUT), de transit (FORWARD) et de sortie (ACCEPT). A noter que l'on trouve souvent ces règles en début de script, hors, d'expérience, il est préférable de les mettre en dernière position afin de s'assurer qu'elles ne seront pas écrasées par d'autres règles.
Concernant le do_stop, on active un politique globale permissive et on supprime toutes les règles existantes.
Le fichier de service étant prêt, on s'assure qu'il est exécutable :
chmod +x /etc/init.d/iptables
On s'assure aussi que le service démarrera automatiquement :
systemctl enable iptables
Configuration de base
On crée maintenant le fichier de configuration de base /etc/iptables-base.conf :
nano /etc/iptables-base.conf
Son contenu doit être :
*filter :LOGACCEPT - [0:0] :LOGDROP - [0:0] # Allows all loopback (lo) traffic and drop all traffic to 127/8 that doesn't use lo -A INPUT -i lo -j ACCEPT -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT # Accepts all established inbound connections -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allows all outbound traffic -A OUTPUT -j ACCEPT # Custom chains for logging -A LOGACCEPT -m limit --limit 1/sec --limit-burst 10 -j LOG --log-prefix "ipt-logaccept " --log-level 7 --log-uid -A LOGACCEPT -j ACCEPT -A LOGDROP -m limit --limit 1/sec --limit-burst 10 -j LOG --log-prefix "ipt-logdrop " --log-level 7 --log-uid -A LOGDROP -j DROP COMMIT
Espace
Attention, les lignes vides ne doivent pas contenir d'espace (elles doivent être vraiment vides, juste un retour à la ligne) sinon, le scriptiptables va vouloir les interpréter, ce qui causera des erreurs.Niveau explication :
*filter ... COMMIT
Tous les fichiers de configurations doivent commencé par *filter et finir par COMMIT. Il s'agit de la syntaxe du langage utilisé par iptables.
:LOGACCEPT - [0:0] :LOGDROP - [0:0]
On crée les chaînes LOGACCEPT et LOGDROP pour les besoins de logs.
-A INPUT -i lo -j ACCEPT -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
On accepte tous les paquets de la boucle interne sauf ceux qui ne proviennent pas de cette boucle (la machine peut discuter avec elle-même mais les paquets extérieurs ne peuvent pas atteindre la boucle interne).
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
On accepte les connexions déjà établies (évite les coupures de flux).
-A OUTPUT -j ACCEPT
On accepte le flux sortant (permet l'établissement dynamique des flux sortant en réponse aux flux entrants).
-A LOGACCEPT -m limit --limit 1/sec --limit-burst 10 -j LOG --log-prefix "ipt-logaccept " --log-level 7 --log-uid -A LOGACCEPT -j ACCEPT -A LOGDROP -m limit --limit 1/sec --limit-burst 10 -j LOG --log-prefix "ipt-logdrop " --log-level 7 --log-uid -A LOGDROP -j DROP
On paramètre la chaîne de log pour les flux acceptés et refusés, en ajoutant notamment, un préfixe à chaque ligne de logs (pour les retrouver plus facilement dans syslog, un niveau de logs, des limites de saturations, etc…
Configurations spécifiques
Pour la suite, on peut ajouter des règles spécifiques selon les besoins de la machine. Pour cela, on va déjà créer le dossier qui contiendra ces règles :
mkdir /etc/iptables.d
Selon vos besoins
Les règles suivantes sont des exemples. Elles sont à mettre en place et à adapter selon vos besoins.A noter aussi que les noms de fichiers de configurations utilisés sont arbitraires.
Dans ce dossier, chaque fichier sera numéroté afin d'établir une hiérarchie.
Les groupes
On commence alors par créer le fichier 00-lists qui contiendra les groupes d'adresses IP (pratique pour appliquer une règle spécifique sur plusieurs adresses en même temps) :
nano /etc/iptables.d/00-listsContenu :
*filter # Réseau local :SHYRKA - -A SHYRKA -s 10.0.0.0/8 -j ACCEPT COMMIT
Dans cet exemple, je crée un groupe SHYRKA qui comprend toutes les adresses IP sur le réseau 10.0.0.0/8. Ainsi, si j'autorise un port pour ce groupe, toutes les adresses inclues dans ce groupe seront autorisées.
Les paquets invalides et/ou malformés
Il peut être intéressant de log les paquets invalides ou malformés suite à des micro-coupures ou des erreurs de communications avant de les supprimer. Pour cela, on ajoute le fichier 05-invalid dont le contenu est :
*filter # log iptables denied calls (access via 'dmesg' command) -A INPUT -m state --state INVALID -m limit --limit 5/min -j LOG --log-prefix "[ipt4-in-invalid] " --log-level 7 -A INPUT -m state --state INVALID -j DROP -A FORWARD -m state --state INVALID -m limit --limit 5/min -j LOG --log-prefix "[ipt4-fwd-invalid] " --log-level 7 -A FORWARD -m state --state INVALID -j DROP COMMIT
Ping
Le ping peut être autorisé sur la machine avec le fichier 10-ping :
*filter # Allow ping -A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT COMMIT
En remplaçant ACCEPT par DROP, le ping est alors explicitement refusé.
SSH
Sur un machine linux, il est fréquent de s'y connecter en SSH. Le port doit donc être autorisé mais surveillé. Pour cela, on aura recours au fichier 22-ssh :
*filter # Allows SSH from SHYRKA -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED,RELATED -j SHYRKA # Allows SSH from UNIVERSE -A INPUT -s 12.34.56.78 -p tcp --dport 22 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Ici, on applique l'ouverture du port 22 (SSH) pour le groupe SHYRKA (qui accepte les règles pour le réseau 10.0.0.0/8). Pour des connexions SSH depuis l'extérieur, j'utilise le paramètre -s pour spécifier l'adresse IP source (ici 12.34.56.78) pour laquelle l'ouverture du port est autorisé et ce afin d'éviter d'ouvrir ce port à tout internet, question de sécurité.
Log
On termine généralement par loguer tout ce qui n'est pas accepté via la configuration du fichier 99-log :
*filter # log iptables denied calls (access via 'dmesg' command) -A INPUT -m limit --limit 5/min -j LOG --log-prefix "[ipt4-in-deny] " --log-level 7 -A FORWARD -m limit --limit 5/min -j LOG --log-prefix "[ipt4-fwd-deny] " --log-level 7 COMMIT
Autres exemples de configurations
Ci-dessous, des exemples de configurations additionnelles selon des services courants.
FTP
Fichier : 21-ftp
Contenu :
*filter # Allow FTP and FTPS -A INPUT -p tcp --dport 20,21 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 989 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Messagerie
Fichier : 25-mail
Contenu :
*filter # Allows POP3 and POP3S -A INPUT -p tcp --dport 110 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 995 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # Allow IMAP and IMAPS -A INPUT -p tcp --dport 143 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 995 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # Allow SMTP, SMTPS and SMTPS with STARTTLS -A INPUT -p tcp --dport 25 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 465 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 587 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Munin node
Fichier : 26-munin-node
Contenu :
*filter # Allows Munin connections from Munin server(s) -A INPUT -p tcp -s 10.1.2.3 --dport 4949 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Serveur Web
Fichier : 30-web-server
Contenu :
*filter # Allows HTTP(s) connections -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
MySQL
Fichier : 34-mysql
Contenu :
*filter # Allows MySQL connections -A INPUT -p tcp --dport 3306 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Rsyslog (pour les puist de logs)
Fichier : 50-rsyslog
Contenu :
*filter # Allows Rsyslog connections -A INPUT -p tcp -s 10.4.5.6 --dport 514 -j ACCEPT -A INPUT -p udp -s 10.4.5.6 --dport 514 -j ACCEPT COMMIT
NRPE (Services actifs Nagios)
Fichier : 90-nrpe
Contenu :
*filter # Allows NRPE connections from Nagios server(s) -A INPUT -p tcp -s 10.7.8.9 --dport 5666 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
NSCA (Services passifs Nagios)
Fichier : 91-nsca
Contenu :
*filter # Allows NSCA connections from local network -A INPUT -p tcp -s 10.0.0.0/8 --dport 5667 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT COMMIT
Conclusion
Une fois les différentes configutions mises en place et le service iptables redémarrés, on peut voir les différentes règles appliquées avec iptables -L -n :
Exemple :
Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 REJECT all -- 0.0.0.0/0 127.0.0.0/8 reject-with icmp-port-unreachable ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED LOG all -- 0.0.0.0/0 0.0.0.0/0 state INVALID limit: avg 5/min burst 5 LOG flags 0 level 7 prefix "[ipt4-in-invalid] " DROP all -- 0.0.0.0/0 0.0.0.0/0 state INVALID ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 8 SHYRKA tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW,RELATED,ESTABLISHED ACCEPT tcp -- 12.34.56.78 0.0.0.0/0 tcp dpt:22 state NEW,RELATED,ESTABLISHED ACCEPT tcp -- 10.1.2.3 0.0.0.0/0 tcp dpt:4949 state NEW,RELATED,ESTABLISHED ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 state NEW,RELATED,ESTABLISHED ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 state NEW,RELATED,ESTABLISHED ACCEPT tcp -- 10.7.8.9 0.0.0.0/0 tcp dpt:5666 state NEW,RELATED,ESTABLISHED LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 5/min burst 5 LOG flags 0 level 7 prefix "[ipt4-in-deny] " Chain FORWARD (policy DROP) target prot opt source destination LOG all -- 0.0.0.0/0 0.0.0.0/0 state INVALID limit: avg 5/min burst 5 LOG flags 0 level 7 prefix "[ipt4-fwd-invalid] " DROP all -- 0.0.0.0/0 0.0.0.0/0 state INVALID LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 5/min burst 5 LOG flags 0 level 7 prefix "[ipt4-fwd-deny] " Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 Chain LOGACCEPT (0 references) target prot opt source destination LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 1/sec burst 10 LOG flags 8 level 7 prefix "ipt-logaccept " ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 Chain LOGDROP (0 references) target prot opt source destination LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 1/sec burst 10 LOG flags 8 level 7 prefix "ipt-logdrop " DROP all -- 0.0.0.0/0 0.0.0.0/0 Chain SHYRKA (1 references) target prot opt source destination ACCEPT all -- 10.0.0.0/8 0.0.0.0/0
Voilà, votre pare-feu est actif et entièrement paramétrable selon vos souhaits.
Discussion