Ceci est une ancienne révision du document !


IPTables - Installation et gestion de pare-feu

CréationNicolas 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 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

Droits

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

Espace

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

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.

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.

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

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é.

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é.

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.

  • 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

  • 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

  • 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

  • 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

  • Fichier : 34-mysql
  • Contenu :

*filter

# Allows MySQL connections
-A INPUT -p tcp --dport 3306 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

COMMIT

  • 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

  • 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

  • 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

Fini

Voilà, votre pare-feu est actif et entièrement paramétrable selon vos souhaits.
Entrer votre commentaire. La syntaxe wiki est autorisée:
 
  • iptables.1658311927.txt.gz
  • Dernière modification : 2022/07/20 12:12
  • de nekan