OpenVPN usando Ethernet Bridging

Autor: Juan Manuel Merlos (natasab@merlos.org)
Publicación: Octubre 2005b
Web: http://www.merlos.org

Change-Log:
   - Enero/2007 - Conversión de TXT a HTML

Introducción

En este texto explicaremos cuáles son los diferentes pasos para instalar OpenVPN en un servidor con el sistema operativo GNU/Linux y diferentes clientes con los sistemas operativos Windows XP y GNU/Linux.

En nuestro caso la distribución empleada es la Debian GNU/Linux 3.1 (sarge)

OpenVPN permite dos tipos de VPN una del tipo routing (VPN basadas en encaminamiento de subredes) y otra del tipo bridging (basadas en puentes a nivel físico ethernet). Este segundo método será el que comentaremos en este texto.

Esta segunda configuración es especialmente indicada para conectar lo que en la nomenclatura de VPN se denominan roadwarriors. Los roadwarriors, típicamente, son equipos portátiles que se conectan desde internet a la red local de una oficina/empresa de forma segura desde una ubicación externa a ella a través de Internet. El problema de esta configuración radica en que es algo menos eficiente y que escala peor que la otra alternativa (estamos hablando de redes de varias decenas de roadwarriors). Sin embargo, debido a que emula un puente a nivel físico este tipo de VPNs lo más parecido a que el equipo estuviera físicamente conectado a la subred de la oficina con todas las ventajas que esto conlleva.

Los requisitos previos para la comprensión de este texto son: conocimientos básicos de redes IP y conocimiento del concepto de puente ethernet, netfilter (iptables), gestión de certificados (OpenSSL) y entender scripts de shell básicos.

En esta misma página existe un tutorial sobre cómo ser tu propia autoridad de certificación, en el que se explica todo lo que hace falta para crear los certificados y la infraestructura de clave pública necesaria para la VPN

Caso práctico que se tratará.

Esta será la arquitectura de red con la que trabajaremos:

Disponemos de un servidor GNU/Linux con dos tarjetas de red, una conectada a Internet con IP fija (interfaz eth0) y otra conectada a la subred local (eth1) 172.19.50.0/24.

Los roadwarriors estarán conectados a Internet (ya sea directamente o a través de NAT) y se les asignará una IP dentro del subrango de la red local de entre el 172.19.50.230 al 250.

### TODO Imagen arquitectura de red ###

Configuración del servidor GNU/Linux

Lo primero que tendremos que hacer será instalar el software necesario, esto es el servidor de VPN y las utilidades para gestionar puentes:

        # apt-get install openvpn bridge-utils

A continuación, Crearemos un fichero con un script al que llamaremos bridge-start.


#!/bin/bash
#################################
# Set up Ethernet bridge on Linux
# Requires: bridge-utils
#################################

################################## Config zone ###############
# Define Bridge Interface
br="br0"

# Define list of TAP interfaces to be bridged,
# for example tap="tap0 tap1 tap2".
tap="tap0"

# Define physical ethernet interface to be bridged
# with TAP interface(s) above.
# Interface of the local network.
eth="eth1"
# IP Information of our VPN server on the local network
eth_ip="172.19.50.1"
eth_netmask="255.255.255.0"
eth_broadcast="172.19.50.255"

#################################################################
for t in $tap; do
    openvpn --mktun --dev $t
done

brctl addbr $br
brctl addif $br $eth

for t in $tap; do
        brctl addif $br $t
done

for t in $tap; do
    ifconfig $t 0.0.0.0 promisc up
done

ifconfig $eth 0.0.0.0 promisc up

ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast

