Introducción

El siguiente artículo explica como configurar OpenVPN.

Es un proceso complicado y en el que tendréis que poner algo de imaginación para resolver algunos de los problemas que os van a aparecer.

Instalación

Linux, Raspberry y asimilados:

# apt-get install openvpn

Windows

https://openvpn.net/index.php/open-source/downloads.html

Generar certificados

Se trata de generar un certificado digital (clave pública y una privada) autofirmada por una autoridad de certificación (CA) que previamente crearemos nosotros.

Este proceso está explicado en el post sobre generación de certificados autofirmados.

Al final de este artículo, puedes ver un script para facilitarlo todo.

Además de lo anterior, hay que generar un DiffieHellman:
openssl dhparam -out dh2048.pem 2048

Generados los certificados, tendremos los siguientes ficheros.

  • Clave privada de nuestra CA – Solo usado para firmar el resto de certificados
  • Clave pública de nuestra CA – En el servidor y en el cliente
  • Clave privada de nuestro servidor – Solo en el servidor
  • Clave pública de nuestro servidor – Solo en el servidor
  • Clave privada de nuestro cliente – Solo en el cliente
  • Clave pública de nuestro cliente – Solo en el cliente
  • DiffieHellman – En el servidor y en el cliente

Cada uno de esos ficheros los tendremos que copiar donde se indica, según el rol que vaya a tener el equipo (cliente o servidor)

En linux, el directorio debería ser /etc/openvpn/server para el servidor o /etc/openvpn/client para el cliente

En windows esa carpeta debería estar en:

C:\Program Files\OpenVPN\config

Nota importante sobre la clave privada de nuestro servidor: Después de muchos problemas para arrancar como servicio server.conf, lo más sencillo es crear este certificado sin clave.

Si lo has creado con clave, puedes ejecutar el siguiente comando para quitarle dicha clave:

openssl rsa -in server_priv.pem -out server_priv_nokey.pem

Configuración del fichero .conf del servidor

Si estan comprimidas,  descomprimir una configuración de ejemplo de servidor. Si no, copiar el fichero.

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz |sudo tee /etc/openvpn/server.ovpn

En el fichero server.ovpn, modificaremos los nombres de los certificados a los nombres que usaremos en este ejemplo (o a los que decidas)
ca --> ca_pub.pem
cert --> server_pub.pem
key --> server_priv.pem
dh --> dh2048.pem

Configuración del fichero .conf del cliente

Si estan comprimidas, descomprimir una configuración de ejemplo de cliente. Si no, copiar el fichero.

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/client.conf.gz |sudo tee /etc/openvpn/client.ovpn

Modificar los parámetros con los nombres de los certificados del fichero de configuración


# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote 192.168.1.20 1194
ca ca_pub.pem
cert client_pub.pem
key client_priv.pem
dh dh2048.pem

En este caso 192.168.1.20 será la dirección del servidor. También podría ser un nombre DNS.

Probando el servicio

Antes de lanzar el servicio lo mejor es que lo pruebes desde la consola. De esta manera podrás ver qué está pasando, seguramente nada bueno. Desde la carpeta donde tengas el fichero .conf del servidor

openvpn server.ovpn

Así mismo podrás probar el fichero del cliente en el mismo equipo antes de probar desde otros equipos (así puedes depurar previamente errores de configuración antes de depurar problemas de conexión)

openvpn client.ovpn

Arrancar servicio

systemctl start openvpn@server

Como a la primera no va a funcionar, tendrás que revisar el log:
journalctl -xe

Es muy recomendable, si quieres usar openvpn como servidor y no quieres  complicarte la vida, que no uses clave en el certificado privado del servidor.

En todo caso, se puede investigar en este enlace los parámetros auth-users-pass: https://www.smarthomebeginner.com/configure-openvpn-to-autostart-linux/

El enrutamiento

Vale, ahora ya se puede conectar el cliente. Quizás quieras que tu LAN sea visible desde fuera. Para ello, después de dar muchas vueltas, donde mejor se explica es en esta pregunta de serverfault.

