Publier un port de client VPN derrière CGNAT : liste de contrôle
Une règle NAT de destination seule donne des connexions à moitié ouvertes. Fixez l’adresse du tunnel, traduisez dans les deux sens et confirmez le chemin de la réponse avant de tester.
Placez un service sur un ordinateur portable derrière un NAT d’opérateur, dirigez cet ordinateur vers un VPS via un VPN, et personne à l’extérieur ne peut l’atteindre. Vous ajoutez une règle NAT de destination sur le VPS et obtenez pire que le silence : les connexions s’ouvrent, puis calent. La réponse ne manque pas, elle sort par la route par défaut du client lui-même, ce qui signifie que le serveur ne la voit jamais. Faites ces cinq vérifications dans l’ordre et arrêtez-vous à la première qui ne tient pas.
Confirmez que le serveur transmettra du tout
Cochez cette case avant d’écrire la moindre traduction. Une règle DNAT pour un paquet que le noyau refuse de transmettre est acceptée par l’analyseur de règles puis abandonnée par le chemin de transmission, ce qui produit un délai qui ressemble à un problème de pare-feu.
sysctl net.ipv4.ip_forward
sysctl -w net.ipv4.ip_forward=1
Le régler dans un noyau en cours d’exécution n’est pas la même chose que le régler au-delà d’un redémarrage. Écrivez net.ipv4.ip_forward=1 dans un fichier sous /etc/sysctl.d/, exécutez sysctl --system, puis relisez la valeur au lieu de croire que le fichier a été pris en compte. Un conteneur qui gère son propre espace de noms réseau a besoin de la même valeur à l’intérieur de cet espace, pas seulement sur l’hôte.
Si la relecture est toujours nulle, arrêtez-vous ici. Rien en aval ne fonctionnera.
Figez l’adresse du tunnel avant qu’une règle ne s’y réfère
Le pool distribue les adresses dans l’ordre des connexions, si bien qu’une règle écrite pour le bail du jour peut pointer discrètement vers un autre client la semaine prochaine. Liez l’adresse à l’identité du certificat plutôt qu’à l’ordre d’arrivée.
client-config-dir /etc/openvpn/ccd
ifconfig-push 10.77.0.14 10.77.0.13
Cette paire est l’extrémité client et l’extrémité pair d’un tunnel point à point, le serveur étant indexé sur le nom commun du certificat. Sous une topologie de sous-réseau, la seconde valeur est lue comme un masque de réseau à la place, écrivez donc la forme qui correspond à la topologie utilisée. Reconnectez ensuite le client et lisez l’adresse sur le client lui-même, car la vue du serveur sur le pool ne prouve pas ce que le client a configuré.
Si l’adresse change après une reconnexion, arrêtez-vous. Une règle NAT qui suit une cible mobile échouera par intermittence et ne vous apprendra rien.
Traduisez dans les deux sens
La traduction de destination envoie le paquet entrant au client. La traduction de source est ce qui pousse le client à répondre au serveur plutôt qu’à l’expéditeur d’origine, et c’est la règle que les gens oublient.
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 29443 -j DNAT --to-destination 10.77.0.14:29443
iptables -t nat -A POSTROUTING -d 10.77.0.14 -p tcp --dport 29443 -j SNAT --to-source 10.77.0.13
Sans la seconde règle, le client répond par sa liaison montante ISP, si bien que le pair distant voit une adresse source à laquelle il n’a jamais parlé, tandis que le serveur ne tient aucune entrée de suivi pour la réponse. L’observateur extérieur voit une poignée de main qui ne se termine qu’à moitié, et c’est exactement le symptôme qui envoie les gens chasser un bug de pare-feu qui n’existe pas.
Relisez les deux règles avec iptables -t nat -S et confirmez que le nom d’interface est celui qui porte l’adresse publique. Sur un hôte qui filtre déjà avec nftables, écrivez la traduction dans une chaîne NAT nftables de la famille d’adresses correspondante au lieu de mélanger les outils.
Laissez passer la table de filtrage
Les tables NAT réécrivent les en-têtes ; elles n’accordent pas la permission. Avec une politique DROP par défaut, le flux transmis a besoin de sa propre acceptation, plus le sens retour que la plupart des politiques couvrent déjà par une règle established,related.
iptables -A FORWARD -i eth0 -o tun0 -p tcp --dport 29443 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Vérifiez la politique de la chaîne FORWARD avant d’ajouter quoi que ce soit, car l’ordre d’un DROP précoce décide si votre règle sera seulement consultée. Sur un hôte dont le filtrage vit dans nftables, ajoutez la règle équivalente au hook forward de la table inet et confirmez que la chaîne de base voit réellement le trafic transmis et pas seulement l’entrée locale. Si un compteur de paquets de la nouvelle règle reste à zéro alors que les compteurs NAT montent, le paquet est abandonné avant votre règle. C’est le signal pour lire l’ordre des chaînes, pas pour ajouter une seconde copie de la même règle.
Prouvez-le depuis un réseau extérieur
Testez depuis un réseau sans rapport. Une sonde depuis une autre machine du même LAN peut passer par la prise en charge du NAT en épingle et n’exerce jamais le chemin qu’utilise un client distant, donc un résultat vert là-bas prouve la mauvaise chose.
tcpdump -ni any port 29443
conntrack -L | grep 29443
Lancez la capture sur le serveur et sur le client en même temps. La capture du serveur montre si le paquet traduit sort vers le tunnel ; celle du client montre si la requête arrive et où la réponse est adressée. Une entrée de traduction dans conntrack -L prouve que la règle a correspondu, et son absence prouve que le paquet n’a jamais atteint la chaîne NAT.
Les scanners de ports sont une preuve faible. Ils signalent le port comme fermé tant que l’application n’est pas liée et à l’écoute, utilisez donc une vraie connexion au vrai service. Quand cela fonctionne enfin, gardez l’exposition sur ce seul port : transmettre SSH ou un panneau d’administration parce que la première règle semblait gênante est une décision bien plus lourde que publier un service.