S03 - Pare-feu sous Linux : iptables, nftables, ufw

Objectif

Filtrer le trafic d’un serveur Linux, et transformer une VM Linux en routeur NAT (comme la VM routeur du projet transversal).


1. Qui fait quoi ?

Le filtrage est fait dans le noyau par Netfilter. On le pilote avec un outil :

OutilStatut en 2026Usage
iptablesToujours très utilisé (en réalité souvent iptables-nft, qui traduit vers nftables)Cours, TP, scripts existants
nftables (nft)Remplaçant officiel (défaut Debian 10+)Nouvelles installations
ufwSurcouche simple (Ubuntu, Pop!_OS)Poste de travail
firewalldSurcouche à zones (Fedora, RHEL)Serveurs RHEL

2. Le parcours d’un paquet dans iptables

flowchart LR
  IN(("Paquet entrant")) --> PRE["PREROUTING<br/>(table nat : DNAT)"]
  PRE --> D{"Pour moi ?"}
  D -- oui --> INPUT["INPUT<br/>(filter)"] --> APP["Programme local<br/>(sshd, apache…)"]
  D -- non --> FWD["FORWARD<br/>(filter) — routeur"] --> POST
  APP --> OUT["OUTPUT"] --> POST["POSTROUTING<br/>(table nat : SNAT / MASQUERADE)"]
  POST --> SORTIE(("Paquet sortant"))
ChaîneTrafic concerné
INPUTDestiné à la machine elle-même
OUTPUTÉmis par la machine
FORWARDQui traverse la machine (routeur)
PREROUTING / POSTROUTINGAvant / après la décision de routage (NAT)

Actions (targets) : ACCEPT (laisser passer), DROP (jeter sans répondre), REJECT (refuser en prévenant), LOG (journaliser), MASQUERADE / SNAT / DNAT (NAT).


3. iptables : les commandes essentielles

sudo iptables -L -n -v --line-numbers      # lister les règles (filter)
sudo iptables -t nat -L -n -v              # lister les règles NAT
 
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT        # -A = ajouter à la fin
sudo iptables -I INPUT 1 -s 10.0.0.5 -j DROP              # -I = insérer en position 1
sudo iptables -D INPUT 3                                  # supprimer la règle n°3
sudo iptables -P INPUT DROP                               # politique par défaut
sudo iptables -F                                          # tout vider (attention !)

En SSH sur une machine distante : autorise le port 22 AVANT de passer INPUT en DROP, sinon tu te coupes toi-même.

Pare-feu minimal d’un serveur web

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
sudo iptables -P INPUT DROP

Rendre les règles permanentes (Debian/Ubuntu)

sudo apt install iptables-persistent      # propose de sauvegarder les règles actuelles
sudo netfilter-persistent save            # après chaque modification
# fichiers : /etc/iptables/rules.v4 et rules.v6

4. Routeur NAT Linux (projet transversal)

flowchart LR
  VMweb["VM Web<br/>172.30.16.2"] --> R["VM Routeur<br/>eth1 172.30.16.1 | eth0 172.16.118.6"]
  VMbdd["VM BDD<br/>172.30.16.5"] --> R
  R -->|"MASQUERADE :<br/>source réécrite en 172.16.118.6"| LABO(("Réseau labo / Internet"))
# 1) Autoriser le transit des paquets
sudo sysctl -w net.ipv4.ip_forward=1                                  # immédiat
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-routeur.conf # permanent
# 2) NAT
sudo iptables -t nat -A POSTROUTING -s 172.30.16.0/24 -o eth0 -j MASQUERADE
# 3) Autoriser le transit
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A FORWARD -s 172.30.16.0/24 -j ACCEPT

Les VM internes doivent avoir le routeur comme passerelle (172.30.16.1).

Publier un service interne (DNAT / port forwarding)

# Tout ce qui arrive sur le port 8080 du routeur part vers le serveur web interne
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 172.30.16.2:80
sudo iptables -A FORWARD -p tcp -d 172.30.16.2 --dport 80 -j ACCEPT

Au projet, c’est HAProxy qui jouait ce rôle (reverse proxy) → SV03 - HAProxy (reverse proxy et répartition de charge).

Script complet

Fichier : scripts/securite/routeur_nat.sh - usage : sudo ./routeur_nat.sh eth0 eth1 172.30.16.0/24

#!/usr/bin/env bash
set -euo pipefail
interface_externe="$1"; interface_interne="$2"; reseau_interne="$3"
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-routeur.conf
sysctl --system > /dev/null
iptables -F; iptables -t nat -F; iptables -X
iptables -P INPUT DROP; iptables -P FORWARD DROP; iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i "$interface_interne" -o "$interface_externe" -s "$reseau_interne" -j ACCEPT
iptables -t nat -A POSTROUTING -s "$reseau_interne" -o "$interface_externe" -j MASQUERADE
netfilter-persistent save

Et scripts/securite/pare_feu_serveur.sh : ouvre automatiquement 80/443 si Apache tourne et 3306 si MariaDB tourne (fonction firewall du TP Linux B2).


5. La même chose en nftables (syntaxe moderne)

Fichier /etc/nftables.conf :

#!/usr/sbin/nft -f
flush ruleset
 
table inet filtre {
    chain entree {
        type filter hook input priority 0; policy drop;
        iif "lo" accept
        ct state established,related accept
        ip protocol icmp accept
        tcp dport { 22, 80, 443 } accept
    }
    chain transit {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ip saddr 172.30.16.0/24 oifname "eth0" accept
    }
}
 
table ip nat {
    chain sortie {
        type nat hook postrouting priority 100;
        ip saddr 172.30.16.0/24 oifname "eth0" masquerade
    }
}
sudo nft -c -f /etc/nftables.conf          # vérifier la syntaxe sans appliquer
sudo systemctl enable --now nftables        # appliquer et garder au démarrage
sudo nft list ruleset                       # afficher

6. ufw : le plus simple (Pop!_OS, Ubuntu)

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh                 # = 22/tcp
sudo ufw allow from 192.168.1.0/24 to any port 3306 proto tcp
sudo ufw enable
sudo ufw status numbered
sudo ufw delete 2

Sur Arch : sudo pacman -S ufw && sudo systemctl enable --now ufw.

Voir aussi