Como automatizar un inicio de sesión VPN que espera un código de token
Un cliente VPN de liña de ordes que pregunta nun terminal bloquea un script que só envía un contrasinal por tubo. Faga estas cinco comprobacións antes de recorrer a expect.
Un script que inicia un cliente VPN de provedor queda colgado ata que expira o tempo, e o rexistro mostra que o cliente pide un código de verificación que ninguén escribiu. O contrasinal enviárase, así que a conclusión obvia é que o contrasinal é incorrecto. Non o é. A petición do código é unha conversa aparte nunha canle aparte, e o seu script nunca a abriu.
Faga as cinco comprobacións seguintes en orde. Detéñase na primeira que falle, porque cada paso posterior supón que os anteriores se cumpren.
Comprobación 1: o cliente le a entrada estándar, cando menos?
Próbeo antes de escribir calquera automatización: envíe un secreto ficticio ao cliente por un tubo e observe que ocorre. Se imprime a súa petición e despois espera, non está a ler o tubo.
Moitos clientes abren o dispositivo de terminal directamente, ou néganse a tomar un secreto dun fluxo que non é un terminal, para que un tubo extraviado non poida filtrar un contrasinal. OpenVPN é a excepción documentada, porque --auth-user-pass acepta unha ruta de ficheiro. Os clientes de provedor que piden un código dun só uso normalmente non teñen unha opción equivalente, e a súa petición espera un terminal que o seu script nunca forneceu.
Comprobación 2: ten o proceso fillo un terminal?
Un pty asigna un terminal ao fillo, o que converte as peticións en saída lexible que pode responder en orde.
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)As cadeas de petición anteriores son ilustrativas; copie o texto exacto que imprime o seu cliente, incluídos maiúsculas e puntuación. Cada expectativa leva un tempo de espera, e un fillo pechado lanza unha excepción en lugar de devolver un estado, así que envolva a secuencia e trate o final de ficheiro como un fallo. Fíxese no que este bloque non fai: o fillo morre co script, porque un pty non é un mecanismo de desacoplamento e disown é unha orde interna da consola que non pode alcanzar un proceso que o seu script lanzou.
Comprobación 3: hai unha entrada non interactiva admitida?
O raspado de pantalla rompe coas actualizacións do cliente, así que busque primeiro unha opción documentada.
Revise a saída de axuda por se hai unha opción de token ou de código dun só uso, e comprobe se o servizo acepta o código engadido ao campo de contrasinal. Onde o cliente le un ficheiro de credenciais, déalle o ficheiro en lugar dunha petición:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")A substitución de procesos dálle ao cliente unha ruta lexible en sistemas que ofrecen /dev/fd. O secreto segue sendo un secreto desde o punto de vista do cliente, así que mantéñao fóra dos rexistros, do historial da consola e das listas de procesos. Se o cliente rexeita /dev/fd ou abre a ruta de credenciais máis dunha vez, escriba un ficheiro real con permisos restritivos e bórreo no mesmo script.
Comprobación 4: sobrevivirá o túnel ao script?
Por defecto o túnel morre co seu pai, que é o contrario do que necesita un script de arranque.
disown -h só axuda cando lanzou o cliente como unha tarefa da consola, porque edita a táboa de tarefas desa consola e non pode alcanzar un proceso que o seu script lanzou mediante un pty. Un xestor de servizos é o mellor fogar para todo o que debe reconectarse sen supervisión, porque reinicia o cliente e rexistra por que morreu. En calquera caso, espere un código novo despois de cada reconexión: un token dun só uso consómese coa primeira autenticación correcta.
Observe que fai sudo coa secuencia. A petición de contrasinal de sudo non é a petición do VPN, e respondela co contrasinal do VPN é a forma máis común de que unha orde de expectativas por outra parte correcta siga fallando.
Comprobación 5: debería o código dunha persoa estar nun script?
Esta é a comprobación que a xente salta. Un token pertence a unha persoa, mentres que un túnel que debe erguerse segundo un horario pertence á máquina.
Se unha tarefa debe reconectarse sen supervisión, pregunte se un certificado de máquina ou unha conta de servizo poden substituír o inicio de sesión interactivo. Automatizar o código dun só uso de alguén converte un segundo factor nun secreto almacenado, o que é un cambio de política e non unha comodidade de scripting. Onde o servizo admite ambas as dúas, escolla a credencial que encaixa con como se executa realmente a tarefa. Escriba a resposta, porque a seguinte persoa preguntará por que o script garda un token.
Como se ve un script que funciona
O script imprime o paso ao que chegou, nunca o secreto, e sae cun código distinto de cero ante calquera expectativa fallida.
Próbeo rompéndoo a propósito: contrasinal incorrecto, grupo incorrecto, token caducado. Cada fallo debería deterse nun paso con nome en lugar de colgarse. Despois execúteo unha vez contra o servizo real e comprobe o túnel desde fóra do script, non desde dentro.