Trois choses décident quelle source d’identifiants utiliser : si une personne est assise à la console, si le secret peut vivre sur le disque et si un autre processus doit répondre à l’invite. Faites le mauvais choix et le client signale un problème stdin alors que le mot de passe est parfaitement valide, ce qui envoie la plupart des gens vers le serveur sans raison. Choisissez d’abord le chemin ; les messages d’erreur n’ont de sens qu’une fois que vous savez quel chemin les a produits.

Les trois conditions qui décident

L’invite de la console est le seul chemin qui a besoin d’un humain, c’est donc le seul qui échoue silencieusement dans une unité systemd ou un conteneur. Si une personne lance le client et tape le mot de passe, aucun fichier n’intervient et rien de sensible n’atterrit sur le disque. Si le client démarre au boot, cette même invite devient un blocage, et le délai d’attente apparaît généralement comme une panne de connexion générique plutôt que comme une erreur d’identifiants.

Un fichier d’identifiants est la bonne réponse lorsque le processus démarre sans surveillance et que le secret peut survivre sur le disque sous un ensemble de permissions maîtrisé. Quand le secret ne doit pas du tout être écrit - une politique coffre uniquement, un jeton de courte durée - il vous faut un flux que le client peut ouvrir, ce qui veut dire en pratique une substitution de processus ou un assistant qui écrit dans un descripteur de fichier. L’interface de gestion couvre le quatrième cas : un contrôleur qui gère déjà le cycle de vie du tunnel et peut répondre aux questions via une socket.

  • Humain à la console, pas d’automatisation : invite interactive.
  • Démarrage sans surveillance, le secret peut être stocké : fichier d’identifiants en mode 0600.
  • Démarrage sans surveillance, le secret ne peut pas être stocké : substitution de processus ou un fd écrit par un agent de secrets.
  • Un autre processus possède le client : interface de gestion.

Quand deux réponses conviennent, préférez celle qui garde le secret hors d’argv et hors de l’historique du shell. Un mot de passe passé comme argument de programme est lisible par tout utilisateur local via la liste des processus, et cette exposition est difficile à annuler.

Ce que fait réellement chaque chemin d’entrée

--auth-user-pass seul demande un nom d’utilisateur et un mot de passe à la console. Avec un nom de fichier, le client prend la première ligne comme nom d’utilisateur et la deuxième comme mot de passe ; rien ne prend en charge les guillemets, les commentaires ou la syntaxe clé-valeur. C’est tout le format, donc quiconque le modifie en attendant un fichier INI le casse. Un bloc <auth-user-pass> en ligne contient ces deux mêmes lignes dans le profil, ce qui fait du profil lui-même un secret et le place dans la même classe de traitement qu’une clé privée.

Les deux autres chemins sont un flux et une socket. OpenVPN n’a besoin que d’un descripteur de fichier lisible, il acceptera donc une substitution de processus, une entrée /dev/fd adossée à un tube ou un nom de fichier qui est en réalité un FIFO. L’interface de gestion est différente par nature : le client demande les valeurs à un processus superviseur au lieu de les lire lui-même. Cette différence compte à la reconnexion : un fichier d’identifiants, un FIFO dans lequel un assistant de secrets peut réécrire et l’interface de gestion peuvent fournir à nouveau sans personne ; la substitution de processus non, car le descripteur est consommé à la première lecture.

Le fichier doit comporter exactement deux lignes

Deux modes de défaillance couvrent la plupart des fichiers d’identifiants cassés. Un éditeur Windows laisse des fins de ligne CRLF, le retour chariot devient une partie du mot de passe, et le serveur rejette une valeur qui semble correcte à l’écran. Une deuxième ligne vide - une ligne vide là où devrait se trouver le mot de passe - laisse le client avec un mot de passe vide, que le serveur rejette même si la valeur à l’écran semble correcte. Un saut de ligne final après le mot de passe est inoffensif. Écrivez le fichier depuis le shell, pas depuis un éditeur, et vérifiez les octets :

install -m 600 /dev/null /etc/openvpn/client.creds
printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS" > /etc/openvpn/client.creds
od -c /etc/openvpn/client.creds | head -3

Le chemin compte autant que le contenu. Un chemin relatif se résout par rapport au répertoire de travail du processus, qui pour un service est rarement le répertoire où vous avez testé. Utilisez un chemin absolu, faites en sorte que le fichier appartienne au compte qui exécute le client, et gardez le mode 0600 pour que le groupe et les autres ne puissent pas le lire. Le manuel d’OpenVPN 2.6 énumère les formes acceptées de la directive ; consultez-le avant d’en inventer une troisième.

Testez le fichier avant d’accuser le serveur. Exécuter openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 affiche si le fichier a été ouvert et, plus tard, si les identifiants ont été acceptés, ce qui vous dit quelle couche changer ensuite.