Con este script lo que estamos haciendo es:

  1. Crear un interfaz de red bridge o puente br0 y uno tap0 (será el interfaz virtual de la VPN, es decir, todo el tráfico que vaya a la subred de la VPN se enviará por ese interfaz)
  2. Asociar el interfaz eth1 y tap0 al puente. Con esto hacemos, todos los equipos que estén al otro lado de cada uno de los interfaces podrán ver a los equipos del otro lado como si estuvieran conectados al mismo switch
  3. Asociar una dirección IP al interfaz del puente, ya que ahora virtualmente sólo hay un interfaz de red, el br0.

Conceptualmente estamos convirtiendo nuestro servidor VPN en un puente ethernet que une dos subredes físicamente distintas: la red local y la red de la VPN.

Nótese que, como es lógico, el interfaz de red local (eth1) tras configurar el puente se habrá puesto en modo promíscuo, esto es, interceptará todas las tramas que circulen por él aunque no vayan dirigidas a su dirección MAC. Esto se hace para poder capturar y enviar todas las tramas que vayan dirigidas a una MAC que se encuentre en el lado del interfaz tap0. Cuando un PC de la red local quiera enviar un paquete a uno de la VPN con IP conocida, lo primero que hará será, si no está actualizada su tabla ARP, enviar una trama ARP broadcast preguntando por la MAC del PC al que se quiere conectar, ésta trama broadcast le llegará también al puente (servidor VPN) por el interfaz eth1 que lo reenviará por el interfaz tap0, el cliente de la VPN responderá con la MAC Virtual de su interfaz tap0 y con su IP que está dentro del pool de las IPs locales de la subred de la empresa (entre la 230 y la 250 en nuestro caso), que llegará al interfaz tap0 del puente (servidor VPN), éste la reenviará a por el interfaz eth1, que por último llegará al ordenador que hizo la petición ARP. Una vez que el PC ya dispone de la dirección MAC se enviarán las tramas ethernet a esa dirección MAC.

El que haya peticiones ARP es debido a que puesto que los PCs cliente de la VPN poseén una IP dentro del rango de la subred local para el resto de PCs de la oficina se encuentran físicamente conectados a la red local, por tanto, en su tabla de encaminamiento (lo que sale al ejecutar el comando route) no está activado el switch G (que indica que el próximo salto un gateway), cosa que sí pasa cuando se intenta acceder a un PC con una IP que está fuera de la subred.

Una vez hecho lo anterior, también deberemos crear un fichero con el script que pare el puente, lo llamaremos bridge-stop:


#!/bin/bash

####################################
# Tear Down Ethernet bridge on Linux
####################################

# Define Bridge Interface
br="br0"

# Define list of TAP interfaces to be bridged together
tap="tap0"

ifconfig $br down
brctl delbr $br

for t in $tap; do
    openvpn --rmtun --dev $t
done

Una vez que ya tenemos el puente llega el momento de editar los ficheros de configuración de OpenVPN. Disponemos de ficheros ejemplo en el directorio

	    /usr/share/doc/openvpn/examples/server.conf.gz

Si lo deseamos podemos cambiar el puerto al que escuchará el servidor OpenVPN


; Por defecto 1194
 port 56789

;Por defecto, si no se indica lo contrario, se creará una VPN del tipo
;routing (interfaz del tipo tun), así descomentaremos el interfaz tap
;(empleado para crear VPN tipo bridging) y comentaremos el interfaz tun:

 dev tap0
;dev tun

; Comentaremos la línea server:
;server 10.8.0.0 255.255.255.0


;Editaremos los parámetros de la PKI (public key infraestructure)

 ca cacert.pem
 cert servercert.pem
 key server.key  # This file should be kept secret

;Donde ca es el certificado de la autoridad de certificación, cert el 
;certificado del servidor y key la clave secreta del servidor.

;Descomentaremos la línea server-bridge y la editaremos con la 
;información de nuestra subred:

;Datos:       IP servidor VPN  Máscara Subred Inicio Pool    Fin Pool
server-bridge 172.19.50.1      255.255.255.0  172.19.50.230  172.19.50.250