Hay que comprobar los siguientes puntos:

1. Instruir a los clientes para que redirijan todo el tráfico por el túnel.

Para ello habrá que añadir esta línea al fichero de configuración del servidor:

push "redirect-gateway def1"
push "dhcp-option DNS 192.168.1.1" # Dirección del router
push "route 192.168.1.0 255.255.255.0" # Red de la LAN

Con estas directivas, todo el tráfico de nuestros clientes pasará por nuestro servidor Openvpn. Esto puede que no sea lo que deseamos. Para evitar esto en algunos clientes podemos usar la siguiente línea en el fichero del cliente en cuestión:

pull-filter ignore redirect-gateway

También podemos añadir una ruta específica en nuestro cliente con:

route 80.0.0.0 255.0.0.0 172.16.1.1

Con la directiva anterior. el tráfico a la subred 80.0.0.0 sería enviado a la puerta de enlace 172.16.1.1

2. Permitir al servidor enrutar el tráfico

Podemos comprobar el estado del reenvío de paquetes. Si el siguiente comando devuelve un 1, está activado. Si devuelve un 0, desactivado:

# cat /proc/sys/net/ipv4/ip_forward

En nuestro caso queremos activarlo, lanzando desde el servidor el siguiente comando:

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

Para hacer el cambio permanente se puede hacer editando /etc/sysctl.conf

3. Asegurarse que iptables no bloquea el tráfico

# iptables -I FORWARD -j ACCEPT

4. Hacer un NAT para que el tráfico dentro de nuestro túnel pueda ser redirigido a nuestra LAN. Podemos ver primero qué reglas NAT tenemos:

# iptables -t nat -L

, y después crear la regla correspondiente.

# iptables -t nat -I POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Ojo en el punto 4 con la tarjeta que vamos a usar para enrutar (el interface «eth0» en este caso)

Para hacer pesistentes los cambios en iptables

# apt-get install iptables-persistent
# iptables-save > /etc/iptables/rules.v4
# ip6tables-save > /etc/iptables/rules.v6

Script

Un script vale más que mil palabras. En concreto éste:

  1. Crea una clave pública y privada de nuestro CA
  2. Para nuestro servidor OpenVPN, crear una clave privada y una petición de clave pública que será firmada por nuestra CA
  3. Para nuestro cliente OpenVPN, crear una clave privada y una petición de clave pública que será firmada por nuestra CA
  4. Firma la petición del certificado digital del servidor, añadiendo las extensiones de poder usarlo como autenticación en servidor TLS
  5. Firma la petición del certificado digital del cliente

Primero debemos crear el fichero cert-server-extensions.cnf

[ server ]
# Para poder usarlo de certificado en el servidor
extendedKeyUsage = serverAuth
keyUsage = digitalSignature, keyEncipherment

Antes de lanzar el script debemos modificar los siguientes parámetros:

  • ca_pass – Clave del certificado de nuestro CA
  • server_pass – Clave del certificado de nuestro servidor. Lo necesitaremos en el servidor cuando queramos arrancar el servicio openvpn. Si queremos simplificar la configuración, es posible no utilizar esta clave.
  • client_pass – Clave del certificado cliente (lo necesitaremos en el cliente cuando queramos conectarnos al servidor)
  • /DC=mi,/DC=dominio,/DC=com – Nombre del dominio del servidor. Los certificados generados sirven para conectarse únicamente al dominio definido (en este ejemplo mi.dominio.com)
