Como automatizar um login de VPN que espera um código de token
Um cliente VPN de linha de comando que pergunta no terminal bloqueia um script que apenas envia uma palavra-passe por pipe. Faça estas cinco verificações antes de recorrer ao expect.
Um script que inicia um cliente VPN de fornecedor fica pendurado até ao limite de tempo, e o registo mostra que o cliente pede um código de verificação que ninguém escreveu. A palavra-passe foi fornecida, por isso a conclusão óbvia é que a palavra-passe está errada. Não está. O pedido do código é uma conversa separada num canal separado, e o seu script nunca a abriu.
Percorra as cinco verificações abaixo por ordem. Pare na primeira que falhar, porque cada passo posterior assume que os anteriores se mantêm.
Verificação 1: o cliente lê a entrada padrão, sequer?
Teste antes de escrever qualquer automatização: envie um segredo falso ao cliente por um pipe e veja o que acontece. Se imprimir o seu pedido e depois esperar, não está a ler o pipe.
Muitos clientes abrem o dispositivo de terminal diretamente, ou recusam receber um segredo de um fluxo que não é um terminal, para que um pipe perdido não possa divulgar uma palavra-passe. O OpenVPN é a exceção documentada, porque --auth-user-pass aceita um caminho de ficheiro. Os clientes de fornecedor que pedem um código de uso único normalmente não têm uma opção equivalente, e o pedido deles espera por um terminal que o seu script nunca forneceu.
Verificação 2: o processo filho tem um terminal?
Um pty atribui um terminal ao filho, o que transforma os pedidos em saída legível a que pode responder por ordem.
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 cadeias de pedido acima são ilustrativas; copie o texto exato que o seu cliente imprime, incluindo maiúsculas e pontuação. Cada expectativa tem um limite de tempo, e um filho fechado lança uma exceção em vez de devolver um estado, por isso envolva a sequência e trate o fim do ficheiro como uma falha. Repare no que este bloco não faz: o filho morre com o script, porque um pty não é um mecanismo de desacoplamento e o disown é um comando interno da shell que não alcança um processo que o seu script lançou.
Verificação 3: existe uma entrada não interativa suportada?
O raspar do ecrã parte-se nas atualizações do cliente, por isso procure primeiro uma opção documentada.
Verifique a saída de ajuda para uma opção de token ou código de uso único, e verifique se o serviço aceita o código acrescentado ao campo da palavra-passe. Onde o cliente lê um ficheiro de credenciais, dê-lhe o ficheiro em vez de um pedido:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")A substituição de processos dá ao cliente um caminho legível em sistemas que fornecem /dev/fd. O segredo continua a ser um segredo do ponto de vista do cliente, por isso mantenha-o fora de registos, do histórico da shell e das listas de processos. Se o cliente recusar /dev/fd ou abrir o caminho das credenciais mais de uma vez, escreva um ficheiro real com permissões restritas e elimine-o no mesmo script.
Verificação 4: o túnel vai sobreviver ao script?
Por predefinição o túnel morre com o seu progenitor, o que é o contrário do que um script de arranque precisa.
O disown -h só ajuda quando lançou o cliente como tarefa da shell, porque edita a tabela de tarefas dessa shell e não alcança um processo que o seu script lançou através de um pty. Um gestor de serviços é a melhor casa para tudo o que tem de se voltar a ligar sem supervisão, porque reinicia o cliente e registra por que morreu. Em qualquer caso, espere um código novo após cada reconexão: um token de uso único é consumido pela primeira autenticação bem-sucedida.
Repare no que o sudo faz à sequência. Um pedido de palavra-passe do sudo não é o pedido da VPN, e responder-lhe com a palavra-passe da VPN é a forma mais comum de uma ordem de expectativas de resto correta continuar a falhar.
Verificação 5: o código de uma pessoa deve estar num script?
Esta é a verificação que as pessoas saltam. Um token pertence a uma pessoa, enquanto um túnel que tem de subir segundo um horário pertence à máquina.
Se uma tarefa tem de se voltar a ligar sem supervisão, pergunte se um certificado de máquina ou uma conta de serviço podem substituir o início de sessão interativo. Automatizar o código de uso único de alguém transforma um segundo fator num segredo guardado, o que é uma mudança de política e não uma comodidade de scripting. Onde o serviço suporta os dois, escolha a credencial que corresponde à forma como a tarefa realmente corre. Escreva a resposta, porque a próxima pessoa vai perguntar por que o script guarda um token.
Como é um script que funciona
O script imprime o passo a que chegou, nunca o segredo, e sai com um código diferente de zero em qualquer expectativa falhada.
Teste-o quebrando-o de propósito: palavra-passe errada, grupo errado, token expirado. Cada falha deve parar num passo com nome em vez de ficar pendurada. Depois execute-o uma vez contra o serviço real e verifique o túnel de fora do script, não de dentro.