Så automatiserar du en VPN-inloggning som väntar på en tokenkod
En CLI-VPN-klient som frågar i en terminal blockerar ett skript som bara skickar ett lösenord genom ett rör. Gör dessa fem kontroller innan du tar till expect.
Ett skript som startar en leverantörs VPN-klient hänger tills det får timeout, och loggen visar att klienten ber om en verifieringskod som ingen skrev in. Lösenordet skickades, så den uppenbara slutsatsen är att lösenordet är fel. Det är det inte. Kodfrågan är ett separat samtal på en separat kanal, och ditt skript öppnade den aldrig.
Gå igenom de fem kontrollerna nedan i ordning. Stanna vid den första som misslyckas, eftersom varje senare steg förutsätter att de tidigare gäller.
Kontroll 1: läser klienten över huvud taget standardindata?
Testa innan du skriver någon automatisering: skicka en låtsashemlighet genom ett rör till klienten och se vad som händer. Om den skriver ut sin fråga och sedan väntar läser den inte röret.
Många klienter öppnar terminalenheten direkt, eller vägrar ta en hemlighet från ett flöde som inte är en terminal, så att ett vilsekommet rör inte kan läcka ett lösenord. OpenVPN är det dokumenterade undantaget, eftersom --auth-user-pass tar en filsökväg. Leverantörsklienter som ber om en engångskod har oftast ingen motsvarande flagga, och deras fråga väntar på en terminal som ditt skript aldrig tillhandahöll.
Kontroll 2: har barnprocessen en terminal?
En pty tilldelar en terminal åt barnet, vilket gör frågor till läsbar utdata som du kan svara på i ordning.
import pexpect
child = pexpect.spawn("openconnect vpn.example.net", encoding="utf-8", timeout=30)
child.expect("GROUP:")
child.sendline("staff")
child.expect("USERNAME:")
child.sendline("alice")
child.expect("PASSWORD:")
child.sendline(PASSWORD)
child.expect("Connected as", timeout=60)Frågesträngarna ovan är illustrativa; kopiera den exakta text som din klient skriver ut, inklusive versaler och skiljetecken. Varje förväntan har en tidsgräns, och ett stängt barn kastar ett undantag i stället för att returnera en status, så linda in sekvensen och behandla filens slut som ett fel. Notera vad det här blocket inte gör: barnet dör med skriptet, eftersom en pty inte är en frånkopplingsmekanism och disown är ett inbyggt skalkommando som inte kan nå en process som ditt skript startade.
Kontroll 3: finns det stöd för icke-interaktiv inmatning?
Skärmskrapning går sönder vid klientuppdateringar, så leta först efter en dokumenterad flagga.
Kontrollera hjälputdata efter ett token- eller engångskodealternativ och kontrollera om tjänsten accepterar koden som läggs till i lösenordsfältet. Där klienten läser en inloggningsfil, ge den filen i stället för en fråga:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")Processubstitution ger klienten en läsbar sökväg på system som tillhandahåller /dev/fd. Hemligheten är fortfarande en hemlighet ur klientens synvinkel, så håll den borta från loggar, skalhistorik och processlistor. Om klienten avvisar /dev/fd eller öppnar inloggningssökvägen mer än en gång, skriv en riktig fil med strikta rättigheter och radera den i samma skript.
Kontroll 4: överlever tunneln skriptet?
Som standard dör tunneln med sin förälder, vilket är motsatsen till vad ett startskript behöver.
disown -h hjälper bara när du startade klienten som ett skaljobb, eftersom det redigerar det skalets jobbtabell och inte kan nå en process som ditt skript startade via en pty. En tjänstehanterare är ett bättre hem för allt som måste återansluta utan övervakning, eftersom den startar om klienten och registrerar varför den dog. Oavsett vilket, förvänta dig en ny kod efter varje återanslutning: en engångstoken förbrukas av den första lyckade autentiseringen.
Lägg märke till vad sudo gör med sekvensen. En sudo-lösenordsfråga är inte VPN-ens fråga, och att svara på den med VPN-lösenordet är det vanligaste sättet som en i övrigt korrekt förväntansordning ändå misslyckas.
Kontroll 5: bör en persons kod finnas i ett skript?
Det här är kontrollen som folk hoppar över. En token tillhör en person, medan en tunnel som måste komma upp enligt ett schema tillhör maskinen.
Om ett jobb måste återansluta utan övervakning, fråga om ett maskincertifikat eller ett tjänstekonto kan ersätta den interaktiva inloggningen. Att automatisera någons engångskod gör en andra faktor till en lagrad hemlighet, vilket är en policyändring och inte en bekvämlighet för skript. Där tjänsten stöder båda, välj den inloggning som matchar hur jobbet faktiskt körs. Skriv ner svaret, eftersom nästa person kommer att fråga varför skriptet håller en token.
Hur ett fungerande skript ser ut
Skriptet skriver ut steget det nådde, aldrig hemligheten, och avslutar med en icke-nollkod vid varje misslyckad förväntan.
Testa det genom att avsiktligt bryta det: fel lösenord, fel grupp, utgången token. Varje fel bör stanna vid ett namngivet steg i stället för att hänga. Kör det sedan en gång mot den riktiga tjänsten och kontrollera tunneln utifrån skriptet, inte inifrån.