#!/bin/bash
ca_pass=clave_de_la_ca
server_pass=clave_del_servidor
client_pass=clave_del_cliente
echo ---------------------
echo CREANDO CA
echo ---------------------
openssl req -x509 -newkey rsa:2048 -passout pass:"$ca_pass" -keyout ca_priv.pem -out ca_pub.pem -days 365
echo --------------------------------
echo CREANDO CERTIFICADO DEL SERVIDOR
echo --------------------------------
echo Generando petición del certificado del servidor para ser firmado
openssl req -newkey rsa:2048 -subj "/DC=mi,/DC=dominio,/DC=com,/CN=server" -passout pass:"$server_pass" -keyout server_priv.pem -out server_pet.pem
echo ---------------------------------------------
echo FIRMANDO EL CERTIFICADO DE SERVIDOR CON LA CA
echo ---------------------------------------------
openssl x509 -extfile cert-server-extensions.cnf -extensions 'server' -CA ca_pub.pem -passin pass:"$ca_pass" -CAkey ca_priv.pem -req -in server_pet.pem -days 3650 -sha1 -CAcreateserial -out server_pub.pem
echo -------------------------------
echo CREANDO CERTIFICADO DEL CLIENTE
echo -------------------------------
echo Generando petición del certificado del cliente para ser firmado
openssl req -newkey rsa:2048 -subj "/DC=mi,/DC=dominio,/DC=com,/CN=client" -passout pass:"$client_pass" -keyout client_priv.pem -out client_pet.pem
echo ---------------------------------------------
echo FIRMANDO EL CERTIFICADO DE CLIENTE CON LA CA
echo ---------------------------------------------
openssl x509 -CA ca_pub.pem -passin pass:"$ca_pass" -CAkey ca_priv.pem -req -in client_pet.pem -days 3650 -sha1 -CAcreateserial -out client_pub.pem
echo ---------------------------------------------
echo CREANDO DIFFIE-HELLMAN
echo ---------------------------------------------
openssl dhparam -out dh2048.pem 2048

Si no quieres crear el certificado de servidor privado con clave, que como ya se ha comentado, facilita un montón la instalación como servicio, tendrás que modificar la línea de creación de la clave privada del certificado privado de servidor:

openssl req -nodes -newkey rsa:2048 -subj "/DC=mi,/DC=dominio,/DC=com,/CN=server" -keyout server_priv.pem -out server_pet.pem 

Como ves, solo hay que añadir el parametro -nodes:

#!/bin/bash
ca_pass=clave_de_la_ca
client_pass=clave_del_cliente
echo ---------------------
echo CREANDO CA
echo ---------------------
openssl req -x509 -newkey rsa:2048 -passout pass:"$ca_pass" -keyout ca_priv.pem -out ca_pub.pem -days 365
echo --------------------------------
echo CREANDO CERTIFICADO DEL SERVIDOR
echo --------------------------------
echo Generando petición del certificado del servidor para ser firmado
openssl req -nodes -newkey rsa:2048 -subj "/DC=dominio,/DC=com,/CN=server" -keyout server_priv.pem -out server_pet.pem 
echo ---------------------------------------------
echo FIRMANDO EL CERTIFICADO DE SERVIDOR CON LA CA
echo ---------------------------------------------
openssl x509 -extfile cert-server-extensions.cnf -extensions 'server' -CA ca_pub.pem -passin pass:"$ca_pass" -CAkey ca_priv.pem -req -in server_pet.pem -days 3650 -sha1 -CAcreateserial -out server_pub.pem
echo -------------------------------
echo CREANDO CERTIFICADO DEL CLIENTE
echo -------------------------------
echo Generando petición del certificado del cliente para ser firmado
openssl req -newkey rsa:2048 -subj "/DC=dominio,/DC=com,/CN=client" -passout pass:"$client_pass" -keyout client_priv.pem -out client_pet.pem
echo ---------------------------------------------
echo FIRMANDO EL CERTIFICADO DE CLIENTE CON LA CA
echo ---------------------------------------------
openssl x509 -CA ca_pub.pem -passin pass:"$ca_pass" -CAkey ca_priv.pem -req -in client_pet.pem -days 3650 -sha1 -CAcreateserial -out client_pub.pem
echo ---------------------------------------------
echo CREANDO DIFFIE-HELLMAN
echo ---------------------------------------------
openssl dhparam -out dh2048.pem 2048