Imaginez un hôte Linux qui termine un VPN et exécute aussi un conteneur sur un réseau macvlan. Le LAN est 192.168.60.0/24, le conteneur détient 192.168.60.210, et les clients VPN arrivent depuis 10.95.0.0/24. Le client atteint le service, la réponse ne revient jamais, et chaque règle de pare-feu sur l’hôte semble correcte. Deux contraintes distinctes produisent ce symptôme, et corriger l’une laisse l’autre en place.

Deux contraintes, un symptôme

La première contrainte est l’isolation : le pilote macvlan de Docker ne permet pas à un conteneur de parler à son propre hôte via l’interface parente. Le trafic entre la pile de l’hôte et le conteneur n’a aucun chemin, quelle que soit la façon dont les routes de l’hôte sont écrites.

La seconde contrainte est le chemin de retour. La passerelle par défaut du conteneur est généralement le routeur du LAN, si bien qu’une réponse adressée à un client VPN sort par ce routeur. Si le routeur n’a pas de route de retour vers le pool VPN, la réponse est abandonnée quelque part au milieu.

Les deux pannes se ressemblent du point de vue du client : une requête qui arrive et une réponse qui n’arrive jamais. Elles demandent des réparations différentes, et une règle de masquerade large peut masquer laquelle des deux est encore cassée. C’est pourquoi le premier test est une capture côté conteneur plutôt qu’une nouvelle modification du pare-feu. Si la requête n’y apparaît jamais, c’est la contrainte d’isolation qui est en cause.

Construisez le shim côté hôte, de façon étroite

Une seconde interface macvlan sur l’hôte, rattachée au même parent en mode pont, donne à la pile de l’hôte sa propre identité sur ce segment du LAN. Réservez-lui une adresse hors du pool DHCP et hors de la plage du conteneur, et n’acheminez que le conteneur à travers elle.

ip link add macvlan-vpn link eth0 type macvlan mode bridge
ip address add 192.168.60.250/32 dev macvlan-vpn
ip link set macvlan-vpn up
ip route add 192.168.60.210/32 dev macvlan-vpn src 192.168.60.250

La première commande crée l’interface en mode pont, qui est la valeur par défaut documentée pour ce pilote et le mode que vous voulez pour le trafic entre hôte et conteneur. La deuxième attribue un /32 pour que l’adresse n’entre pas en collision avec le préfixe du LAN, et la quatrième n’envoie que l’adresse du conteneur à travers le shim.

Ne redirigez pas tout le LAN à travers la nouvelle interface. La route connectée ordinaire reste telle quelle, et la route de l’hôte est délibérément étroite pour qu’un conteneur gagne un chemin sans que le reste du segment change de comportement. Une route par défaut pointant vers le shim serait une autre conception avec d’autres conséquences. Gardez-la précise et le rayon d’impact reste faible.

Ces commandes modifient la configuration réseau d’un hôte en production. Sur un appareil ou une plateforme gérée, utilisez le mécanisme de configuration pris en charge par cette plateforme, car une modification interactive dans un shell root peut ne pas survivre à une mise à jour.

Décidez comment la source est préservée

Une fois le shim en place, le conteneur peut atteindre l’hôte, et la question devient quelle adresse source porte la réponse. Préserver la source VPN d’origine est le modèle le plus propre : le conteneur voit la vraie adresse du client, et les journaux et règles d’accès du service peuvent l’utiliser.

Pour que cela fonctionne, la configuration réseau du conteneur doit, pour ce chemin, envoyer le trafic de 10.95.0.0/24 vers 192.168.60.250 comme passerelle. C’est un réglage de route ou de passerelle pris en charge dans la configuration du conteneur lui-même, pas une astuce côté hôte. Confirmez-le depuis l’intérieur du conteneur plutôt que de supposer que le réglage a pris effet. Une passerelle par défaut qui pointe encore vers le routeur du LAN continuera d’envoyer les réponses dans le même trou.

Si la conception approuvée masque plutôt les sources VPN, limitez la traduction de façon étroite : le pool VPN réel, le shim comme interface de sortie, et le conteneur et le service précis.

iptables -t nat -A POSTROUTING -s 10.95.0.0/24 -o macvlan-vpn -j SNAT --to-source 192.168.60.250

Faites correspondre le shim comme interface de sortie, pas le tunnel. Une règle qui nomme le tunnel comme interface de sortie ne correspondra pas à un paquet allant vers le conteneur, et c’est l’erreur que ce genre de montage contient habituellement. Gardez la règle aussi étroite que la phrase ci-dessus et révisez-la lorsque le pool change.

Vérifiez depuis le client, pas depuis l’hôte

Une requête depuis l’hôte lui-même, liée à l’adresse du shim, prouve que le shim peut atteindre le conteneur. Elle ne prouve pas que le conteneur peut renvoyer du trafic vers une source préservée 10.95.0.x, car l’adresse source de ce test est celle du shim lui-même.

curl -sS --interface 192.168.60.250 -o /dev/null -w '%{http_code}\n' http://192.168.60.210:8080/health
sudo tcpdump -ni macvlan-vpn host 192.168.60.210

La première commande teste le tronçon de l’hôte au conteneur, et la seconde montre ce qui traverse réellement le shim pendant qu’un vrai client VPN fait la requête. Regardez l’adresse source à l’entrée et si une réponse apparaît avec le même flux.

Le transfert doit être activé sur l’hôte, et le chemin de transfert a besoin d’une autorisation pour le pool VPN vers le shim sur le port du service, plus les réponses établies. Une règle INPUT sur l’hôte n’autorise pas le trafic transféré, ce qui est une raison fréquente pour laquelle le paquet est abandonné alors que le routage semble correct.

Exécutez la vraie application avec de vrais identifiants, puis vérifiez qu’un second service sans rapport sur le même conteneur vous refuse toujours. Si le seul moyen de le faire fonctionner était d’ouvrir toutes les règles de transfert, la conception n’est pas terminée. Notez aussi quelle adresse source le service a enregistrée, car c’est celle que ses propres règles d’accès utiliseront désormais.

Articles similaires