;
;Añadiremos un "cortafuegos HMAC", esto es, se añade una firma en cada
;paquete UDP de forma que los paquetes que no estén firmados son
;descartados, esto permite evitar ataques DoS y UDP flooding. Para
;ello ejecutaremos los siguientes comandos:
;
;
;    # cd /etc/openvpn
;    # openvpn --genkey --secret ta.key
;    # chmod 600 ta.key
;
;y descomentaremos la línea:

  tls-auth ta.key 0 # This file is secret

;El fichero ta.key será compartido por el servidor y todos los clientes,
;es decir, los clientes también poseerán una copia de este fichero.

;Descomentaremos el usuario y el grupo con el que se ejecutará openvpn. 
;En el caso de Debian deberemos cambiar el valor de la opción group de
;nobody a nogroup

    user nobody
    group nogroup

;---
;Nota: Si deseamos que con un mismo certificado puedan conectarse varios clientes a la vez debemos descomentar la opción
;  
;        duplicate-cn 
;---

Con esto finalizaremos la edición del fichero /etc/openvpn/server.conf.

A continuación, añadiremos las reglas en el cortafuegos para que se permita el tráfico por la VPN. En principio, a no ser que queramos ser más restrictivos bastará con añadir las reglas que siguen:


#!/bin/sh
# Reglas OpenVPN
echo "-- Añadiendo reglas OpenVPN"
# Permitir acceso a puertos TCP/UDP
iptables -A INPUT -i $I_INT -p tcp --dport 56789 -j ACCEPT
iptables -A INPUT -i $I_INT -p udp --dport 56789 -j ACCEPT

#Permitimos que el tráfico circule por el interfaz de la VPN
iptables -A INPUT -i tap0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A FORWARD -i br0 -j ACCEPT

#Por si no tenemos forward activado.
echo 1 > /proc/sys/net/ipv4/ip_forward

# OJO! Sólo si hacemos soruce nat, deberemos añadir esta regla 
#iptables -t nat -A POSTROUTING -o br0 -j SNAT --to 172.19.50.1

Disponemos un ejemplo completo de configuración del firewall en

    /usr/share/doc/openvpn/examples/sample-config-files/firewall.sh

Para lanzar la VPN deberemos crear el interfaz del puente y después ejecutar el script de inicialización de la VPN:

     # bridge-start
     # /etc/init.d/openvpn start
     (se nos pedirá la contraseña del certificado creado para el servidor)

Para ternimar la ejecución de la VPN:

     # /etc/init.d/openvpn stop
     # bridge-stop

Una cosa a tener en cuenta es que por defecto, el paquete añade el arranque de la VPN durante la inicialización del sistema, esto no puede ser de nuestro agrado, ya que puesto que no solicita contraseña, en caso de que no estemos delante del servidor no podamos introducirla, por este motivo es conveniente no permitir el arranque de la VPN. Así eliminaremos el enlace simbólico de

  /etc/rc2.d/S16openvpn

Otra opción que tenemos es la de eliminar la contraseña del certificado que use nuestro servidor OpenVPN. Para ello primero deberemos asegurarnos de que en la configuración de OpenSSL no se nos exige un mínimo de caracteres en pa contraseña del certificado. Comprobaremos que /etc/openssl/openssl.cnf tenga estas opciones de configuración:

   [ req_attributes ]
   challengePassword               = A challenge password
   challengePassword_min           = 0
   challengePassword_max           = 20

Por defecto, en Debian la opción challengePassowrd_min está establecido a 4, por lo que deberemos modificarlo.

Para eliminar la frase de paso del certificado ejecutaremos:

    openssl rsa -in server.key -out server.key

donde server.key es el fichero con la clave privada del cerficiado del servidor.

Información de estado y depuración

Por defecto, a no ser que se le indique lo contrario OpenVPN enviará sus mensajes de depuración al fichero


    /var/log/syslog

Disponemos de dos ficheros con información de estado


   /etc/openvpn/openvpn-status.log

