sexta-feira, 20 de março de 2020

Configurando VPN IPsec site-to-site FreeBSD


Recentemente tive que fazer uma VPN site-to-site na empresa onde trabalho, normalmente o pessoal acaba utilizando Linux pra isso, mas para essa empreitada decidi utilizar o FreeBSD, que tem uma vantagem ao meu ver que é, poder atualizar de uma versão major para outra sem necessidade de formatação, à já conhecida estabilidade do seu SO e também por possuir o PF como firewall para filtro de pacotes. Como não há praticamente "how-to" desse tipo de coisa na internet, foi um trabalho hercúleo de ser feito, mas vou deixar registrado aqui como proceder, assim ajudando mais pessoas na configuração de VPN's do tipo IPsec.


O FreeBSD tem como missão a estabilidade, ou seja, serviços de rotas de VPN, integração com filtro de pacotes e afins no kernel, não existem, justamente para preservar o kernel de possíveis instabilidades.

Dito isso,  vamos a configuração de fato:

OBS: Esse tutorial parte do pressuposto que você já tenha um FreeBSD instalado e com internet para download de pacotes e configuração do túnel.

1 - A primeira coisa à ser feita é ativar no arquivo "/etc/rc.conf" o firewall PF para filtragem de pacotes, devemos inserir as seguintes linhas no arquivo:

#Habilita FW
pf_enable="YES"   ## habilita o PF no boot do sistema
pf_rules="/etc/pf.conf" ## arquivo onde as regras serão inseridas
pflog_enable="YES" ## habilita o PF para logar o tráfego passante
pflog_logfile="/var/log/pflog" ## arquivo de log do PF

2 - Depois devemos ativar a interface de encapsulamento do túnel IPsec no kernel, por padrão isso não vem ativo. Insira a seguinte linha no arquivo "/boot/loader.conf"

if_enc_load="YES"

Devemos também ativar essas flags sugeridas no arquivo "/etc/sysctl.conf", conforme sugerido na man da interface:

net.enc.out.ipsec_bpf_mask=1
net.enc.out.ipsec_filter_mask=1
net.enc.in.ipsec_bpf_mask=2
net.enc.in.ipsec_filter_mask=2

Os valores acima são inseridos para que o tráfego seja filtrado pelo firewall

Man da interface: https://www.freebsd.org/cgi/man.cgi?query=enc&sektion=4&manpath=freebsd-release-ports

Também devemos inserir no arquivo "/etc/rc.conf" a linha para inicialização da interface enc0

ifconfig_enc0="up"

Após executar as configurações acima, vamos efetuar o reboot da máquina.

3 - Depois de rebootar a máquina, agora com a interface enc0 e o PF já ativo, vamos instalar o pacote strongswan para configuração do túnel da VPN:

# pkg install strongswan

Depois devemos ativar o strongswan no boot do sistema com  o comando abaixo:

# sysrc strongswan=YES

Com o comando acima, é inserida uma linha no arquivo "/etc/rc.conf" para inicialização do serviço junto ao sistema

4 - Agora vamos configurar o nosso túnel no arquivo de configuração "/usr/local/etc/ipsec.conf"

# ipsec.conf - strongSwan IPsec configuration file

config setup
        charondebug="all"
        uniqueids=yes
        strictcrlpolicy=no

conn %default

conn site1-site2  # nome da conexao
        auto=route  # parametro que informa ao strongswan, que ele é roteado via PF
        left=1.1.1.1 # IP válido do nosso lado do tunel
        leftsubnet=10.10.0.0/24 #Rede inválida da LAN do nosso lado
        ike=aes256-sha2_256-modp1024! # Criptografia de fase 1 do túnel
        esp=aes256-sha2_256-modp1024! # Criptografia de fase 2 do túnel
        ikelifetime=1h  #Tempo de expiração para renegociação das chaves
        lifetime=24h # Quanto tempo a conexão deve durar desde a conexão até a expiração
        keyexchange=ikev2 # Tipo de chave de troca de conexão
        authby=secret # Método de autenticação
        type=tunnel # Tipo de conexão, por padrão é túnel
        right=2.2.2.2  # IP válido do outro lado do túnel
        rightsubnet=10.10.10.0/24 # Rede inválida do outro lado do túnel

