Pare-feu avec FirewallD sur un serveur Debian 13
FirewallD est un système de pare-feu principalement utilisé sur les systèmes Fedora et Red Hat Enterprise Linux et toutes les distributions dérivées de cette dernière comme Rocky Linux, AlmaLinux et Oracle Linux. On le trouve également sur d'autres distributions comme OpenSUSE et Debian.
FirewallD est un frontal à nftables relativement simple à manipuler. Il est
bien documenté dans la littérature imprimée et un peu partout sur le web. Je
ne vais donc pas réinventer la roue et vous concocter un cours magistral sur
FirewallD. Au lieu de cela, je vais reprendre les trois cas pratiques présentés
dans mon précédent article sur la configuration du réseau et procéder à la
configuration de base du pare-feu pour chacun d'entre eux.
Différents chemins mènent à Saint-Bauzille-de-Putois
La distribution Debian vous laisse le choix pour configurer un pare-feu. La
solution la plus populaire consiste à utiliser ufw (Uncomplicated
Firewall). Les gourous de l'administration système éditent directement
leur propre litanie de règles nftables. Pour ma part, j'ai choisi
FirewallD pour la simple raison que j'ai longtemps travaillé avec les
systèmes de la famille Red Hat et que je suis passablement familiarisé avec
cette solution.
Installation
FirewallD est fourni par les dépôts de paquets officiels de Debian :
La mise en service se fait automatiquement sur un système Debian :
$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled;
preset: enabled)
Active: active (running) since Fri 2026-01-30 08:43:36 CET; 44s ago
Invocation: 47a0c3b66bf24fab8f986eacad28cb0d
Docs: man:firewalld(1)
Process: 17734 ExecStartPost=/usr/bin/firewall-cmd --state (code=exited,
status=0/SUCC>
Main PID: 17708 (firewalld)
Tasks: 2 (limit: 4634)
Memory: 34.7M (peak: 57.9M)
CPU: 2.435s
CGroup: /system.slice/firewalld.service
└─17708 /usr/bin/python3 /usr/sbin/firewalld --nofork --nopid
Configuration de base
Dans cet article, nous allons nous concentrer uniquement sur la configuration de base de FirewallD. Qu'est-ce que j'entends par là ?
-
Associer les interfaces réseau aux zones appropriées. Une zone est une collection de règles de pare-feu associées à un certain contexte. FirewallD fournit toute une série de zones prédéfinies.
-
Supprimer quelques services prédéfinis comme
dhcpv6-client,mdnsousamba-client. -
Autoriser le seul service
sshcomme point de départ.
Ouvrir et/ou rediriger les ports
L'ouverture et/ou la redirection des ports sera traitée au fur et à mesure dans les articles sur les services correspondants.
Dans les trois exemples pratiques ci-dessous, je vais aller du plus simple au plus complexe.
FirewallD sur un serveur dédié
La configuration de base de FirewallD sur un serveur dédié avec une ouverture frontale sur Internet est relativement simple. C'est pour cette raison que je vous la présente en premier.
Dans la configuration par défaut, c'est la zone public qui est active sans
pour autant être associée à une quelconque interface réseau :
$ sudo firewall-cmd --list-all
public (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Voici la configuration réseau de ma machine :
J'associe l'interface enp1s0 à la zone public :
Je prends en compte les modifications :
Et voilà le résultat :
$ sudo firewall-cmd --list-all
public (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Je supprime le service dhcpv6-client :
$ sudo firewall-cmd --permanent --remove-service=dhcpv6-client
success
$ sudo firewall-cmd --reload
success
À présent il ne me reste plus que le seul service ssh :
$ sudo firewall-cmd --list-all
public (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Je vérifie depuis une machine externe :
$ sudo nmap sd-150204.dedibox.fr
Starting Nmap 7.95 ( https://nmap.org ) at 2026-01-30 09:08 CET
Nmap scan report for sd-150204.dedibox.fr (195.154.114.174)
Host is up (0.016s latency).
rDNS record for 195.154.114.174: 195-154-114-174.rev.poneytelecom.eu
Not shown: 980 filtered tcp ports, 19 filtered tcp ports
PORT STATE SERVICE
22/tcp open ssh
Nmap done: 1 IP address (1 host up) scanned in 14.61 seconds
FirewallD sur un serveur local
La distinction entre un serveur dédié avec une adresse IP publique et une
machine locale derrière un routeur est purement pragmatique. En théorie, nous
pourrions très bien appliquer la même configuration que dans l'exemple
ci-dessus. En pratique, j'aime bien faire la distinction et utiliser la zone
internal pour ce genre de configuration.
La pertinence de cette distinction apparaîtra plus clairement dans le dernier exemple de cet article.
FirewallD est installé, et le service correspondant est lancé. Je jette un œil
sur la configuration par défaut de la zone internal :
$ sudo firewall-cmd --list-all --zone=internal
internal
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: dhcpv6-client mdns samba-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Voici la configuration réseau de la machine :
Je définis la zone internal par défaut en lui associant l'interface réseau
enp3s0 :
$ sudo firewall-cmd --set-default-zone=internal
success
$ sudo firewall-cmd --permanent --zone=internal --change-interface=enp3s0
success
$ sudo firewall-cmd --reload
success
Je vérifie le résultat de l'opération :
$ sudo firewall-cmd --list-all
internal (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp3s0
sources:
services: dhcpv6-client mdns samba-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Je supprime une poignée de services prédéfinis pour cette zone :
$ sudo firewall-cmd --permanent --remove-service=dhcpv6-client
success
$ sudo firewall-cmd --permanent --remove-service=mdns
success
$ sudo firewall-cmd --permanent --remove-service=samba-client
success
$ sudo firewall-cmd --reload
success
Là encore, je n'ai gardé que le seul service ssh :
$ sudo firewall-cmd --list-all
internal (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp3s0
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Je vérifie depuis une autre machine du réseau :
$ sudo nmap sandbox.microlinux.lan
Starting Nmap 7.95 ( https://nmap.org ) at 2026-01-30 10:04 CET
Nmap scan report for sandbox.microlinux.lan (192.168.2.3)
Host is up (0.00036s latency).
Not shown: 989 filtered tcp ports, 10 filtered tcp ports
PORT STATE SERVICE
22/tcp open ssh
MAC Address: B0:83:FE:90:4D:64 (Dell)
Nmap done: 1 IP address (1 host up) scanned in 5.24 seconds
FirewallD sur un routeur
Sur mon routeur local, les choses se compliquent un tout petit peu. Là aussi, FirewallD est installé, et le service correspondant est activé. Voici la configuration réseau de la machine :
J'affiche la configuration par défaut de la zone external :
$ sudo firewall-cmd --list-all --zone=external
external
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Dans un premier temps, j'associe l'interface enp1s0 à la zone
external :
$ sudo firewall-cmd --permanent --zone=external --change-interface=enp1s0
success
$ sudo firewall-cmd --reload
success
Je vérifie :
$ sudo firewall-cmd --list-all --zone=external
external (active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
L'interface enp2s0 sera associée à la zone internal. Cette zone sera
définie comme la zone par défaut :
$ sudo firewall-cmd --permanent --zone=internal --change-interface=enp2s0
success
$ sudo firewall-cmd --set-default-zone=internal
success
$ sudo firewall-cmd --reload
success
Voilà ce que ça donne :
$ sudo firewall-cmd --list-all
internal (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp2s0
sources:
services: dhcpv6-client mdns samba-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Au passage, je désactive les services que je n'utilise pas :
$ sudo firewall-cmd --permanent --remove-service=dhcpv6-client
success
$ sudo firewall-cmd --permanent --remove-service=mdns
success
$ sudo firewall-cmd --permanent --remove-service=samba-client
success
$ sudo firewall-cmd --reload
success
Je vérifie :
$ sudo firewall-cmd --list-all
internal (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp2s0
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Configurer le relais des paquets
Maintenant que j'ai mis en place la configuration de mes deux zones, il me faut
activer le relais des paquets (IP Masquerading). Concrètement, cela veut dire
que les paquets IP du réseau 192.168.3.0/24 doivent pouvoir transiter vers le
réseau 192.168.2.0/24.
Le relais des paquets n'est pas activé par défaut sur un système Debian. Je
vais donc éditer un fichier /etc/sysctl.d/ip-forwarding.conf à cet
effet :
J'active ce nouveau paramètre :
Dans la configuration par défaut, la zone external permet déjà le relais des
paquets :
$ sudo firewall-cmd --list-all --zone=external
external (active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: ssh
ports:
protocols:
forward: yes
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Il nous reste à définir une politique pour autoriser le trafic entre les zones
internal et external. Voici à quoi ça ressemble :
$ sudo firewall-cmd --permanent --new-policy=router
success
$ sudo firewall-cmd --permanent --policy=router --add-ingress-zone=internal
success
$ sudo firewall-cmd --permanent --policy=router --add-egress-zone=external
success
$ sudo firewall-cmd --permanent --policy=router --set-target=ACCEPT
success
$ sudo firewall-cmd --reload
success
Autoriser le trafic entre les zones
FirewallD requiert ce genre d'autorisation explicite du trafic entre les zones depuis la version 1.0. Dans les versions antérieures, ce trafic était autorisé par défaut. Étant donné qu'avant de migrer mes machines vers Debian, j'utilisais FirewallD 0.9 sur des systèmes Red Hat, j'ai passé une bonne journée à m'arracher les cheveux en me demandant ce qui pouvait bien bloquer mes paquets entre les deux réseaux. J'ai fini par trouver la réponse dans la documentation de Arch Linux. Ce genre de surprise fait partie de notre métier.
J'affiche les détails de cette nouvelle politique :
$ sudo firewall-cmd --info-policy=router
router (active)
priority: -1
target: ACCEPT
ingress-zones: internal
egress-zones: external
services:
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Pour tester le relais des paquets, je me connecte à un client dans le réseau
192.168.3.0/24 :
Tester le relais des paquets
Pour l'instant je n'ai pas encore installé Dnsmasq sur le routeur. Pour tester le relais des paquets, je me sers provisoirement d'un poste client avec une configuration réseau statique.
Pour finir, j'essaie d'envoyer successivement un ping sur les deux
réseaux :
$ ping -c 1 -q 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
--- 192.168.3.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.352/0.352/0.352/0.000 ms
$ ping -c 1 -q 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
--- 192.168.2.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.986/0.986/0.986/0.000 ms
Documentation
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.

