Configurando uma VPN no GCP com DNS e certificados Let’s Encrypt para serviços internos: Parte 1 VPN

You can’t be early, you can’t be late
It’s not a city, it’s a state
It’s not a city, it’s a state
An island
Secret, secluded and excitin’

Stanley Brinks and The Wave Pictures (2015)

Vamos compartilhar aqui um desenvolvimento que fizemos para tornar nosso ambiente mais seguro. Em boa parte dos projetos, acabamos trabalhando dentro do ambiente de nossos clientes, dessa forma respeitando as configurações de segurança de cada um dos projetos. Entretanto nos últimos meses temos desenvolvido alguns produtos internos o que tornou necessário criar o nosso próprio ambiente de desenvolvimento. Com isso veio a necessidade da criação de uma VPN para a empresa e veio a pergunta… como fazer isso? Ou melhor como fazer isso de forma simples e que não implicasse necessariamente na utilização de serviços que fossem específicos de uma determinada cloud (agnóticos).

Acho que para quem já tentou fazer o que descrevemos no título dessa publicação sabe que é simples mas nem tanto assim fazer isso. Ainda mais que gostaríamos de conseguir certificados SSL para os serviços internos. Em uma vasculhada pela rede não encontrei nada que fosse muito padrão a esse respeito sendo que muitas soluções criavam aberturas na VPN para a validação do domínio (o que pode trazer algum risco) ou mesmo não eram muito automatizadas.

Esse é o primeiro artigo de 3 que vamos explicar como fizemos para criar o ambiente, passar por algumas configurações e algumas ideias que tivemos para cercar o máximo aplicando a ideia de trust no one para o nosso ambiente interno.

Criação da VPN no GCP:

Bom a primeira coisa que fizemos foi separar a VPN em um projeto específico para facilitar a criação e monitoramento dos acesso à infra. Para isso criamos um novo projeto:

Criação de um novo projeto no GCP

 

Quando se cria um projeto no GCP automaticamente é criada uma rede default com as sub-redes mapeadas para todas as regiões disponíveis. No nosso caso como vamos criar uma VPN achamos prudente criar um outra rede em separado para que ela possa eventualmente se compartilhada entre projetos se necessário:

Acessando a aba com as VPNs dentro do projeto
Criando uma nova VPN para o projeto
Só colocar o nome na rede pode ser VPN mesmo… criatividade não é uma coisa boa quando se está dando nomes em programação

Reservando os IP para a conexão:

Bom agora temos uma VPN! Mas não conseguimos nos conectar a ela :(… para fazer a conexão usamos um servidor de ponte do tipo OpenVPN (ou algo similar). Achei bem simples para fazer a configuração, só é necessário adquirir um licença que é decorrente do número de usuários com acesso simultâneo (até dois sai de graça), mas a compra é super simples e pode ser feita no site do cloud da OpenVPN e depois colocar a chave de acesso. Antes de fazer o deploy do servidor de ponte, é interessante já reservar um endereço estático para associar à maquina.

Reservando um endereço de IP estático para a ponte com a VPN.
Configurando o IP externo que setá utilizado para acessar o servidor de ponte da VPN.

 

Configuramos o IP para estar alocado na região que vamos fazer o deploy do servidor de ponte. Como todos nossos colaboradores ficam no Brasil, faz sentido usar a região de São Paulo para reduzir a latência das conexões, só torcer para não ter apagão 😐

Depois de alocar o IP, isso demora um pouco (1 minuto às vezes)… vai ser associado um endereço pelo qual no futuro os usuários poderão se conectar à ponte da VPN.

IP para ser usado no servidor de ponte do OpenVPN

 

Criando o servidor de ponte OpenVPN

Para criar o servidor de ponte foi utilizado o Cloud Deployment Manager, nunca consigo achar ele no menu de navegação da esquerda… menor ideia de onde ele se esconde! De qualquer forma dá para usar a pesquisa para tirar ele do esconderijo.

Achando o Cloud Deployment Manager

 

Aqui vamos definir as configurações. O tamanho da máquina não precisa ser muito grande, o processo de criptografia e tunelamento não precisa de muita memória, a restrição costuma ser pelo CPU, mas ainda assim a demanda é bem pequena. É importante configurar que esteja na rede que criamos anteriormente na sub-rede de São Paulo, fora isso deve se associar o IP externo ao IP que foi reservado nos passos anteriores.

Em vermelho a rede dever ser seleciona a rede que foi criada para a VPN. Em verde deve ser selecionado o IP que foi reservado

 

Quando foi requisitada a criação o deployment vai criar uma máquina virtual para o servidor do OpenVPN e as regras de firewall de forma a permitir a conexão com a máquina.

Criando um banco MySQL para guardar as informações do OpenVPN

Por definição o OpenVPN guarda as informações em disco, isso não é a melhor forma de implementar o OpenVPN e é recomendado migrar para um backend usando um banco de dados. Para isso vamos utilizar um banco gerenciado do Google também para facilitar o desenvolvimento. Para isso vá na aba SQL no GCP, clique para a criação de uma nova instância e escolha o MySQL.

 

Peça para criar um banco de dados padrão (MySQL 5.7) gerando uma senha forte para o usuário raiz, pode-se colocar a disponibilidade para uma única zona. O importante é não deixar o banco acessível externamente e associar ele à rede que vamos utilizar na VPN para isso deve-se clicar em mostrar opões de configuração. Nela existe algumas opções:

Tipo de máquina:

No caso o banco de dados vai só ser o backend da VPN usado principalmente no inicio da conexão do usuário, por isso pode-se usar uma máquina muito simples para reduzir o custo (nossa tem 1vCPU e 1.7Gb de memória).

Armazenamento:

Mesma coisa do tipo de máquina, vai ser necessário um disco pequeno (usamos 20Gb)

Conexões:

Aqui tem uma parte importante… por definição o SQL do Google pressupõe que vamos nos conectar a ele de forma externa, o que é errado para o nosso caso. A unica máquina que vai ser conectar a esse banco vai ser o servidor do OpenVPN, por isso ele deve ser alocado apenas no IP particular sem abertura para a internet. Fora isso é necessário associar o SQL à mesma rede da VPN que está o servidor.

Aqui conectamos o SQL à rede de VPN e especificamos que não haverá um IP público para o banco de dados

 

Com isso vamos criar um banco de dados que não está acessível a internet, mas que pode ser conectado por dentro da VPN. Depois da criação ao banco será associado um IP interno na rede, para não usar o usuário root, podemos criar um novo usuário no banco de dados para que o OpenVPN se conecte.

Instância que foi criada para servir o MySQL. Em vermelho encontra-se o IP interno da rede que pode ser utilizado para conexão
No nosso caso criamos um usuário chamado VPN para ser usado pelo OpenVPN no banco de dados

Configurando o servidor do OpenVPN

Bom a primeira coisa que temos que fazer é trocar a senha do usuário OpenVPN, isso pode ser feito por SSH no próprio GCP, para ver um tutorial, pode ser verificar esse link. Depois é necessário acessar o admin do Open VPN, quando você tentar entrar no site do admin vai receber uma mensagem tenebrosa…

Certificados self-assign produzem uma mensagem incisiva nos navegadores modernos

 

Isso ocorre porque a conexão com o Admin do OpenVPN é feito por um certificado do tipo self-assign (o próprio servidor criou o certificado). O que ocorre é que não tem como criar um certificado externo sem associar o IP à um DNS (nome do ip aka www.google.com ou coisa do tipo). No nosso caso não chega a ser um problema muito grave (a conexão está encryptada de qq forma), vamos tomar outras providências para deixar o servidor seguro por firewall de forma a minimizar o problema. Você vai ter que confiar em mim e clicar em proceed XXX (unsafe), vai na fé :).

Depois desse teste de fé você vai cair na tela de login do admin do OpenVPN, use o usuário openvpn e a senha que você modificou por SSH.

 

Migrando o banco de dados para o MySQL

Primeira coisa que vamos fazer é migrar o banco de dados que está local para o MySQL. Assim podemos fazer backups periódicos e dá para escalar o servidor em cluster se necessário.

