Ett skript som startar OpenVPN och aldrig ansluter är oftast inte ett nätverksproblem: klienten sitter vid en prompt utan terminal att rita den på. OpenVPN har exakt två stödda sätt att svara på den prompten utan en människa, en inloggningsfil bakom auth-user-pass och styruttaget, och de är inte utbytbara. Filen kostar ett direktiv och svarar på en prompt; uttaget svarar på varje prompt och ger allt som kan öppna en loopback-port en oautentiserad kontrollkanal. Vilken som hör till din driftsättning beror på vilken prompt som faktiskt blockerar, och på vilken hemlighet du har råd att låta ligga i ro.

Namnge prompten innan du väljer mekanism

Fyra promptar ser identiska ut på en terminal. Kontoparet kommer från serverns PAM- eller auth-user-pass-verify-inställning och besvaras av auth-user-pass. En lösenfras för en privat nyckel hör till nyckelfilen och läses via --askpass eller skrivs in för hand. Ett PKCS#12-paket frågar efter sitt eget lösenord. Proxyautentisering använder auth-filen som --http-proxy tar, inte kontouppgifterna.

När OpenVPN körs som barn till systemd, PHP eller Node finns ingen terminal, så var och en av dessa blockerar tyst. Processen sitter där, loggen stannar efter chifferraden och enheten går till slut i timeout; den tystnaden är anledningen till att folk lägger till en återförsöksloop eller en sleep i stället för att titta på vilken prompt som väntar. Bara styruttaget kan svara på alla fyra. Inloggningsfilen svarar på den första och inget annat.

auth-user-pass: en fil, en prompt

Filen innehåller användarnamnet på rad ett och lösenordet på rad två, och inget annat: inga citattecken, inga nyckelnamn, ingen kommentar. Sätt läget 600 och gör ägaren till kontot som kör openvpn, vilket för en tjänst ofta är en dedikerad användare och inte din inloggning. En fil som ägs av root under /root är skillnaden mellan ett kommando som fungerar i ditt skal och en enhet som misslyckas vid uppstart.

Två detaljer förvandlar en korrekt fil till en prompt. En redigerare som sparar CRLF lämnar en vagnretur fastklistrad vid lösenordet, så servern avvisar ett lösenord som ser korrekt ut i filen; kontrollera med cat -A eller od -c i stället för med ögat. Och en auth-user-pass utan argument inne i profilen betyder enligt designen «fråga användaren», vilket ett andra direktiv på kommandoraden kanske inte åsidosätter, eftersom profilen tolkas där den ligger.

Ordningen på alternativen är den tredje fällan, och den beror på versionen. Vissa OpenVPN 2.4-byggen ignorerar --auth-user-pass när det står före --config, så samma två alternativ i den andra ordningen ansluter. Placera direktivet i profilen, eller efter --config på kommandoraden, och grep:a profilen efter varje förekomst innan du ändrar något annat.

auth-nocache hör till den här mekanismen men levererar ingenting. Det begränsar hur länge klienten behåller inloggningsuppgifterna i minnet, vilket hjälper efter en krasch och inte alls när filen saknas. En återanslutning efter en sessionstimeout på serversidan läser filen igen, så uppgifter som fungerade vid uppstart kan fortfarande gå ut mitt på dagen.

Styruttaget: varje prompt, större yta

Starta klienten med en lyssnare och deklarera uttryckligen att promptar rapporteras på den, med de direktiv som dokumenteras i OpenVPN 2.6-handboken:

management 127.0.0.1 3030
management-query-passwords

Från bash håller du anslutningen på en ledig fildeskriptor och svarar efter promptnamn i stället för position, eftersom en återanslutning kan fråga i en annan ordning:

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

Gränsen är transporten. Styrprotokollet är klartext över TCP på loopback, så lyssnaren får inte publiceras på en LAN- eller tunneladress för att en fjärrstyrenhet ska nå den; en fjärrstyrenhet betyder en SSH-vidarebefordran, inte en bredare bindning. Community-daemonen accepterar också bara en styrklient i taget, så en GUI eller monitor kan inte dela uttaget med ditt skript. Den andra anslutningen avvisas, köas inte, och felet ser ut som ett skript som blivit dövt.

Det uttaget är också en kontrollkanal. Utan ett styrlösenord kan allt som kan ansluta till 127.0.0.1:3030 läsa status, döda tunneln eller själv svara på en prompt. Styrlösenordet och inloggningsfilen är hemligheter i samma klass, och båda förtjänar samma omsorg.

Vilken passar driftsättningen

Välj inloggningsfilen när den enda prompten är kontoparet, klienten körs som tjänst med en stabil ägare och du kan hålla en 600-fil utanför säkerhetskopior du inte kontrollerar. Välj styruttaget när en nyckellösenfras eller ett PKCS#12-lösenord är inblandat, när omslaget redan övervakar processen, eller när du behöver följa status och promptar medan du felsöker en återanslutning.

Två villkor flyttar beslutet. Om omslaget är /bin/sh, en systemd-enhet som anropar binären direkt, eller en minimal container, är bash-only-uttagsklister inte tillgängligt och filen är det billigare svaret. Om hemligheten roterar ofta är ingen av filerna ett bra hem för den: fråga en nyckelring från ett litet omslag och låt enheten anropa omslaget, vilket håller rotationen på ett ställe och lösenordet utanför skalhistoriken.

Processubstitution står mellan de två och tillhör ingen av dem. Enradaren nedan fungerar för att bash expanderar den innan openvpn startar, inte för att klienten förstår syntaxen:

openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")

Den går sönder under /bin/sh, i en enhet som kringgår skalet och i avbildningar utan bash eller /dev/fd. Behåll den för interaktiva tester, aldrig som kontraktet en tjänst är beroende av.

Skydda hemligheten och verifiera sedan från loggen

Båda mekanismerna lämnar en hemlighet som OpenVPN-processen kan läsa. Lägg aldrig lösenordet på kommandoraden eller i enhetsfilen, där ps och systemctl visar det för varje lokal användare; skicka sökvägen till filen, inte värdet i den. Där certifikat kan ersätta kontoparet tar det bort promptkategorin i stället för att dölja den.

En korrekt körning visar att promptsekvensen fullbordas och att sessionen når «Initialization Sequence Completed». Om klienten stannar vid samma prompt misslyckades matchningen: skriv ut de exakta raderna som uttaget skickade, kontrollera citattecken och promptnamnet, och rätta mönstret i stället för att lägga till en sleep. En tunnel som rapporterar framgång och inte bär något är ett routing- eller push-problem, inte ett inloggningsproblem.

Testa sedan återanslutningen, inte bara första starten. Släpp sessionen på serversidan eller vänta ut dess timeout; klienten frågar igen, och det är där en fil som såg korrekt ut vid uppstart visar om den fortfarande kan läsas av kontot som återansluter.

Relaterade artiklar