Bonjour,
Auto-réponse, pour la satisfaction de passer le sujet en résolu et pour le cas (bien improbable si j'en crois le peu de matière que j'ai trouvé lors de mes recherches) où quelqu'un rencontrerait ce problème.
Je résume la problématique, qui est en fait liée à l'utilisation d'un
bridge ethernet.
Pour isoler ses containers, Docker crée directement ses propres règles dans iptables (
https://docs.docker.com/network/iptables/). Si l'on n'utilise pas iptables, cela ne pose pas de problème particulier, pas même avec OpenVPN en situation classique client-serveur.
En revanche, si iptables est déjà configuré avec des règles personnalisées, celles ajoutées par Docker peuvent perturber le fonctionnement. Je ne m'étends pas là-dessus, d'abord parce que ce n'est pas mon cas (je n'ai pas de règle personnalisée dans iptables), et ensuite par incompétence (ceux qui ont des règles personnalisées dans iptables maîtrisent cela bien mieux que moi, et ont probablement déjà rencontré et réglé ce problème avec Docker).
Mon problème vient que je n'utilise pas OpenVPN en situation client-serveur, mais en configuration site-à-site : pour que les postes de la maison, qui sont derrière le serveur VPN, communiquent avec ceux qui sont derrière le client VPN (et inversement, de manière finalement à ce que tous participent au même grand LAN), j'utilise, sur le serveur et sur le client, un pont ethernet (
https://openvpn.net/community-resources/ethernet-bridging/). En gros, le pont ethernet est une interface virtuelle qui rassemble l'interface physique (réellement branchée au LAN) et l'interface VPN (interface elle-même virtuelle créé par OpenVPN lors de la connexion) : les deux interfaces regroupées en pont perdent leurs paramètres IP individuels (adresses, masques, etc.) et c'est le pont qui dispose d'une unique adresse IP, recevant et
relayant ainsi à la fois les communications qui viennent du LAN et celles qui viennent du VPN.
Je souligne
relayant, parce que c'est de là que venait mon problème. Le pont fonctionnant au niveau 2 du modèle OSI, je n'imaginais pas que son fonctionnement pût être perturbé par iptables (qui est au niveau 3). Sauf que voilà :
https://serverfault.com/questions/162366/iptables-bridge-and-forward-chain/162384#162384 ! À l'intérieur du pont, il faut bien que les communications du niveau 3 passent du LAN au VPN, et donc les règles d'iptables leur sont appliquées.
Or on a vu que Docker passe sur DROP la politique par défaut de la chaîne FORWARD, qui traite les paquets passant d'une interface à une autre : donc les paquets, même à l'intérieur du pont, n'ont plus le droit de passer de l'interface LAN à l'interface VPN, et
vice-versa. Ça se voit très bien en enregistrant dans le journal système les paquets bloqués dans la chaîne FORWARD (
https://tecadmin.net/enable-logging-in-iptables-on-linux/) :
IN=br0 OUT=br0 PHYSIN=enp6s0 PHYSOUT=tap0 MAC=XX:XX:XX:XX:XX:XX SRC=192.168.10.17 DST=224.0.0.252 LEN=52 TOS=0x00 PREC=0x00 TTL=1 ID=23331 PROTO=UDP SPT=59543 DPT=5355 LEN=32
Le pont
br0 est à la fois l'interface d'entrée et l'interface de sortie mais, à l'intérieur, on voit bien que le paquet vient de l'interface LAN et va vers l'interface VPN ; en comme je n'ai pas de règle dans la chaîne FORWARD pour permettre cela, la politique DROP mise en place par Docker rejette le paquet. J'ai donc dû créer une règle dans la chaîne FORWARD pour permettre, à l'intérieur du pont, toutes les communications entre les interfaces regroupées.
Pour être certain que cette règle soit traitée avant celles de Docker, il faut l'ajouter dans la chaîne utilisateur DOCKER-USER, qui n'est pas effacée quand Docker redémarre (
https://blog.donnex.net/docker-and-iptables-filtering/). Donc, dans le script qui crée le pont (rassemble les interfaces) lors du démarrage d'OpenVPN, j'ai ajouté :
iptables -I DOCKER-USER 1 -i br0 -o br0 -j ACCEPT
Ce qui donne, après démarrage d'OpenVPN :
$ sudo iptables -L -v -n
Chain INPUT (policy ACCEPT 252K packets, 208M bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.10.61 tcp dpt:58051
0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.10.61 tcp dpt:58050
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1342K 1151M DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
893 189K DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT 261K packets, 162M bytes)
pkts bytes target prot opt in out source destination
Chain DOCKER (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:9980
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.3 tcp dpt:443
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
pkts bytes target prot opt in out source destination
0 0 DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
893 189K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
Chain DOCKER-ISOLATION-STAGE-2 (1 references)
pkts bytes target prot opt in out source destination
0 0 DROP all -- * docker0 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
Chain DOCKER-USER (1 references)
pkts bytes target prot opt in out source destination
362K 308M ACCEPT all -- br0 br0 0.0.0.0/0 0.0.0.0/0
893 189K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
Attention à l'option
-I (i majuscule) dans la commande iptables : si on utilise
-A, la règle est ajoutée à la fin de la chaîne DOCKER-USER, après la règle RETURN, et n'est donc jamais traitée.
Toujours par acquit de conscience, et aussi pour éviter que la règle soit insérée une deuxième fois en cas de redémarrage d'OpenVPN, j'ai ajouté dans le script qui supprime le pont à l'arrêt du service :
iptables -D DOCKER-USER 1
Mais si j'ai bien compris, ça fonctionne parce que cela supprime la ligne 1 de la chaîne DOCKER-USER : je ne sais pas traiter le cas où, entre-temps, on aurait inséré une nouvelle règle en ligne 1...
Blue Duck