OpenVPN-inlogbestand of beheersocket: wat je moet scripten
auth-user-pass dekt de accountprompt; de beheersocket dekt alle vier. Vergelijk de blootstelling, de scriptkosten en hoe elk in een dienst faalt.
Een script dat OpenVPN start en nooit verbindt, is meestal geen netwerkprobleem: de client zit bij een prompt zonder terminal om die op te tekenen. OpenVPN heeft precies twee ondersteunde manieren om die prompt zonder mens te beantwoorden, een inlogbestand achter auth-user-pass en de beheersocket, en ze zijn niet uitwisselbaar. Het bestand kost één richtlijn en beantwoordt één prompt; de socket beantwoordt elke prompt en geeft alles wat een loopback-poort kan openen een niet-geauthenticeerd besturingskanaal. Welke bij jouw uitrol hoort, hangt af van welke prompt echt blokkeert, en van welk geheim je je kunt permitteren om te laten rusten.
Benoem de prompt voordat je een mechanisme kiest
Vier prompts zien er op een terminal hetzelfde uit. Het accountpaar komt uit de PAM- of auth-user-pass-verify-instelling van de server en wordt door auth-user-pass beantwoord. Een wachtwoordzin voor een privésleutel hoort bij het sleutelbestand en wordt via --askpass gelezen of met de hand getypt. Een PKCS#12-bundel vraagt een eigen wachtwoord. Proxyauthenticatie gebruikt het auth-bestand dat --http-proxy neemt, niet de accountgegevens.
Wanneer OpenVPN als kind van systemd, PHP of Node draait, is er geen terminal, dus elk van deze blokkeert stil. Het proces zit daar, de log stopt na de cipher-regel en de unit loopt uiteindelijk in een time-out; die stilte is de reden dat mensen een herhaal-loop of een sleep toevoegen in plaats van te kijken welke prompt wacht. Alleen de beheersocket kan alle vier beantwoorden. Het inlogbestand beantwoordt de eerste en niets anders.
auth-user-pass: één bestand, één prompt
Het bestand bevat de gebruikersnaam op regel één en het wachtwoord op regel twee, en niets anders: geen aanhalingstekens, geen sleutelnamen, geen commentaar. Zet modus 600 en maak de eigenaar het account dat openvpn draait, wat voor een dienst vaak een aparte gebruiker is in plaats van jouw login. Een bestand van root onder /root is het verschil tussen een commando dat in je shell werkt en een unit die bij het opstarten faalt.
Twee details maken van een correct bestand een prompt. Een editor die CRLF opslaat, laat een regelterugloop aan het wachtwoord kleven, waardoor de server een wachtwoord weigert dat in het bestand correct lijkt; controleer met cat -A of od -c in plaats van met het oog. En een auth-user-pass zonder argument in het profiel betekent volgens ontwerp «vraag de gebruiker», wat een tweede richtlijn op de opdrachtregel misschien niet overschrijft, omdat het profiel wordt geparseerd waar het staat.
De volgorde van opties is de derde valkuil, en die is versieafhankelijk. Sommige OpenVPN 2.4-builds negeren --auth-user-pass wanneer het vóór --config staat, zodat dezelfde twee opties in de andere volgorde verbinden. Zet de richtlijn in het profiel, of na --config op de opdrachtregel, en grep het profiel op elk voorkomen voordat je iets anders verandert.
auth-nocache hoort bij dit mechanisme maar levert niets. Het beperkt hoe lang de client de inloggegevens in het geheugen houdt, wat na een crash helpt en helemaal niet wanneer het bestand ontbreekt. Een herverbinding na een sessie-time-out aan de serverkant leest het bestand opnieuw, dus inloggegevens die bij het opstarten werkten, kunnen midden op de dag nog verlopen.
De beheersocket: elke prompt, meer oppervlak
Start de client met een luisteraar en verklaar uitdrukkelijk dat prompts daarop worden gerapporteerd, met de richtlijnen die in de OpenVPN 2.6-handleiding zijn gedocumenteerd:
management 127.0.0.1 3030
management-query-passwords
Houd vanuit bash de verbinding op een vrije bestandsdescriptor en antwoord op promptnaam in plaats van op positie, omdat een herverbinding in een andere volgorde kan vragen:
exec 3<>/dev/tcp/127.0.0.1/3030
while read -r -u 3 line; do
case "$line" in
*"Need 'Auth' username/password"*)
echo 'username "Auth" alice' >&3
echo 'password "Auth" secret' >&3 ;;
*"Need 'Private Key' password"*)
echo 'password "Private Key" secret' >&3 ;;
esac
done
De grens is het transport. Het beheerprotocol is platte tekst over TCP op loopback, dus de luisteraar mag niet op een LAN- of tunneladres worden gepubliceerd om een externe controller hem te laten bereiken; een externe controller betekent een SSH-doorsturing, geen bredere binding. De community-daemon accepteert ook maar één beheerclient tegelijk, dus een GUI of monitor kan de socket niet met je script delen. De tweede verbinding wordt geweigerd, niet in de wachtrij gezet, en de storing lijkt op een script dat doof is geworden.
Die socket is ook een besturingskanaal. Zonder beheerwachtwoord kan alles wat verbinding kan maken met 127.0.0.1:3030 de status lezen, de tunnel doden of zelf een prompt beantwoorden. Het beheerwachtwoord en het inlogbestand zijn geheim van dezelfde klasse, en beide verdienen dezelfde zorg.
Welke bij de uitrol past
Kies het inlogbestand wanneer de enige prompt het accountpaar is, de client als dienst draait met een stabiele eigenaar, en je een 600-bestand buiten back-ups kunt houden die je niet beheert. Kies de beheersocket wanneer een sleutelwachtwoordzin of een PKCS#12-wachtwoord in het spel is, wanneer de wrapper het proces al bewaakt, of wanneer je status en prompts wilt volgen terwijl je een herverbinding debugt.
Twee voorwaarden verschuiven de beslissing. Is de wrapper /bin/sh, een systemd-unit die het binaire bestand direct aanroept, of een minimale container, dan is de alleen-bash-socketlijm niet beschikbaar en is het bestand het goedkopere antwoord. Als het geheim vaak roteert, is geen van beide bestanden een goed huis ervoor: vraag een sleutelhanger op uit een kleine wrapper en laat de unit de wrapper aanroepen, wat de rotatie op één plek houdt en het wachtwoord buiten de shellgeschiedenis.
Procesvervanging staat tussen beide in en hoort bij geen van beide. De one-liner hieronder werkt omdat bash hem uitbreidt voordat openvpn start, niet omdat de client de syntaxis begrijpt:
openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")
Hij breekt onder /bin/sh, in een unit die de shell omzeilt, en in images zonder bash of /dev/fd. Bewaar hem voor interactief testen, nooit als het contract waarvan een dienst afhangt.
Bescherm het geheim en verifieer daarna uit de log
Beide mechanismen laten een geheim achter dat het OpenVPN-proces kan lezen. Zet het wachtwoord nooit op de opdrachtregel of in het unitbestand, waar ps en systemctl het aan elke lokale gebruiker tonen; geef het pad naar het bestand, niet de waarde erin. Waar certificaten het accountpaar kunnen vervangen, haalt dat de categorie prompt weg in plaats van hem te verbergen.
Een correcte run laat de promptreeks voltooien en de sessie «Initialization Sequence Completed» bereiken. Als de client bij dezelfde prompt stopt, is de overeenkomst mislukt: druk de exacte regels af die de socket stuurde, controleer de aanhalingstekens en de promptnaam, en repareer het patroon in plaats van een sleep toe te voegen. Een tunnel die succes meldt en niets vervoert, is een routerings- of push-probleem, geen inlogprobleem.
Test daarna de herverbinding, niet alleen de eerste start. Breek de sessie aan de serverkant af of wacht de time-out af; de client vraagt opnieuw, en daar laat een bestand dat bij het opstarten correct leek zien of het nog leesbaar is voor het account dat opnieuw verbindt.