OpenVPN é um sistema de rede virtual privada (VPN), usado pra criar conexões seguras entre dispositivos, protegendo a troca de informações mesmo em trajetos não confiáveis, como a internet. Implementa tanto aplicação de servidor quanto de cliente e é distribuído sob a licença GPL-2.0.
O sistema funciona com base em infraestrutura de chave pública (PKI). Pra configurar a autenticação de forma segura é necessário gerar certificados SSL e chaves para uma autoridade certificadora (CA), para o servidor e para os clientes da VPN.
Felizmente, não precisamos tocar diretamente no OpenSSL, que é bem complexo. Em vez disso, a gente usa o EasyRSA, uma ferramenta que nos ajuda a gerar as chaves e certificados que a gente precisa.
Considerando uma instalação do Debian ou Ubuntu server:
# apt install openvpn easy-rsa
Pra facilitar e deixar a configuração organizada, copie a pasta do EasyRSA para dentro da pasta de configuração do OpenVPN.
# cp -r /usr/share/easy-rsa /etc/openvpn/
Vá para a pasta /etc/openvpn/easy-rsa, edite copie o arquivo vars.example como var e descomente as linhas que quiser editar de acordo com a sua preferência. Configurações sugeridas:
set_var EASYRSA_KEY_SIZE 4096
set_var EASYRSA_CERT_EXPIRE 731
set_var EASYRSA_CRL_DAYS 366
set_var EASYRSA_FIX_OFFSET 30
Dessa forma, os certificados serão válidos por 2 anos, a lista de revogação de certificados (CRL) por 1 ano, e todos os certificados vão ser emitidos com validade fixa a partir de 30 de Janeiro.
Após configurado, podemos iniciar nossa PKI e gerar o CA:
# bash easyrsa init-pki
# bash easyrsa build-ca
Ao gerar a chave do CA, uma senha será pedida pra criptografar a chave do CA.
Deve-se também gerar a chave de Diffie-Hellman, que é usada para gerar a chave simétrica da conexão de VPN a ser estabelecida.
# bash easyrsa gen-dh
Opcionalmente, para maior segurança, pode-se gerar uma chave de autenticação para que o servidor exija uma assinatura válida nos pacotes recebidos dos clientes.
# openvpn --genkey secret pki/tls-auth.key
Ao gerar o par de chaves do servidor, é uma boa ideia gerar a chave sem senha pra que o serviço possa ser iniciado junto com o sistema:
# bash easyrsa build-server-full nome_do_servidor nopass
A senha da chave do CA ainda será pedida para assinar o certificado do servidor.
Assim como para o servidor, você pode escolher deixar as chaves dos clientes com senha ou não passando o parâmetro opcional nopass.
# bash easyrsa build-client-full nome_do_cliente0 nopass
Agora, a configuração do servidor e dos clientes vai depender do propósito da VPN: pode ser um gateway, pode ser apenas para conectar um cliente ao outro, pode ser pra conectar clientes à uma LAN.
Crie um arquivo com extensão .conf na pasta /etc/openvpn server, como por exemplo config_do_servidor.conf com esse conteúdo de exemplo – adapte-o para a sua necessidade:
# Configurações da conexão
# Descomente a linha abaixo e coloque o IP do seu servidor caso ele esteja dentro de uma LAN
;local 192.168.0.10
port 1194
proto udp4
dev tun0
keepalive 10 120
persist-key
persist-tun
# As linhas abaixo determinam a rede privada que seu servidor vai criar
server 10.8.0.0 255.255.255.0
topology subnet
push "route 10.8.0.0 255.255.255.0"
# Descomente a linha abaixo e substitua a LAN pela sua caso queira que os clientes tenham uma rota para a LAN do servidor
;push "route 192.168.0.0 255.255.255.0"
# Descomente a linha abaixo caso queira que o cliente use o servidor de VPN como gateway
;push "redirect-gateway def1 bypass-dhcp"
# Configura resolvedores de DNS alternativos
;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"
# Permite que clientes da VPN possam alcançar outros
;client-to-client
# Limita o número de clientes na VPN
;max-clients 5
# Configurações do processo
verb 3
explicit-exit-notify 1
status /var/log/openvpn/status-conext00.log
# Reduz o privilégio de execução após inicialização para o usuário e grupo abaixo - em distribuições da família Fedora e Red Hat, existe um usuário openvpn próprio. O grupo nogroup não existe.
user nobody
group nogroup
# Mantém clientes com o mesmo IP na VPN
;ifconfig-pool-persist /var/log/openvpn/ipp.txt
# Certificados e chaves necessários gerados através do easy-rsa
ca ../easy-rsa/pki/ca.crt
cert ../easy-rsa/pki/issued/nome_do_servidor.crt
key ../easy-rsa/pki/private/nome_do_servidor.key
dh ../easy-rsa/pki/dh.pem
# Lista opcional de revogação de certificados
;crl-verify ../easy-rsa/pki/crl.pem
# Chave TLS opcional para maior segurança, exigindo que pacotes recebidos tenham uma assinatura válida
;tls-auth ../easy-rsa/pki/tls-auth.key 0
Observe que as linhas do tipo
push "algum parâmetro"
são configurações que também podem ser especificadas no arquivo de configuração do cliente em vez do servidor.
Precisa-se também configurar as permissões de firewall e habilitar no kernel o encaminhamento em IPv4.
Para habilitar o encaminhamento no kernel, adicione um arquivo /etc/sysctl.d/98-ip-fwd.conf com a seguinte linha:
net.ipv4.ip_forward=1
Reinicie para que tenha efeito ou
# sysctl -w net.ipv4.ip_forward=1
No firewall, para permitir conexão de clientes:
# ufw allow 1194/udp
Caso use o servidor de VPN como um gateway ou estabeleça rota do cliente para a LAN em que o servidor está:
# ufw route allow in on tun0 out on eth0
# ufw route allow in on eth0 out on tun0
E configure o protocolo NAT adicionando este trecho no topo do arquivo /etc/ufw/before.rules
### START OF MANUAL NAT CONFIG
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 10.8.0.0/24 -o tun0 -j MASQUERADE
# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT
### END OF MANUAL NAT CONFIG
Lembre-se de substituir a interface física e a rede pelas do seu servidor.
Alternativamente ao NAT, no caso da existência de uma LAN, você pode configurar no seu roteador uma rota para 10.8.0.0/24 pelo IP privado do seu servidor.
Agora basta habilitar e iniciar o serviço:
# systemctl enable --now openvpn-server@config_do_servidor.service
É isso, o servidor deve estar funcionando.
Agora precisamos que clientes se conectem. Pra isso, eles precisam de um arquivo de configuração do mesmo tipo que foi feito para o servidor. O easy-rsa não gera esses arquivos, então eu fiz um pequeno script pra resolver esse problema, que deixo em /etc/openvpn/easy-rsa/build-client-config.sh
Conteúdo do script:
#!/bin/bash
system=$1
client=$2
clients_dir=./clients
client_template_win=./clients/client.ovpn
client_template_lnx=./clients/client.conf
init() {
mkdir $clients_dir
cat <<'EOF' > $client_template_win
client
dev tun
proto udp4
remote servidor.exemplo.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
;key-direction 1
verb 3
EOF
cat <<'EOF' > $client_template_lnx
client
dev tun
proto udp4
remote servidor.exemplo.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
;key-direction 1
verb 3
user nobody
group nogroup
EOF
if ! [[ -f ./pki/ca.crt ]]; then
echo "CA não encontrado. Encerrando."
exit 1
else
echo "" | tee -a $client_template_lnx $client_template_win
echo "<ca>" | tee -a $client_template_lnx $client_template_win
cat pki/ca.crt | tee -a $client_template_lnx $client_template_win
echo "</ca>" | tee -a $client_template_lnx $client_template_win
fi
if [[ -f ./pki/tls-auth.key ]]; then
sed -i 's/;//g' $client_template_lnx $client_template_win
echo "" | tee -a $client_template_lnx $client_template_win
echo "<tls-auth>" | tee -a $client_template_lnx $client_template_win
cat pki/tls-auth.key | tee -a $client_template_lnx $client_template_win
echo "</tls-auth>" | tee -a $client_template_lnx $client_template_win
else
echo "tls-auth.key não encontrada, prosseguindo sem"
fi
}
if ! [[ -d $clients_dir ]]; then
init
exit
fi
if ! [[ -f ./pki/issued/$client.crt ]]; then
echo "Cliente não existe"
exit 1
fi
if [[ $system == "-l" || $system == "--linux" ]]; then
fileExt=conf
elif [[ $system == "-o" || $system == "--outro" ]]; then
fileExt=ovpn
else
echo "Sistema não especificado"
fi
targetFile=clients/$client.$fileExt
cp clients/client.$fileExt $targetFile
echo "" | tee -a $targetFile
echo "<cert>" | tee -a $targetFile
cat pki/issued/$client.crt | tee -a $targetFile
echo "</cert>" | tee -a $targetFile
echo "" | tee -a $targetFile
echo "<key>" | tee -a $targetFile
cat pki/private/$client.key | tee -a $targetFile
echo "</key>" | tee -a $targetFile
Pra inicializar, basta executar o script sem nenhum argumento
# bash build-client-config.sh
Ele vai criar uma pasta clients, com um template para Linux, client.conf, e outro para Windows, client.ovpn. Edite-os conforme necessário.
Feito isso, é possível criar o arquivo de configuração para um cliente existente com
# bash build-client-config.sh --linux nome_do_cliente0
ou para Windows, macOS, iOS ou Android
# bash build-client-config.sh --outro nome_do_cliente0