que contiene la información sobre los clientes conectados al servidor VPN y que es actualizado cada minuto, y el fichero

 
   /etc/openvpn/ipp.txt
 

que contiene la información sobre las IPs asignadas a los clientes de la VPN.

Automatización del Arranque

Para que se pueda lanzar la VPN durante el arranque hacen falta dos requisitos, que el certificado del servidor no tenga frase de paso (si la tiene podemos eliminarla con openssl rsa -in server.key -out server.key) y crear un script de arranque para crear el puente. Para esto último creamos una copia del fichero /etc/init.d/skeleton y lo editamos para que ejecute con la opción start el fichero bridge-start y con stop el fichero bridge-stop creados anteriormente. Una vez hecho esto creamos los enlaces simbólicos (suponiendo haber llamado bridge a la copia de skeleton)

  # ln -s /etc/init.d/bridge /etc/rc2.d/S15bridge
  # ln -s /etc/init.d/openvpn /etc/rc2.d/S16openvpn 

Client Setup (Windows)

Descargar la versión del instalador que incluye la GUI de www.openvpn.se.

Realizar la instalación. Durante la instalación se nos advertirá de que vamos a crear un interfaz que no está firmado por MS... Aceptamos.

Una vez instalado, en Conexiones de Red deberemos cambiar el nombre del interfaz TAP creado por uno más corto, por ejemplo, "OpenVPN".

Copiaremos los dos ficheros del certificado del cliente (client.pem y client.key) y el certificado de la autoridad de certificación al directorio C:\Archivos de Programa\OpenVPN\config. También copiamos a este directorio el fichero ta.key. Nótese que si deseamos ser coherentes con la seguridad, deberemos copiar estos ficheros a través de un canal seguro, por ejemplo, vía ssh.

A continuación, copiaremos el fichero client.ovpn del directorio C:\Archivos de Programa\Openvpn\examples al directorio C:\Archivos de Programa\OpenVPN\config

Editaemos el fichero client.ovpn del directorio config. Los cambios son:

#Usar TAP
dev tap

# Seleccionar el nombre del interfaz (sólo para WinDoS)
dev-node OpenVPN

#establecer el servidor remoto y el puerto.
remote ip.fija.de.nuestro.servidor.vpn 56789

#Establecemos los parámetros de la PKI

ca ca.crt
cert client.crt
key client.key

#Establecemos el fichero para la firma HMAC (nótese que se usa 1 como segundo #argumento para clientes)
tls-auth ta.key 1

Configuración de Clientes GNU/Linux

La configuración en los clientes GNU/Linux es la misma que para los clientes windows excepto que no se descomenta la directiva dev-node y en la directiva dev se completa igual que en el caso del servidor, es decir, con tap0.

Por supuesto, al igual que en el servidor deberemos instalar el paquete openVPN

apt-get install openvpn

Nos preguntará si deseamos crear el interfaz TUN/TAP, le decimos que sí.

El fichero base se encuentra en
    /usr/share/doc/openvpn/examples/sample-config-files/client.conf

Deberemos copiarlo al directorio /etc/openvpn al igual que:

  1. El certificado del cliente (client.crt)
  2. La clave privada del cliente (client.key)
  3. El certificado de la Autoridad de Certificación (ca.crt)
  4. El fichero ta.key

Para arrancar la VPN:

/etc/inint.d/openvpn start

Nos pedirá una contraseña, que es que se introdujo al hacer el certificado del cliente.

Como en el servidor, por defecto, al instalar el paquete Debian se añadirá al script al arranque del sistema. Si no deseamos que esto suceda deberemos eliminar el enlace simbólico

 # rm /etc/rc2.d/S16openvpn

Para volver a crearlo, en caso de que deseemos que se arranque la VPN deberemos usar el siguiente comando

  # ln -s /etc/init.d/openvpn /etc/rc2.d/S16openvpn