Múltiples VPNs interconectadas con OpenVPN y iptables

Crear una red privada virtual (VPN) mediante OpenVPN es muy fácil y permite de manera sencilla conectar múltiples equipos de manera segura usando cualquier conexión a Internet. Cuando conectamos múltiples equipos surge la duda de como gestionar la comunicación entre ellos.

Cada equipo conectado a la VPN recibe una IP privada de un rango definido para esa VPN. El software OpenVPN permite configurar la VPN para que actúe como una red local de manera que la comunicación entre todos los equipos conectados puede realizarse directamente sin ningún filtro ni protección. Esto puedo ser útil en la mayoría de los casos, cuando todos los equipos forman parte de la misma organización y se busca la facilidad de configuración. Para conseguir este efecto utilizamos la directiva 'client-to-client'.

La alternativa consiste en no indicar esa directiva. En ese caso el servidor OpenVPN lo que hace es reenviar los paquetes que pretenden ir de equipo a equipo dentro de la VPN al kernel del servidor donde se ejecuta. Este comportamiento nos permite, combinado con iptables, una flexibilidad total en la gestión de permisos. Podemos crear reglas que permitan o limiten el tráfico a nivel equipos y/o servicios (IPs y/o puertos).

Si además combinamos esto con subredes y múltiples instancias de OpenVPN tenemos poderosas herramientas para planificar nuestra red con el máximo detalle.

A continuación uno ejemplo de una configuración con dos instancias VPN, basado en un caso real, en el que tenemos una VPN de administración propia y otra VPN para clientes.

Introducción

La instalación básica del software es muy sencilla, se puede seguir el HOW-TO oficial para más detalles.Queremos montar varias VPN para nuestros clientes, queremos que dos usuarios de la misma VPN no se puedan ver, pero necesitamos que los usuarios de la VPN-Empresa si que puedan ver a los usuarios de otras VPN para poder tener acceso para administración de las maquinas.

 Instalación

Primero tenemos que escoger un nombre para la nueva vpn, por ejemplo test.

Necesitamos un directorio donde generar los pares de claves para la nueva vpn, copiaremos los ficheros por defecto de /usr/share/doc/openvpn/examples/:

sb3:/# cd /usr/share/doc/openvpn/examples/  
sb3:/usr/share/doc/openvpn/examples# cp -R easy-rsa/2.0 /etc/openvpn/rsa-test  

Modificamos el fichero vars del directorio /etc/openvpn/rsa-test modificando las siguientes lineas:

# Increase this to 2048 if you
# are paranoid.  This will slow
# down TLS negotiation performance
# as well as the one-time DH parms
# generation process.
export KEY_SIZE=2048  
# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY=ES  
export KEY_PROVINCE=BCN  
export KEY_CITY=Barcelona  
export KEY_ORG="TestVPN"  
export KEY_EMAIL="soporte@empresa.com"  

Ejecutamos los comandos para generar la Autoridad de Certificacion y las claves para el servidor:

sb3:/etc/openvpn/rsa-test# . ./vars  
NOTE: when you run ./clean-all, I will be doing a rm -rf on /etc/openvpn/rsa-test/keys  
sb3:/etc/openvpn/rsa-test# ./clean-all  
sb3:/etc/openvpn/rsa-test# ./build-ca  
Generating a 2048 bit RSA private key  
..................................+++
............+++
writing new private key to 'ca.key'  
-----
You are about to be asked to enter information that will be incorporated  
into your certificate request.  
What you are about to enter is what is called a Distinguished Name or a DN.  
There are quite a few fields but you can leave some blank  
For some fields there will be a default value,  
If you enter '.', the field will be left blank.  
-----
Country Name (2 letter code) [ES]:  
State or Province Name (full name) [BCN]:  
Locality Name (eg, city) [Barcelona]:  
Organization Name (eg, company) [TestVPN]:  
Organizational Unit Name (eg, section) []:TestVPNCA  
Common Name (eg, your name or your server's hostname) []:TestVPNCA  
Email Address [soporte@empresa.com]:  
sb3:/etc/openvpn/rsa-test# ./build-key-server server  
Generating a 2048 bit RSA private key  
...........................................+++
.....................................+++
writing new private key to 'server.key'  
-----
You are about to be asked to enter information that will be incorporated  
into your certificate request.  
What you are about to enter is what is called a Distinguished Name or a DN.  
There are quite a few fields but you can leave some blank  
For some fields there will be a default value,  
If you enter '.', the field will be left blank.  
-----
Country Name (2 letter code) [ES]:  
State or Province Name (full name) [BCN]:  
Locality Name (eg, city) [Barcelona]:  
Organization Name (eg, company) [TestVPN]:  
Organizational Unit Name (eg, section) []:  
Common Name (eg, your name or your server's hostname) []:TestVPNServer  
Email Address [soporte@empresa.com]:  
Please enter the following 'extra' attributes  
to be sent with your certificate request  
A challenge password []:  
An optional company name []:  
Using configuration from /etc/openvpn/rsa-test/openssl.cnf  
Check that the request matches the signature  
Signature ok  
The Subject's Distinguished Name is as follows  
countryName           :PRINTABLE:'ES'  
stateOrProvinceName   :PRINTABLE:'BCN'  
localityName          :PRINTABLE:'Barcelona'  
organizationName      :PRINTABLE:'TestVPN'  
commonName            :PRINTABLE:'TestVPNServer'  
emailAddress          :IA5STRING:'soporte@empresa.com'  
Certificate is to be certified until Jun  3 17:32:14 2016 GMT (3650 days)  
Sign the certificate? [y/n]:y  
1 out of 1 certificate requests certified, commit? [y/n]y  
Write out database with 1 new entries  
Data Base Updated  
sb3:/etc/openvpn/rsa-test# ./build-dh  
Generating DH parameters, 2048 bit long safe prime, generator 2  
This is going to take a long time  
...............................................................................................................

Por ultimo necestamos un directorio donde guardar las ips de los clientes:

sb3:/etc/openvpn/rsa-test# mkdir ../ccd-test
 Configuración
 Servidor

En el directorio /etc/openvpn/ vamos a tener tantos ficheros server*.conf como VPN queramos. El fichero serverEmpresa.conf quedaria de la siguiente forma:

port 9760  
proto udp  
dev tun51  
ca easy-empresa/keys/ca.crt  
cert easy-empresa/keys/server.crt  
key easy-empresa/keys/server.key  # This file should be kept secret  
dh easy-empresa/keys/dh2048.pem  
server 10.34.21.0 255.255.255.0  
ifconfig-pool-persist ipp.txt  
push "route 10.34.22.0 255.255.255.0"  
client-config-dir ccd-empresa  
keepalive 10 120  
tls-auth ta.key 0 # This file is secret  
comp-lzo  
user nobody  
group nogroup  
persist-key  
persist-tun  
status openvpn-status-empresa.log  
log openvpn-empresa.log  
verb 3  

El fichero serverClientes.conf es el siguiente:

port 9761  
proto udp  
dev tun52  
ca easy-clientes/keys/ca.crt  
cert easy-clientes/keys/server.crt  
key easy-clientes/keys/server.key  # This file should be kept secret  
dh easy-clientes/keys/dh2048.pem  
server 10.34.22.0 255.255.255.0  
ifconfig-pool-persist ipp.txt  
push "route 10.34.21.0 255.255.255.0"  
client-config-dir ccd-clientes  
keepalive 10 120  
tls-auth ta.key 0 # This file is secret  
comp-lzo  
user nobody  
group nogroup  
persist-key  
persist-tun  
status openvpn-status-clientes.log  
log openvpn-clientes.log  
verb 3  

Las diferencias entre los dos ficheros son:

  • port: Cada VPN necesita un puerto diferente.
  • dev: Cada VPN tendra su porpia interficie de red.
  • server: Cada VPN tiene su rango de ip's
  • client-config-dir: Cada VPN utilizara un directorio diferente donde indicar los usuarios que tiene.
  • push route: Cada VPN tiene sus propios push de rutas a los clientes, estos definen las VPN's que van a ver los clientes, Por ejemplo la VPN de Empresa tendrà rutas para todas las otras VPN's pero la VPN d'clientes, solo tendrà push a la de Empresa, porque no tiene porque ver las VPNs de los otros clientes.
  • certs: Cada VPN tendrà sus propios certificados
  • logs
 Cliente

En el cliente, el fichero de configuración seria el siguiente:

client  
dev tun  
proto udp  
remote 192.168.1.39 9761  
resolv-retry infinite  
nobind  
persist-key  
persist-tun  
ca ca.crt  
cert francesc.crt  
key francesc.key  
ns-cert-type server  
tls-auth ta.key 1  
comp-lzo  
verb 3  

La única operación importante és la linea 'remote', que es donde indicas qual és el servidor y el puerto donde esta la VPN, el puerto define a que VPN estas accediendo y los certificados si puedes acceder a ella.

 Configuración de red del servidor

Para que en el servidor se puedan reenviar los paquetes entre las interficies de dos VPNs, tun51 y tun52, tenemos que permitir el ip_forwarding, para hacer esto tenemos que ejecutar la siguiente comanda:

echo 1 > /proc/sys/net/ipv4/ip_forward

Si tenemos prohibidos los FORWARDs entre interficies tendremos que ejecutar las siguentes reglas en el iptables:

VPN_EMPRESA="tun51"  
VPN_EMPRESA_IP="10.34.21.1"  
VPN_EMPRESA_RANGE="10.34.21.0/24"  
VPN_CLIENTES="tun52"  
VPN_CLIENTES_IP="10.34.22.1"  
VPN_CLIENTES_RANGE="10.34.22.0/24"  
# discard source address check for packets coming from the VPN-EMPRESA or VPN-CLIENTES
$IPT -I source-address-check 1 -i $VPN_EMPRESA -s $VPN_EMPRESA_RANGE -j RETURN
$IPT -I source-address-check 1 -i $VPN_CLIENTES -s $VPN_CLIENTES_RANGE -j RETURN
###############################################################
# VPN-EMPRESA-input
logger -s [FIREWALL] Setting custom chains: VPN-input  
$IPT -N VPN-EMPRESA-input
# Incoming TCP connections
$IPT -A VPN-EMPRESA-input -p tcp -m multiport --dport 22,25,53,80,110,225,443,993,995,3333,8080 -m state --state NEW -j ACCEPT
# Reject incoming AUTH requests with RST
$IPT -A VPN-EMPRESA-input -p tcp --sport $UNPRIVPORTS --dport 113 -j REJECT --reject-with tcp-reset
#.............................................................
# ICMP
$IPT -A VPN-EMPRESA-input -p icmp -j icmp-in
###############################################################
# VPN-CLIENTES-input
logger -s [FIREWALL] Setting custom chains: VPN-input  
$IPT -N VPN-CLIENTES-input
# Incoming TCP connections
$IPT -A VPN-CLIENTES-input -p tcp -m multiport --dport 22,8080 -m state --state NEW -j ACCEPT
# Reject incoming AUTH requests with RST
$IPT -A VPN-CLIENTES-input -p tcp --sport $UNPRIVPORTS --dport 113 -j REJECT --reject-with tcp-reset
#.............................................................
# ICMP
$IPT -A VPN-CLIENTES-input -p icmp -j icmp-in
# Begin standard firewall tests for packets addressed to this host
$IPT -A INPUT -i $VPN_EMPRESA -d $VPN_EMPRESA_IP -j VPN-EMPRESA-input
$IPT -A INPUT -i $VPN_CLIENTES -d $VPN_CLIENTES_IP -j VPN-CLIENTES-input
# Begin standard firewall tests for packets sent from this host
# Source address spoofing by this host is  not allowed due to the
# test on source address in this rule.
$IPT -A OUTPUT -o $VPN_EMPRESA -s $VPN_EMPRESA_IP -j ACCEPT
$IPT -A OUTPUT -o $VPN_CLIENTES -s $VPN_CLIENTES_IP -j ACCEPT
###############################################################
# VPN-EMPRESA-to-VPN-CLIENTES
logger -s [FIREWALL] Setting custom chains: VPN-EMPRESA-to-VPN-CLIENTES  
$IPT -N VPN-EMPRESA-to-VPN-CLIENTES
$IPT -A VPN-EMPRESA-to-VPN-CLIENTES -p tcp -m multiport --dport 5900,8080 -m state --state NEW -j ACCEPT
#............................................................
# ICMP 
$IPT -A VPN-EMPRESA-to-VPN-CLIENTES -p icmp -j icmp-out
# VPN entre EMPRESA y CLIENTES
$IPT -A FORWARD -i $VPN_EMPRESA -s $VPN_EMPRESA_RANGE -o $VPN_CLIENTES -d $VPN_CLIENTES_RANGE -j VPN-EMPRESA-to-VPN-CLIENTES