====== IPTables - Installation et gestion de pare-feu ====== --- //[[nekan@shyrkasystem.com|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. 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. Pour des raisons de sécurité, les politiques par défaut sont généralement des ''refus'' (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 ====== Attention, l'installation et le paramétrage de IPTables nécessitent des droits ''root''. 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 Attention, les lignes vides ne doivent pas contenir d'espace (elles doivent être vraiment vides, juste un retour à la ligne) sinon, le script ''iptables'' 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 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-lists Contenu : *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. ===== NTP ===== * Fichier : ''12-ntp'' * Contenu : *filter # Allow NTP -A INPUT -p udp --dport 123 -j ACCEPT COMMIT ===== 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 ===== DNS ===== * Fichier : ''53-dns'' * Contenu : *filter # Allows DNS connections -A INPUT -p udp --dport 53 -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~~