Pourquoi un conteneur Docker n’atteint pas les hôtes derrière le VPN
Les conteneurs en pont ont leur propre espace de noms, donc le tunnel de l’hôte leur est invisible. Comparez le réseau de l’hôte, un périphérique tun et macvlan avant de modifier le DNS.
Un conteneur qui n’atteint rien derrière le VPN d’entreprise vit généralement dans un espace de noms réseau différent de celui du tunnel. Les routes, les serveurs DNS et les marques du pare-feu du client de l’hôte appartiennent à la pile de l’hôte ; un conteneur en réseau pont a la sienne. Ce seul fait explique la plupart des signalements qui parviennent à une équipe plateforme, et c’est aussi pourquoi « le VPN est cassé » et « Docker contourne le VPN » peuvent être faux en même temps. Deux configurations très différentes se cachent derrière un symptôme, alors identifiez la vôtre avant de changer un réglage.
Déterminez à quel espace de noms appartient le tunnel
Sous Docker Desktop pour macOS ou Windows, les conteneurs s’exécutent dans une machine virtuelle Linux. Un client VPN installé sur le poste crée un tunnel dans le système d’exploitation du poste, et la machine virtuelle ne le voit jamais. Aucune configuration du conteneur n’y remédie, car l’interface dont le conteneur aurait besoin n’existe pas du tout dans son espace de noms réseau.
Sur un hôte Linux, le tunnel vit dans l’espace de noms de l’hôte, et les conteneurs en pont l’atteignent normalement via la table de routage de l’hôte avec du NAT source appliqué à la sortie. Quand ce chemin échoue, la cause est généralement une politique de transfert, un filtrage de chemin inverse ou un sous-réseau qui se chevauche plutôt qu’une route manquante. Confirmez dans lequel des deux mondes vous êtes avant de lire la suite :
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
La différence entre ces deux tables de routage, c’est tout le problème sur un seul écran. Si la vue de l’hôte contient l’interface du tunnel et que celle du pont non, vous regardez l’isolation des espaces de noms, et tout le reste est un choix sur la façon de la franchir.
Le réseau de l’hôte est un test, pas une conception
Exécuter un conteneur avec le réseau de l’hôte, que Docker documente comme un partage de l’espace de noms réseau de l’hôte, le fait hériter directement de l’interface du tunnel et de ses routes. Si la même requête réussit ensuite, la théorie des routes est confirmée et la panne est l’isolation des espaces de noms, non les identifiants, le DNS ou une règle d’accès.
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
Gardez-le comme diagnostic. Le réseau de l’hôte abandonne la publication de ports et la majeure partie de l’isolation que vous vouliez d’un conteneur, et sous Docker Desktop « host » désigne la machine virtuelle, pas le poste, donc un succès ou un échec à cet endroit peut vous induire en erreur si vous oubliez quel hôte vous adressiez.
Un périphérique tun et les privilèges qui vont avec
Un client VPN dans le conteneur a besoin d’un périphérique de tunnel et de l’autorisation de le configurer. Le raccourci courant est --privileged, qui accorde tous les périphériques et assouplit la politique de sécurité sur tout le conteneur. C’est bien plus que ce que demande cette tâche, et c’est difficile à justifier en revue.
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
La forme plus étroite mappe le nœud de périphérique unique et n’ajoute que la capacité d’administration réseau. Chargez d’abord le module sur l’hôte pour que le nœud existe. Si le conteneur démarre et que le client signale qu’il ne peut pas ouvrir le périphérique de tunnel, vérifiez le mappage avant de suspecter le profil, car cette erreur est généralement littérale.
Cette conception signifie aussi que le client s’exécute par conteneur. C’est la bonne réponse quand chaque charge de travail a besoin de son propre tunnel, et la mauvaise quand vous vouliez simplement que le tunnel de l’hôte soit visible, ce que l’équipe plateforme supposait probablement que vous faisiez.
Le NAT du pont change la source que voit le VPN
Avec le pont par défaut, le trafic sortant du conteneur est traduit vers l’adresse de l’hôte. Derrière un VPN, le côté entreprise voit donc l’adresse de tunnel de l’hôte et non celle du conteneur, les règles d’accès par source se comportent comme si l’hôte avait fait la requête, et deux conteneurs deviennent indistinguables pour le serveur VPN.
macvlan ou ipvlan donne au conteneur une adresse LAN à la place, ce qui aide la découverte sur le LAN et fait ressembler le conteneur à un pair sur le segment. Cela contourne aussi entièrement le tunnel de l’hôte, donc un tel conteneur n’atteindra pas les préfixes réservés au VPN à moins que le VPN soit aussi joignable depuis ce LAN.
Les deux formes sont légitimes ; elles répondent à des exigences différentes. Si l’exigence est « ce conteneur doit atteindre un service réservé au VPN », vous choisissez entre router via l’hôte et terminer le tunnel dans le conteneur. Notez ce choix avant le déploiement, pas après la première requête échouée. Quel que soit votre choix, consignez l’adresse source que verra l’extrémité distante, car c’est ce que montreront ses règles d’accès et ses journaux. Une conception qui ne peut pas énoncer cette adresse n’est pas terminée.
Le DNS suit le démon, pas le tunnel
Un conteneur reçoit sa configuration de résolveur au démarrage, copiée du démon ou de l’image. Les adresses que le VPN pousse après la connexion arrivent trop tard pour cette copie, et elles sont poussées vers le résolveur de l’hôte plutôt que dans le conteneur.
Définissez le résolveur explicitement pour le service, ou pointez-le vers un résolveur interne joignable via le tunnel. Un conteneur qui résout un nom privé en adresse publique utilise généralement un résolveur public, ne souffre pas d’une route cassée, et la correction appartient au fichier compose ou à la configuration du démon.
Le même raisonnement s’applique à la question de l’adresse de sortie. Si chaque conteneur doit apparaître depuis une adresse VPN différente, un seul tunnel d’hôte ne peut pas le fournir car le NAT les réduit à une seule source. Les formes viables sont un client dans l’espace de noms de chaque conteneur ou un sidecar qui possède le tunnel et partage sa pile, et les deux changent la façon dont l’application est adressée.
Liste de vérification avant de fermer le ticket : identifiez l’espace de noms qui possède le tunnel, prouvez le chemin avec le réseau de l’hôte, ne mappez que le périphérique tun nécessaire, retenez l’adresse source après le NAT, définissez le résolveur explicitement et traitez les adresses de sortie par conteneur comme une décision d’architecture et non comme un indicateur.