Um script que inicia o OpenVPN e nunca liga não costuma ser um problema de rede: o cliente está parado num prompt sem terminal onde o desenhar. OpenVPN tem exatamente duas formas suportadas de responder a esse prompt sem uma pessoa, um ficheiro de credenciais por trás de auth-user-pass e o socket de gestão, e não são intermutáveis. O ficheiro custa uma diretiva e responde a um prompt; o socket responde a todos os prompts e entrega a tudo o que consiga abrir uma porta loopback um canal de controlo não autenticado. Qual deles pertence à sua implementação depende de que prompt está realmente a bloquear e de que segredo se pode dar ao luxo de deixar em repouso.

Nomeie o prompt antes de escolher um mecanismo

Quatro prompts parecem idênticos num terminal. O par de conta vem da configuração PAM ou auth-user-pass-verify do servidor e é respondido por auth-user-pass. A frase-passe de uma chave privada pertence ao ficheiro da chave e é lida via --askpass ou escrita à mão. Um pacote PKCS#12 pede uma palavra-passe própria. A autenticação de proxy usa o ficheiro auth que --http-proxy recebe, não as credenciais da conta.

Quando o OpenVPN corre como filho de systemd, PHP ou Node não há terminal, pelo que qualquer destes bloqueia em silêncio. O processo fica ali, o registo pára após a linha da cifra e a unidade acaba por expirar; esse silêncio é a razão pela qual as pessoas acrescentam um ciclo de repetição ou um sleep em vez de olharem para o prompt pendente. Só o socket de gestão consegue responder aos quatro. O ficheiro de credenciais responde ao primeiro e a mais nada.

auth-user-pass: um ficheiro, um prompt

O ficheiro guarda o nome de utilizador na linha um e a palavra-passe na linha dois, e nada mais: sem aspas, sem nomes de chaves, sem comentário. Defina o modo 600 e torne proprietário a conta que executa o openvpn, que num serviço é muitas vezes um utilizador dedicado e não o seu login. Um ficheiro pertencente a root em /root é a diferença entre um comando que funciona na sua shell e uma unidade que falha no arranque.

Dois detalhes transformam um ficheiro correto num prompt. Um editor que grava CRLF deixa um retorno de carro colado à palavra-passe, pelo que o servidor recusa uma palavra-passe que no ficheiro parece correta; verifique com cat -A ou od -c em vez de a olho. E um auth-user-pass sem argumento dentro do perfil significa «perguntar ao utilizador» por conceção, o que uma segunda diretiva na linha de comandos pode não anular, porque o perfil é analisado onde está.

A ordem das opções é a terceira armadilha, e depende da versão. Algumas compilações do OpenVPN 2.4 ignoram --auth-user-pass quando aparece antes de --config, pelo que as mesmas duas opções na outra ordem ligam. Coloque a diretiva dentro do perfil, ou depois de --config na linha de comandos, e procure no perfil cada ocorrência antes de mudar mais alguma coisa.

auth-nocache pertence a este mecanismo mas não fornece nada. Limita quanto tempo o cliente guarda a credencial em memória, o que ajuda após uma falha e nada ajuda quando o ficheiro falta. Uma reconexão após um tempo de sessão no servidor volta a ler o ficheiro, pelo que uma credencial que funcionou no arranque ainda pode expirar a meio do dia.

O socket de gestão: todos os prompts, mais superfície

Inicie o cliente com um ouvinte e declare explicitamente que os prompts serão reportados nele, usando as diretivas documentadas no manual do OpenVPN 2.6:

management 127.0.0.1 3030
management-query-passwords

A partir do bash, mantenha a ligação num descritor de ficheiro livre e responda pelo nome do prompt em vez de pela posição, porque uma reconexão pode perguntar noutra ordem:

exec 3<>/dev/tcp/127.0.0.1/3030
while read -r -u 3 line; do
  case "$line" in
    *"Need 'Auth' username/password"*)
      echo 'username "Auth" alice' >&3
      echo 'password "Auth" secret' >&3 ;;
    *"Need 'Private Key' password"*)
      echo 'password "Private Key" secret' >&3 ;;
  esac
done

A fronteira é o transporte. O protocolo de gestão é texto simples sobre TCP em loopback, pelo que o ouvinte não deve ser publicado num endereço de LAN ou de túnel para que um controlador remoto o alcance; um controlador remoto significa um encaminhamento SSH, não uma ligação mais ampla. O daemon da comunidade também aceita apenas um cliente de gestão de cada vez, pelo que uma GUI ou um monitor não podem partilhar o socket com o seu script. A segunda ligação é recusada, não colocada em fila, e a falha parece um script que ficou surdo.

Esse socket é também um canal de controlo. Sem palavra-passe de gestão, tudo o que consiga ligar-se a 127.0.0.1:3030 pode ler o estado, matar o túnel ou responder ele próprio a um prompt. A palavra-passe de gestão e o ficheiro de credenciais são segredos da mesma classe, e ambos merecem o mesmo cuidado.

Qual encaixa na implementação

Escolha o ficheiro de credenciais quando o único prompt é o par de conta, o cliente corre como serviço com um proprietário estável e consegue manter um ficheiro 600 fora de cópias de segurança que não controla. Escolha o socket de gestão quando está em jogo uma frase-passe de chave ou uma palavra-passe PKCS#12, quando o wrapper já supervisiona o processo, ou quando precisa de observar estado e prompts enquanto depura uma reconexão.

Duas condições movem a decisão. Se o wrapper for /bin/sh, uma unidade systemd que chama o binário diretamente, ou um contentor mínimo, a cola de socket só para bash não está disponível e o ficheiro é a resposta mais barata. Se o segredo roda com frequência, nenhum ficheiro é um bom lar para ele: consulte um porta-chaves a partir de um pequeno wrapper e deixe a unidade chamar o wrapper, o que mantém a rotação num só lugar e a palavra-passe fora do histórico da shell.

A substituição de processos fica entre os dois e não pertence a nenhum. A linha única abaixo funciona porque o bash a expande antes de o openvpn arrancar, não porque o cliente compreenda a sintaxe:

openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")

Quebra sob /bin/sh, numa unidade que contorna a shell e em imagens sem bash nem /dev/fd. Guarde-a para testes interativos, nunca como o contrato de que um serviço depende.

Proteja o segredo e depois verifique pelo registo

Ambos os mecanismos deixam um segredo legível pelo processo OpenVPN. Nunca ponha a palavra-passe na linha de comandos ou no ficheiro da unidade, onde ps e systemctl a mostram a cada utilizador local; passe o caminho para o ficheiro, não o valor dentro dele. Onde os certificados podem substituir o par de conta, isso elimina a categoria de prompt em vez de a esconder.

Uma execução correta mostra a sequência de prompts a completar-se e a sessão a atingir «Initialization Sequence Completed». Se o cliente parar no mesmo prompt, a correspondência falhou: imprima as linhas exatas que o socket enviou, verifique as aspas e o nome do prompt, e corrija o padrão em vez de acrescentar um sleep. Um túnel que relata sucesso e não transporta nada é um problema de encaminhamento ou de push, não de credenciais.

Depois teste a reconexão, não apenas o primeiro arranque. Corte a sessão do lado do servidor ou espere pelo seu tempo limite; o cliente pergunta outra vez, e é aí que um ficheiro que parecia correto no arranque mostra se ainda é legível pela conta que se reconecta.

Artigos relacionados