Basicamente você terá que ir nos tools de db convert e preencher o formulário com os dados de conexão com o banco de dados que criamos anteriormente, depois só mandar rodar que as transformações vão ser aplicadas e o OpenVPN passará a usar o MySQL como backend.

Obrigar os usuários a utilizarem autenticação de dois fatores para acessar a VPN

Na aba authentication/general, é possível obrigar os usuário a cadastrarem uma autenticação de dois fatores, assim a cada momento que forem conectar à VPN será necessário um desafio para fazer a autenticação de dois fatores usando por exemplo o Google Autheticator. É meio mala, pessoal vai reclamar, mas trust no-one!

Permitir os usuário acessarem a internet usando a VPN

Dessa forma todos os usuários conectados à VPN terão o mesmo IP público, o que torna possível configurar de forma mais correta os firewalls dos demais projetos.

 

Em vermelho a configuração que permite acessar os demais recursos da rede VPN e em verde as configurações que permitem o usuário acessar a internet usando o IP do servidor.

 

Lembrando só que como a VPN foi configurada em um ambiente separado dos demais, o usuários só terão acesso ao que for colocado dentro da VPN deixando cada projeto independente. É possível modificar a sub-rede que os usuários tem acessos específicos para segmentar melhor a segurança.

Restringir o acesso ao admin para ser feito através apenas da VPN e manter o client público

O admin não é protegido por uma autenticação de dois fatores, dessa forma é bom que esteja mais escondido dentro da VPN. O que pode ser feito é servir o admin em uma porta diferente do end-point onde os usuários baixam as próprias chaves, dessa forma pode-se criar regras de firewall que impedem a conexão com essa porta de fora da VPN ou mesmo habilitar algum IP específico (do sysadmin, por exemplo).

 

Definir que os usuários tenham IPs fixos e impedir a comunicação entre usuários

Dentro das configurações da VPN é possível definir IPs fixos para cada um dos usuários, isso basicamente vai impedir que eles saiam andando pela rede interna sem crachá. Dá para usar o IP de cada um depois para monitorar os logs dos servidores o que pode ser mais uma camada de segurança dentro da rede (sub-firewalls) ou monitoramento.

Outro ponto que pode ser feito é impedir que os usuários conversem entre si, não vejo que um computador de usuário tem que ficar conversando com outro sem ser servidor. Acho que isso (bem chutando mesmo) pode reduzir a propagação caso alguém esteja infectado com uma moléstia cibernética.

Próximos passos: Configuração de um servidor de DNS interno

Usando a VPN é possível se conectar de forma segura as aplicações que forem disponibilizadas na rede interna, mas isso ainda deve ser feito pelo IP da aplicação. Isso torna a utilização muito mais complicada, seria como pedir para um usuário digitar 10.232.1.10 no lugar de sistemarh.murabei.internal (muito mais fácil). Mas para que o computador saiba que 10.232.1.10 é o sistemarh.murabei.internal é necessário que o DNS informe isso, outra possibilidade é “instalar” uma tabela de DNS em todos os computadores. Isso dá muito trabalho e se tiver que migrar isso um dia vai dar mais trabalho ainda, como sou bom programador (acho pelo menos) logo sou preguiçoso (no melhor sentido da palavra).

Bons programadores são preguiçosos, vaidosos e impacientes (Larry Wall) não necessariamente nessa ordem. Extraído de Giphy.

Incluir IPs internos em servidores de DNS públicos é dar o mapa da rede interna para qualquer um, esconder não é uma técnica de proteção, mas também não custa nada não sair espalhando a planta banco só porque se confia no cofre. Outra questão é que isso torna os DNS bagunçados, pois vários endereços públicos passam a apontar para o mesmo IP (cada empresa poderia ter um sistema apontando para o mesmo 10.232.1.10).

Para contornar isso podemos criar o nosso próprio servidor de DNS! Isso pode ser feito através do próprio GCP usando o deployment com o Bind9. Vemos isso no nosso próximo post…

Compartilhar