Les clients de deux serveurs OpenVPN peuvent-ils s’atteindre mutuellement ?
Deux serveurs OpenVPN créent deux pools de clients, pas un seul réseau. Routez entre eux avec des sous-réseaux distincts, des routes réciproques et une frontière de confiance explicite.
Monter un second OpenVPN serveur vous donne un second endroit où les clients peuvent se connecter, et rien de plus. Il ne place pas ces clients sur le réseau du premier serveur, et l’option nommée client-to-client ne change que le transfert à l’intérieur d’un seul processus serveur. Les deux pools deviennent un réseau lorsque vous routez entre eux délibérément, avec un responsable pour chaque sens. Tout ce qui suit suppose le mode TUN en espace utilisateur avec ce transfert interne désactivé, de sorte que le noyau prend la décision.
Le mythe : une liste de comptes, un réseau
Authentification et joignabilité se confondent parce que les deux vivent dans la configuration du serveur. Un utilisateur qui peut se connecter à l’une ou l’autre passerelle ressemble, vu de l’extérieur, à un utilisateur d’un seul système avec deux portes. À l’intérieur, chaque serveur distribue des adresses de son propre pool et n’installe des routes que pour les clients qu’il termine. Ainsi, un client de la passerelle A qui envoie un paquet à un client de la passerelle B demande une destination dont son propre serveur n’a jamais entendu parler. Le paquet part vers la route par défaut de A, quitte le tunnel et arrive à un pare-feu auquel on n’a jamais demandé de l’autoriser.
Ajouter un second serveur n’ajoute donc ni redondance, ni découverte, ni domaine de diffusion partagé. Cela ajoute un réseau routé qui demande un plan, et le plan commence par l’adressage.
Donnez à chaque passerelle son propre pool et une adresse de transit
Deux plages qui ne peuvent chevaucher rien d’autre, plus une petite liaison de transit entre les hôtes, constituent tout le plan d’adressage. Gardez le transit sur un segment privé que vous contrôlez, et notez les chiffres avant qu’un serveur ne distribue un bail.
| Gateway | Client pool | Transit address |
|---|---|---|
| gateway-a | 10.64.10.0/24 | 172.28.44.1/30 |
| gateway-b | 10.64.20.0/24 | 172.28.44.2/30 |
Résistez à la tentation de donner le même pool aux deux serveurs pour que les profils restent identiques. Une route du noyau ne peut pas dire lequel de deux hôtes possède actuellement une adresse arbitraire dans une plage partagée, donc la table de routage pointerait vers une passerelle et le client pourrait être rattaché à l’autre. Les noms d’interface sont des conventions locales, pas un état partagé. Les deux hôtes ici appellent l’appareil de tunnel tun0 et la liaison de transit transit0, ce qui va bien car aucun paquet ne porte ces noms.
Installez la route des deux côtés
Chaque passerelle a besoin d’une route vers le pool de l’autre via l’adresse de transit, et le transfert doit être actif pour que l’une ou l’autre serve de saut. Confirmez d’abord la table actuelle, puis ajoutez l’entrée et rendez-la persistante via le gestionnaire réseau de l’hôte plutôt qu’un crochet de reconnexion.
sysctl net.ipv4.ip_forward
ip route add 10.64.20.0/24 via 172.28.44.2 dev transit0
ip route get 10.64.20.37
Reproduisez cela sur l’autre hôte avec les pools inversés. Ajouter sans cesse la même route depuis un script sans rapport est la façon dont un hôte finit avec plusieurs copies et un changement mystérieux la prochaine fois que quelqu’un lit la table. Si la liaison de transit est elle-même un tunnel, la route pointe vers la topologie de ce tunnel et le saut doit survivre à sa reconnexion. Une adresse de transit qui disparaît pendant trente secondes emporte le chemin entre les pools, ce qui est une propriété de conception qu’il vaut mieux énoncer que découvrir.
Poussez la route du client sans feindre la propriété
Les clients ont besoin d’une route vers le pool distant, sinon leur propre système d’exploitation envoie le paquet à sa passerelle par défaut et le tunnel ne le voit jamais. La configuration du serveur est l’endroit naturel pour la fournir.
push "route 10.64.20.0 255.255.255.0"
Placez la ligne miroir dans la configuration de l’autre serveur, puis reconnectez un client de test et lisez sa table. Un client qui ignore les routes poussées a besoin de sa propre configuration approuvée, et une route qui n’arrive jamais n’est pas un contrôle d’accès. Ne donnez pas à un client un iroute pour tout le pool de l’autre passerelle. Cette directive existe pour un sous-réseau derrière un client connecté, et l’utiliser pour masquer une route manquante entre passerelles produit un serveur qui croit posséder des adresses qu’il ne peut pas atteindre.
Prouvez une requête et refusez-en une autre
Choisissez une opération réelle, par exemple HTTPS depuis un client à 10.64.10.21 vers un service à 10.64.20.37, et autorisez exactement cela sur les deux hôtes. Chaque pare-feu admet la requête côté entrant et la réponse suivie côté retour ; la politique de service de la destination doit encore l’accepter.
iptables -A FORWARD -i tun0 -o transit0 -s 10.64.10.21 -d 10.64.20.37 -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i transit0 -o tun0 -d 10.64.10.21 -s 10.64.20.37 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
Avec des routes réciproques, le NAT source est inutile et ici activement nuisible : traduire la source cache quel client a fait la requête et ruine la politique fondée sur la source côté destination. Vérifiez qu’une règle de masquerade existante pour la sortie internet n’attrape pas aussi ce chemin. Testez ensuite le refus. Un service qui doit rester local au pool B doit rester injoignable depuis le pool A, et les paires de clients d’une même passerelle doivent aussi être testées, puisque la politique de transfert que vous venez de changer s’applique à eux aussi.
Encore une correction du modèle mental : la liaison de transit transporte des paquets internes déchiffrés, c’est donc une frontière de confiance et non une garantie privée. Si elle traverse un réseau que vous ne contrôlez pas, protégez ce saut avec un tunnel chiffré approuvé et routez via sa topologie réelle. TLS de bout en bout authentifie toujours l’application de son côté, et c’est pourquoi le service interne doit continuer à l’utiliser.