Sådan automatiserer du et VPN-login, der venter på en tokencode
En CLI VPN-klient, der spørger i en terminal, blokerer et script, som kun sender en adgangskode gennem en pipe. Gå disse fem kontroller igennem, før du griber efter expect.
Et script, der starter en leverandørs VPN-klient, hænger, indtil det timer ud, og loggen viser, at klienten beder om en bekræftelseskode, som ingen har indtastet. Adgangskoden blev sendt, så den oplagte konklusion er, at adgangskoden er forkert. Det er den ikke. Kodeopfordringen er en separat samtale på en separat kanal, og dit script åbnede den aldrig.
Gå de fem kontroller nedenfor igennem i rækkefølge. Stop ved den første, der fejler, fordi hvert senere trin forudsætter, at de tidligere holder.
Kontrol 1: læser klienten overhovedet standardinput?
Test før du skriver nogen automatisering: send en dummy-hemmelighed gennem en pipe til klienten, og se hvad der sker. Hvis den udskriver sin opfordring og derefter venter, læser den ikke pipen.
Mange klienter åbner terminalenheden direkte eller nægter at tage en hemmelighed fra en strøm, der ikke er en terminal, så en løbsk pipe ikke kan lække en adgangskode. OpenVPN er den dokumenterede undtagelse, fordi --auth-user-pass tager en filsti. Leverandørklienter, der beder om en engangskode, har normalt ikke et tilsvarende flag, og deres opfordring venter på en terminal, som dit script aldrig stillede til rådighed.
Kontrol 2: har barneprocessen en terminal?
En pty tildeler en terminal til barnet, hvilket gør opfordringer til læsbar output, som du kan svare på i rækkefølge.
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)Opfordringsstrengene ovenfor er illustrative; kopier den præcise tekst, din klient udskriver, inklusive store og små bogstaver og tegnsætning. Hver forventning har en timeout, og et lukket barn rejser en undtagelse i stedet for at returnere en status, så indpak sekvensen og behandle slutningen af filen som en fejl. Læg mærke til, hvad denne blok ikke gør: barnet dør med scriptet, fordi en pty ikke er en frakoblingsmekanisme, og disown er en indbygget shell-kommando, der ikke kan nå en proces, som dit script har startet.
Kontrol 3: findes der et understøttet ikke-interaktivt input?
Skærmridsning går i stykker ved klientopdateringer, så led først efter et dokumenteret flag.
Se hjælpeoutputtet igennem for en token- eller engangskodeindstilling, og undersøg, om tjenesten accepterer koden tilføjet adgangskodefeltet. Hvor klienten læser en legitimationsfil, så giv den filen i stedet for en opfordring:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")Procesudskiftning giver klienten en læsbar sti på systemer, der stiller /dev/fd til rådighed. Hemmeligheden er stadig en hemmelighed fra klientens synspunkt, så hold den ude af logfiler, shell-historik og proceslister. Hvis klienten afviser /dev/fd eller åbner legitimationsstien mere end én gang, så skriv en rigtig fil med stramme tilladelser og slet den i samme script.
Kontrol 4: overlever tunnelen scriptet?
Som standard dør tunnelen med sin forælder, hvilket er det modsatte af, hvad et opstarts-script har brug for.
disown -h hjælper kun, når du startede klienten som et shell-job, fordi den redigerer den shells jobtabel og ikke kan nå en proces, som dit script startede gennem en pty. Et værktøj til tjenestestyring er et bedre sted for alt, der skal genoprette forbindelse uden opsyn, fordi det genstarter klienten og registrerer, hvorfor den døde. Under alle omstændigheder skal du forvente en ny kode efter hver genopkobling: et engangstoken forbruges af den første vellykkede godkendelse.
Læg mærke til, hvad sudo gør ved sekvensen. En sudo-adgangskodeopfordring er ikke VPN-ens opfordring, og at svare på den med VPN-adgangskoden er den mest almindelige måde, hvorpå en ellers korrekt forventningsrækkefølge stadig fejler.
Kontrol 5: bør en persons kode være i et script?
Det er den kontrol, folk springer over. Et token tilhører en person, mens en tunnel, der skal op efter en tidsplan, tilhører maskinen.
Hvis et job skal genoprette forbindelse uden opsyn, så spørg, om et maskincertifikat eller en tjenestekonto kan erstatte det interaktive login. At automatisere nogens engangskode gør en anden faktor til en gemt hemmelighed, hvilket er en politikændring snarere end en bekvemmelighed for scripts. Hvor tjenesten understøtter begge, så vælg den legitimationsoplysning, der passer til, hvordan jobbet faktisk kører. Skriv svaret ned, fordi den næste person vil spørge, hvorfor scriptet holder et token.
Sådan ser et fungerende script ud
Scriptet udskriver det trin, det nåede, aldrig hemmeligheden, og afslutter med en ikke-nul kode ved enhver mislykket forventning.
Test det ved at brække det med vilje: forkert adgangskode, forkert gruppe, udløbet token. Hver fejl bør stoppe ved et navngivet trin i stedet for at hænge. Kør det derefter én gang mod den rigtige tjeneste, og kontroller tunnelen udefra scriptet, ikke indefra.