5 - Outra coisa que devemos fazer é trocar a configuração dentro do arquivo "/usr/local/etc/strongswan.conf" na opção "install_routes" de "yes" para "no" conforme segue:

# strongswan.conf - strongSwan configuration file
#
# Refer to the strongswan.conf(5) manpage for details
#
# Configuration changes should be made in the included files

charon {
        install_routes = no
        load_modular = yes
        plugins {
                include strongswan.d/charon/*.conf
        }
}


Caso essa opção se mantenha ativa, gera uma tabela de rotas paralelas, o que nos meus testes não se mostrou muito recomendado, porque quando fica no valor default ele gera uma rota do site2 apontando para o IP válido da interface externa. No meu caso que o roteador à frente era BSD, o pacote saia com source de ip inválido tentando sair pra internet, gerando descarte do pacote.

6 - Feita a configuração acima, devemos inserir a chave de negociação do túnel no arquivo "/usr/local/etc/ipsec.secrets", conforme exemplo:

# ipsec.secrets - strongSwan IPsec secrets file
1.1.1.1 2.2.2.2 : PSK IE7ChwWERTIW123@#$

Lembrando que a chave deve ser a mesma nos dois lados e a chave é gerada pelo administrador.

7 - Após isso, podemos já subir o túnel através do comando:

# service ipsec start

E para vermos se o túnel está ok, executamos o comando:

# ipsec status

# ipsec status
Routed Connections:
  site1-to-site2{1}:  ROUTED, TUNNEL, reqid 1
  site1-to-site2{1}:  10.10.0.0/24 === 10.10.10.0/24
Security Associations (1 up, 0 connecting):
  site1-to-site2[31]: ESTABLISHED 10 minutes ago, 1.1.1.1[1.1.1.1]...2.2.2.2[2.2.2.2]
  site1-to-site2{32}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: c9896268_i 0926547e_o
  site1-to-site2{32}:   10.10.0.0/24 === 10.10.10.0/24


7 - Para que o túnel funcione corretamente, devemos agora sim, inserir uma rota manualmente para o nosso túnel strongswan, conforme segue:

 - Inserção via terminal
# route add -net 10.10.10.0/24 10.10.0.1 #Primeiro campo de IP rota do site2 e o segundo IP é nosso servidor

Para haver resiliência do servidor, devemos inserir as rotas no arquivo "/etc/rc.local", como uma rota estática da interface de LAN do nosso equipamento conforme segue:

ifconfig_xn0="inet 10.10.0.1 netmask 255.255.255.0"
static_routes="ipsec"
route_ipsec="-net 10.10.10.0/24 10.10.0.1"

8 - Para que seja possível rotear os pacotes através do túnel e ocorrer comunicação entre as redes devemos ativar a flag de encaminhamento do kernel no arquivo "/etc/sysctl" conforme segue:

net.inet.ip.forwarding=1

Para já conseguirmos rotear sem reiniciar o servidor, devemos executar o comando:

# sysctl -p /etc/sysctl.conf


Após efetuar os passo acima, a VPN entre as redes já estará UP e totalmente funcional.


Agora vem a segunda parte dessa missão, que é onde o meu cenário se encaixa.
Digamos que seu FreeBSD tenha mais redes atrás da LAN que não a diretamente conectada e tais redes também necessitem comunicar com as máquinas do outro lado do túnel IPsec, abaixo descrevo como proceder nesses casos:


1 - Devemos primeiro inserir no PF uma regra de src-nat(no Linux postrouting) para que as requisições para a rede do site2 saiam com o IP da rede local do tunel VPN. Devemos inserir a seguinte regra no arquivo do nosso firewall que está em "/etc/pf.conf"

#src-nat para acesso da nossa rede com o IP do servidor de VPN
nat on enc0 from 10.10.0.0/16 to 10.10.10.0/24 -> 10.10.0.1

2 - Agora vem o pulo do gato, que mais me custou tempo na configuração disso tudo, quando você sobe o túnel, são criadas rotas no kernel que ficam dentro de uma base de dados de rotas do IPsec que não são visíveis via comando ipsec, para visualizarmos as rotas já inseridas, executamos o seguinte comando:

#setkey -DP

10.10.10.0/24[any] 10.10.0.0/24[any] any
        in ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        created: Mar 19 16:58:11 2020  lastused: Mar 19 16:58:11 2020
        lifetime: 9223372036854775807(s) validtime: 0(s)
        spid=5 seq=2 pid=10314 scope=global
        refcnt=1
10.10.0.0/24[any] 10.10.10.0/24[any] any
        out ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        created: Mar 19 16:58:11 2020  lastused: Mar 19 16:58:11 2020
        lifetime: 9223372036854775807(s) validtime: 0(s)
        spid=6 seq=0 pid=10314 scope=global
        refcnt=1

Você pode se perguntar, porque não inseriu só no campo "left" do tunel o /16 e segue o jogo, certo? Pois é, é viável, mas o /16 sobrepõe a rede do nosso site2, que no caso em questão é uma rede que não está sob minha gerência, logo não posso trocar pra outro range.

3 - Para fazermos isso dentro da tabela de roteamento do ipsec, devemos ativar um arquivo de rotas no "/etc/rc.conf", da seguinte forma:

ipsec_enable="YES"               # Configura como sim, para rodar o setkey no arquivo ipsec_file
ipsec_file="/etc/ipsec.conf"    # Nome do arquivo onde será inserido o setkey

4 - Após isso, vamos inserir as linhas no arquivo para que dentro da tabela de rotas do ipsec, comporte nosso /16 e o nat seja executado com sucesso.

As regras abaixo devem ser inseridas no arquivo "/etc/ipsec.conf"

#ipsec out
spdadd -4 10.10.0.0/16 10.10.10.0/24 any -P out ipsec esp/tunnel/1.1.1.1-2.2.2.2/unique:1;
#ipsec in
spdadd -4 10.10.10.0/24 10.10.0.0/16 any -P in ipsec esp/tunnel/1.1.1.1-2.2.2.2/unique:1;

OBS: O número 1 ao lado do unique, é o número de identificação do túnel na tabela de rotas.

5 - Após isso feito, depois de reiniciarmos o serviço do strongswan, a tabela de rotas ipsec ficará dessa forma:

root@vpn-ipsec:~ # setkey -DP
10.10.10.0/24[any] 10.10.0.0/16[any] any
        in ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        spid=2 seq=3 pid=21756 scope=global
        refcnt=1
10.10.10.0/24[any] 10.10.0.0/24[any] any
        in ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        created: Mar 20 10:20:01 2020  lastused: Mar 20 10:20:01 2020
        lifetime: 9223372036854775807(s) validtime: 0(s)
        spid=5 seq=2 pid=21756 scope=global
        refcnt=1
10.10.0.0/16[any] 10.10.10.0/24[any] any
        out ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        spid=1 seq=1 pid=21756 scope=global
        refcnt=1
10.10.0.0/24[any] 10.10.10.10.0/24[any] any
        out ipsec
        esp/tunnel/1.1.1.1-2.2.2.2/unique:1
        created: Mar 20 10:20:01 2020  lastused: Mar 20 10:20:01 2020
        lifetime: 9223372036854775807(s) validtime: 0(s)
        spid=6 seq=0 pid=21756 scope=global
        refcnt=1


Após esses passos, é possível conectar via tunel IPsec com nat de outras redes.

Alguns link's que me foram úteis nessa empreitada:

Setkey https://www.freebsd.org/cgi/man.cgi?query=setkey&sektion=8&manpath=freebsd-release-ports

Enc0: https://www.freebsd.org/cgi/man.cgi?query=enc&sektion=4&manpath=freebsd-release-ports

PF: https://www.freebsd.org/cgi/man.cgi?pf(4)

Strongswan: https://www.freebsd.org/cgi/man.cgi?query=%20strongswan.conf&manpath=FreeBSD+Ports+9.2-RELEASE

Ipsec: https://www.freebsd.org/cgi/man.cgi?query=ipsec.conf

Tabela de rotas: https://www.freebsd.org/cgi/man.cgi?route


Por hoje é só have a nice day =D


Nenhum comentário:

Postar um comentário