Aller au contenu

Pare-feu : UFW et Docker

Sur une machine qui utilise Docker et UFW, un port publié par un conteneur reste joignable depuis Internet même si UFW l’interdit. Les exemples utilisent des noms génériques (web, port 8080).

Fenêtre de terminal
sudo ufw default deny incoming
docker run -d --name web -p 8080:80 nginx:alpine

Le port 8080 n’est pas autorisé dans UFW, mais curl http://serveur.exemple.com:8080/ depuis une autre machine répond.

Docker écrit ses propres règles iptables (chaînes DOCKER et DOCKER-USER) pour la traduction d’adresses et le transfert vers le conteneur. Le trafic publié passe par la chaîne FORWARD, avant les règles d’UFW qui filtrent le trafic destiné à la machine elle-même. Docker Compose se comporte de la même façon.

Fenêtre de terminal
docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpine

Dans compose.yaml :

services:
web:
image: nginx:alpine
ports:
- '127.0.0.1:8080:80'

Un reverse proxy installé sur l’hôte (Caddy, Nginx) écoute sur 80 et 443, que UFW gère normalement, et transmet vers 127.0.0.1:8080 (voir Exemple : VPS avec Caddy).

Les conteneurs d’un même réseau Docker se joignent par leur nom. Seul le service public publie un port :

services:
app:
image: monapp:1.0 # pas de « ports: »
proxy:
image: caddy:2
ports:
- '80:80'
- '443:443'

Docker évalue la chaîne DOCKER-USER avant ses propres règles et ne l’écrase pas : c’est l’endroit prévu pour filtrer le trafic transféré vers les conteneurs.

Fenêtre de terminal
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 8080 ! -s 198.51.100.7 -j DROP
sudo iptables -S DOCKER-USER

Cette règle refuse le port 8080 depuis l’interface publique eth0, sauf pour une adresse. Elle ne survit pas au redémarrage : la rendre persistante (par exemple dans /etc/ufw/after.rules ou avec iptables-persistent). Une règle trop large coupe aussi l’accès des conteneurs à Internet.

Le projet tiers ufw-docker ajoute à /etc/ufw/after.rules un bloc qui filtre le trafic vers Docker et permet d’écrire des règles par conteneur (ufw-docker allow web 80/tcp). Lire son script avant de l’installer.

{ "iptables": false } dans /etc/docker/daemon.json empêche Docker de modifier le pare-feu, mais supprime aussi le NAT et la publication de ports : déconseillé.

Toujours depuis une autre machine :

Fenêtre de terminal
nc -vz -w 3 serveur.exemple.com 8080
nmap -Pn -p 8080,3306,5432,6379,27017 serveur.exemple.com

Sur le serveur :

Fenêtre de terminal
docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -tlnp | grep docker-proxy
Colonne PORTS Accessible depuis
127.0.0.1:8080->80/tcp La machine elle-même
0.0.0.0:8080->80/tcp Toutes les interfaces, donc Internet
[::]:8080->80/tcp Idem en IPv6

docker run -p 5432:5432 postgres ou -p 6379:6379 redis ouvre la base à Internet. Publier sur 127.0.0.1 (-p 127.0.0.1:5432:5432) ou ne pas publier, et activer l’authentification.

Symptôme Piste
Un port « interdit » répond Port publié par Docker : docker ps, publier sur 127.0.0.1
Conteneurs sans Internet après une règle DOCKER-USER Règle trop large : sudo iptables -D DOCKER-USER …
Règles DOCKER-USER perdues au redémarrage Les rendre persistantes

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Même comportement sur les deux versions (UFW 0.36.2, iptables-nft). Voir aussi Docker : réseau.