Hook client-connect d'OpenVPN : où va réellement votre adresse
Un script client-connect ne peut pas renvoyer une adresse en l'imprimant. Voyez comment le fichier temporaire du hook, le code de sortie et la topologie décident de l'IP du client.
Renvoyer une adresse depuis un script client-connect semble devoir définir l'IP du client. Ce n'est pas le cas : le seul canal du hook vers le serveur est un fichier temporaire dont le chemin arrive comme dernier argument du script, et l'adresse doit y être écrite avec la syntaxe de ifconfig-push. Un script qui affiche l'adresse ou se termine avec zéro sans rien écrire produit un client connecté avec une adresse issue du pool, et le journal du serveur semble parfaitement sain.
La confusion est raisonnable, car plusieurs autres hooks répondent bel et bien par des codes de sortie ou des variables d'environnement. Celui-ci a son propre contrat, et le contrat commence par un nom de fichier.
Le hook écrit un fichier, pas une valeur de retour
La déclaration tient en deux lignes : script-security 2 pour autoriser l'appel, puis client-connect /etc/openvpn/server/assign-address.sh. Quand un client s'authentifie, le serveur exécute ce script avec le chemin du fichier généré ajouté comme dernier argument, qui n'est $1 que si la déclaration ne passe aucun argument supplémentaire propre. Tout ce qui s'applique à ce client va dans ce fichier sous forme de directives ordinaires, une par ligne, exactement comme elles apparaîtraient dans une configuration. Un wrapper qui ajoute ses propres paramètres décale la position, et le symptôme classique est un script qui écrit dans un chemin ressemblant à --verbose.
Le code de sortie est l'autre moitié du contrat. Zéro signifie accepter et lire le fichier ; tout le reste rejette la connexion, et c'est ainsi qu'une identité non mappée est refusée au lieu de retomber silencieusement dans le pool. Écrivez la directive complète avant de renvoyer un succès, afin qu'un fichier à moitié écrit ne devienne jamais la configuration d'un client.
Deux directives méritent attention parce qu'elles interagissent avec tout le reste. ifconfig-push fixe l'adresse, tandis qu'une route poussée indique au client ce qui est joignable à travers le tunnel ; renvoyez la première et oubliez la seconde et vous obtenez un client avec une adresse et nulle part où aller. L'ordre dans le fichier n'importe pas, mais l'exhaustivité si. Un hook qui pousse une route pour un préfixe qu'aucun pair ne peut atteindre est la même erreur vue de l'autre bout.
Les entrées arrivent par variables d'environnement : common_name, trusted_ip, ifconfig_pool_remote_ip et les autres. Traitez-les toutes comme des chaînes venant de l'extérieur du serveur, jamais comme des fragments de shell.
Le mappage d'adresses est une politique, pas de l'arithmétique
Un raccourci tentant consiste à analyser le nom du certificat et à utiliser ses chiffres comme dernier octet. Ce n'est pas un allocateur, et il échoue de façon ordinaire : deux noms de même suffixe entrent en collision, un nom se terminant par 300 n'est pas une adresse, et un certificat renommé par un administrateur déplace silencieusement un appareil. Validez l'appartenance au sous-réseau, la plage d'hôtes utilisable, les adresses réservées et l'unicité à chaque appel, et conservez le mappage dans une table qu'un humain peut lire.
Qui contrôle le nom contrôle l'adresse, alors décidez ce que common_name représente réellement dans ce déploiement. Avec username-as-common-name activé, l'identité est l'identifiant de connexion et non le sujet du certificat. Ne transmettez jamais cette valeur à une évaluation shell, et ne laissez jamais le client influencer un chemin de fichier.
Un allocateur adossé à un registre doit survivre à la concurrence. Réservez l'adresse de façon atomique, gérez une écriture échouée sans admettre un client à moitié configuré, et étiquetez chaque allocation avec la connexion qui la possède, afin qu'une déconnexion tardive d'une session plus ancienne ne puisse libérer une adresse qu'une plus récente détient déjà. Plusieurs instances de serveur partageant un même pool rendent cette exigence plus aiguë, non facultative.
La topologie décide de ce que signifie ifconfig-push
Avec topology subnet sur 10.77.0.0/24, ifconfig-push 10.77.0.20 255.255.255.0 est une adresse plus son masque de réseau. Sous topology net30 le second argument n'est pas un masque du tout mais l'adresse du pair, donc copier la forme sous-réseau sur un serveur net30 vous donne un client qui s'associe et ne peut pas faire passer de trafic. Changez la topologie délibérément, jamais pour qu'un exemple paraisse cohérent. Un serveur qui tourne déjà en net30 a des clients actifs sur l'ancien adressage, donc le basculement est une migration avec fenêtre de maintenance, pas une modification d'une ligne.
Les adresses statiques doivent se situer hors du pool dynamique et hors de toute autre attribution statique, y compris celles distribuées par les fichiers client-config-dir ordinaires. Si deux mécanismes peuvent produire la même adresse pour des clients différents, l'un d'eux finira par le faire.
Testez quatre cas avant de lui faire confiance
Exécutez les mêmes contrôles sur une identité mappée, une non mappée, une reconnexion et une panne de registre simulée. openvpn --config client.ovpn --verb 4 affiche l'adresse attribuée dans la réponse push, et sur le serveur grep -A2 PUSH_REPLY /var/log/openvpn/openvpn.log confirme ce qui a réellement été envoyé. Pour l'identité non mappée, le résultat attendu est une connexion rejetée, pas une adresse du pool.
Inspectez ensuite le répertoire dans lequel le démon écrit ces fichiers temporaires. Le script s'exécute dans le contexte de service dégradé, donc un chemin inscriptible par root mais pas par le démon transforme chaque connexion en rejet avec une erreur de permissions enfouie plusieurs lignes plus bas dans le journal.
Attribuer n'est pas autoriser : une adresse épinglée ne donne toujours pas accès à chaque destination derrière le serveur. Gardez la politique de routage et de pare-feu dans sa propre couche, et vérifiez-la par rapport à l'adresse que vous venez de fixer.