Deux problèmes de noms apparaissent sur presque chaque petite passerelle OpenVPN. Vous ne pouvez pas joindre un portable connecté par le nom de son certificat, et les services derrière le tunnel n’ont aucun nom. Ils ressemblent à un seul problème et demandent des traitements opposés, car une adresse bouge à chaque session et l’autre non. Décidez quel type de nom vous ajoutez avant de modifier quoi que ce soit.

Décidez par nom, pas par passerelle

Le test est simple : cette adresse change-t-elle quand un client se reconnecte ? Si oui, le nom doit être généré depuis la session VPN. Si non, il appartient à une entrée statique que vous pouvez lire et relire.

Name kindSource of truthWhere it lives
Connected clientThe address OpenVPN just assignedGenerated hosts file, rewritten per session
Service behind the tunnelA fixed address you choseStatic address= drop-in
Anything with a certificate nameThe certificate, not the poolEither, but the name must match the certificate

Les mélanger est l’échec habituel. Un service figé dans le fichier généré disparaît la première fois que le script le réécrit, et un client écrit dans une entrée statique pointe vers celui qui détenait cette adresse en dernier. Les deux erreurs restent invisibles jusqu’à ce qu’un nom se résolve vers la mauvaise machine. D’ici là, la personne qui débogue suppose que le DNS est cassé et non le fichier.

La voie dynamique : learn-address et le pool

OpenVPN connaît l’attribution, alors laissez-le vous la dire. Ces options de serveur rendent l’attribution durable et scriptable :

client-config-dir /etc/openvpn/ccd
ifconfig-pool-persist /etc/openvpn/ip-pool 60
script-security 2
learn-address /etc/openvpn/learn-address.sh

learn-address exécute votre script chaque fois qu’une adresse est ajoutée, mise à jour ou supprimée, et transmet l’opération, l’adresse et le nom commun. Un script minimal ajoute une ligne par client et la retire à la suppression :

#!/bin/sh
HOSTS=/etc/openvpn/hosts.lan
case "$1" in
  add|update) echo "$2 $3" >> "$HOSTS" ;;
  delete)     sed -i "/^$2 /d" "$HOSTS" ;;
esac
kill -HUP $(cat /var/run/dnsmasq.pid)

Sur un périphérique tun, le deuxième argument est l’adresse de tunnel du client, la ligne est donc directement utilisable. Sur un périphérique tap, OpenVPN transmet à la place l’adresse MAC du client, car un segment tap peut transporter d’autres protocoles qu’IPv4, et il faut alors chercher l’adresse dans le fichier du pool par le nom commun avant d’écrire quoi que ce soit.

Soyez clair sur ce qu’est le fichier généré : un instantané de qui est connecté maintenant. Les noms disparaissent à la déconnexion, ce qui est exactement ce que vous voulez pour des portables qui passent d’un réseau à l’autre et exactement ce que vous ne voulez pas pour un serveur allumé toute la nuit.

La voie statique : address= et expansion de domaine

Pointez dnsmasq vers le fichier généré au lieu du fichier hosts du système, et donnez-lui un domaine pour que les noms courts s’étendent en noms pleinement qualifiés :

domain=corp.example
no-hosts
addn-hosts=/etc/openvpn/hosts.lan
listen-address=127.0.0.1,10.8.0.1
bind-interfaces

Avec domain défini, une ligne comme 10.8.0.6 alice répond à la fois pour alice et pour alice.corp.example. Gardez listen-address sur la passerelle du tunnel et le loopback, car un résolveur publié par accident sur l’interface LAN est un service que vous ne vouliez pas offrir.

Les services qui ne viennent jamais du pool ont leurs propres entrées. Placez-les dans un fichier drop-in séparé dans le répertoire de configuration de la distribution pour qu’une mise à jour de paquet ne puisse pas les écraser :

address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5

Transmettez le résolveur, sinon rien ne se passe

Un résolveur que personne n’interroge ne change rien. Le serveur doit l’annoncer :

push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"

Les clients Windows appliquent eux-mêmes les deux options. La plupart des clients Linux ne le font pas : ils ont besoin d’une intégration de résolveur prise en charge, comme le crochet update-resolv-conf de la distribution ou la gestion DNS de NetworkManager, ou d’un domaine de recherche et d’un serveur de noms manuels. Vérifiez le résolveur réel du client au lieu de supposer que le push a été respecté, car un push ignoré ressemble exactement à un serveur qui ne répond pas.

Vérifiez à trois niveaux

Interrogez d’abord le serveur directement, puis un client, puis l’application :

dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example

Si les requêtes directes répondent et que l’application non, la faute vient de la transmission au client et non de la zone. Si le nom se résout et que la connexion échoue encore, le nom est correct et il faut regarder ensuite la route ou le pare-feu.

Notez les deux catégories à côté de la configuration : quels noms sont générés, lesquels sont figés et à quel certificat chacun doit correspondre. La prochaine personne qui ajoute un serveur copiera le premier modèle qu’elle trouve.

Articles similaires