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.

Artigos relacionados