Flux, stdin et les erreurs qu’ils produisent

Faire passer le mot de passe par un tube est la première chose que la plupart des gens essaient et le chemin qui réserve le plus de surprises. La substitution de processus fonctionne parce que le client n’a besoin que d’un descripteur lisible : openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS"). Passer /dev/stdin ne fonctionne que si stdin est encore ouvert et lisible au moment où le client demande, ce qui n’est pas vrai dans un pipeline qui l’a déjà consommé.

ERROR: could not read Auth username from stdin a deux causes distinctes. Sur certains clients 2.3.x le message venait d’un défaut de gestion de stdin corrigé par les versions 2.3 ultérieures, donc un client aussi ancien ne s’améliore qu’en étant mis à jour. Sur un client actuel, la même formulation signifie que le client a demandé une entrée console et que stdin n’était pas un terminal - exactement la situation dans une unité systemd, une tâche cron ou un conteneur démarré sans -t.

auth-nocache ajoute une troisième boucle qui ressemble à un mot de passe cassé. Il retire les identifiants de la mémoire après usage, donc une reconnexion déclenchée par un changement de réseau n’a rien à rejouer et l’invite revient. C’est la directive qui fonctionne comme prévu. auth-nocache change ce que le client garde en mémoire, pas ce que le serveur ou le fournisseur d’identité pense du compte, donc toute la correction consiste à fournir à nouveau le même fichier, relu au redémarrage - et pour une connexion gérée, cette fourniture devrait venir du magasin de secrets approuvé, pas d’un mot de passe dans un script.

L’interface de gestion quand un autre processus possède l’invite

Un contrôleur qui supervise déjà le tunnel peut aussi répondre à ses questions. Lancez le client avec --management 127.0.0.1 7505, lisez les lignes d’état et surveillez >PASSWORD:Need 'Auth' username/password. Le contrôleur répond avec username "Auth" alice suivi de password "Auth" ... sur des lignes de commande séparées. Le jeton 'Auth' reprend l’identifiant de la requête et doit correspondre, sinon la réponse est ignorée et le client attend.

Le coût est une machine à états que vous possédez désormais : ordre des connexions, redémarrages du client et une socket locale que les autres utilisateurs de l’hôte ne doivent pas atteindre. Ce que vous achetez, c’est un identifiant fourni à l’exécution, sans fichier sur le disque et sans invite qui puisse se bloquer. Si rien d’autre dans votre pile ne parle déjà le protocole, ce chemin ajoute un composant à maintenir.

Des défaillances qui ressemblent à des problèmes d’identifiants

Une poignée de main TLS qui ne se termine jamais, ou une VERIFY ERROR: depth=0, error=certificate signature failure, est un problème de confiance et survient avant qu’un nom d’utilisateur soit lu. Un client proto tcp pointé vers un écouteur UDP échoue au même endroit : les paquets n’atteignent jamais l’étape d’authentification, donc tout mot de passe semble faux par association. Gardez la vérification des certificats active avant l’envoi de l’identifiant ; une invite familière ne dit rien sur qui reçoit le mot de passe. Vérifiez la chaîne de certificats, le nom commun et le transport avant de toucher à l’identifiant.

Les bogues shell dans le script qui assemble le profil sont l’autre fausse piste. Un espace manquant dans [ ! -f "$file" ] produit command not found, le script s’arrête tôt, le profil n’est jamais reconstruit et le client démarre avec le précédent. Cette erreur appartient au shell, pas à l’authentification, et aucun fait de retaper le mot de passe ne la fera disparaître.

Toutes les invites de ce flux ne concernent pas cet identifiant. Une phrase secrète de clé privée, une connexion proxy HTTP et le mot de passe du service sont trois secrets différents demandés à des phases différentes, et une phrase secrète de clé est généralement gérée par le client ou un agent plutôt que par auth-user-pass. Si l’invite apparaît avant que la session TLS soit établie, vous répondez à la mauvaise question et aucune réinitialisation de compte n’aidera. Une fois la mauvaise invite écartée, les vérifications restantes commencent par la couche la plus précoce :

  • Lisez la première erreur de protocole, pas la dernière ligne d’identifiants : TLS, puis authentification, puis push.
  • Confirmez que le fichier fait deux lignes, ne contient pas de retours chariot et est référencé par un chemin absolu.
  • Confirmez que le profil et la ligne de commande ne se contredisent pas sur la directive.
  • Séparez "identifiants acceptés" de "le trafic circule" - le routage et le DNS sont une couche ultérieure.

Une fois que le client atteint la phase push, cessez de regarder les identifiants et commencez à lire les routes et les serveurs DNS envoyés par le serveur. C’est le problème suivant, et il n’a rien à voir avec le mot de passe que vous venez de corriger.

Articles similaires