Cómo crear tu propio Servidor VPN con OpenVPN

OpenVPN es una solución multiplataforma que ha simplificado la configuración de VPNs en contra de soluciones más antiguas y difíciles de configurar como IPSec, haciéndolo más accesible para el público con menos experiencia en este tipo de tecnologías, permitiéndonos así crear nuestro propio servidor VPN.

Servidor

Lo primero que tenemos que hacer para crear nuestro propio servidor VPN es, obviamente, conseguir un servidor dónde realizar la instalación. Existen múltiples opciones en la nube y la mayoría de ellas, además, cuentan con imágenes para poder preinstalar OpenVPN en la creación de los servidores. Entre las posibles opciones que podemos utilizar encontramos los siguientes:

  • ScaleWay C1: 4 CPU, 2GB RAM, 50GB SDD, 1 IP, 200 Mbit/s ancho de banda -> 2.99€ al mes.
  • DigitalOcean: 1 CPU, 512 MB RAM, 20 GB SDD, 1 IP, 1 TB ancho de banda -> 5$ al mes.
  • Google Cloud Platform: Facturación por minutos de uso.
  • Amazon EC2: Facturación por minutos de uso.

También podríamos realizar la instalación en cualquier máquina Ubuntu con acceso a internet, como un ordenador antiguo o una Raspberry Pi. En estos casos deberemos realizar además tareas de redireccionamiento de tráfico en nuestra red local para que todo funcione correctamente.

Instalación

Para instalar OpenVPN en Ubuntu podemos utilizar apt-get mediante el siguiente comando:

Después de esto, tenemos que extraer el fichero de ejemplo de configuración en la carpeta /etc/openvpn para incorporarlo así a nuestra configuración. Esto se puede hacer con un solo comando:

Una vez extraído editamos el fichero server.conf y realizamos algunos cambios.

Las modificaciones más importantes a realizar son descomentar algunas líneas eliminando el caracter ‘;’. Para que el servidor VPN pase el tráfico web de los clientes a su destino, debemos descomentar la siguiente línea:

Es importante utilizar el servidor OpenDNS con los clientes conectados para la resolución de DNS. Esto puede ayudar a evitar que las solicitudes de DNS se escapen fuera de la conexión VPN. Sin embargo, es importante especificar también estos servidores DNS en los dispositivos de los clientes.. Para lograrlo necesitamos descomentar las siguientes líneas:

Para evitar que OpenVPN se ejecute en modo root descomentaremos las siguientes líneas que especifica el usuario nobody como el usuario por defecto a utilizar. Nobody es un usuario sin los privilegios por defecto de un usuario normal.

El siguiente paso es configurar el reenvío de paquetes con sysctl. Esto le indicará al núcleo del servidor que reenvíe el tráfico de los dispositivos cliente hacia Internet. De lo contrario, el tráfico se detendrá en el servidor. Para lograrlo debemos ejecutar este comando:

Para hacer que este cambio sea permanente debemos descomentar la siguiente línea en el fichero /etc/sysctl.conf.

Cortafuegos

De forma predeterminada, las reglas de reenvío de Linux eliminan todos los paquetes que intentan acceder a otra interfaz, por lo que necesitamos configurar un cortafuegos que permita el tráfico a través del puerto VPN 1194 y enviar por defecto las peticiones realizadas a Internet por los clientes. Para evitar el uso de IPTables vamos a usar ufw con los siguientes comandos para permitir conexiones SSH y 1194/udp:

Después de eso, tenemos que modificar el archivo de configuración ufw para establecer la política de forward por defecto a ACCEPT. Este archivo es /etc/default/ufw y necesitamos modificar la línea:

Finalmente, debemos añadir unas cuantas reglas en el fichero /etc/ufw/before.rules para que OpenVPN funcione correctamente. Estas reglas son:

El resultado del fichero debe parecerse al de la Captura 1:

Captura 1: /etc/ufw/before.rules

Con los cambios realizados en ufw, podemos activarlo finalmente:

Generación de Certificados

El siguiente paso es configurar y generar los certificados que OpenVPN utilizará para cifrar el tráfico. Para este propósito vamos a utilizar los scripts de Easy RSA en nuestra carpeta de servidor.

Copiamos los scripts de generación de Easy RSA con el siguiente comando:

Creamos una carpeta para almacenar las claves:

Ahora debemos modificar algunas variables en el fichero /etc/openvpn/easy-rsa/vars como la carpeta de EASY_RSA el valor del KEY_SIZE como podemos ver en la Captura 2:

Captura 2: /etc/openvpn/easy-rsa/vars

Antes de crear cualquier clave necesitamos configurar nuestro servidor como CA (Certificate Authority) para firmar nuestras claves con los siguientes comandos:

Como podemos ver en la Captura 3 el sistema nos pedirá información sobre el certificado como el país, la provincia, el nombre, etc.

Captura 3: Creando Autoridad de Certificación

Con el siguiente comando generamos las claves del servidor para un servidor con nombre ‘server’ como podemos ver en la Captura 4.

Captura 4: Generando Clave para el Servidor

Ahora que tenemos las claves en la carpeta/etc/openvpn/easy-rsa/keys/ las copiamos en la carpeta /etc/openvpn:

Generamos además los parámetros Diffie-Hellman. Esto puede tardar varios minutos.

Captura 5: Generando Diffie-Hellman

Finalmente, podemos iniciar nuestro servidor OpenVPN con el siguiente comando:

Claves de Cliente

Una vez generadas las claves del servidor, podemos generar claves para cada uno de los diferentes clientes que queremos conectar a nuestra VPN. No existe ninguna relación entre la clave y el propio dispositivo por lo que podríamos generar una clave de cliente única y usarla en todos los dispositivos, eso sí, sólo un cliente podría conectarse a la VPN al mismo tiempo.

Para crear credenciales de autenticación independientes para los clientes (Captura 6) necesitamos usar el script build-key de la carpeta Easy RSA:

Captura 6: Creando Clave para Client 1

Este comando va a generar las siguientes claves:

  • /etc/openvpn/easy-rsa/keys/client1.crt
  • /etc/openvpn/easy-rsa/keys/client1.key

Ahora que tenemos las claves, podemos proceder con la creación del archivo de configuración. Para ello partimos de uno de los archivos predeterminados de Easy RSA copiándolo en nuestra carpeta:

El siguiente paso requiere descargar a nuestro equipo local las llaves del cliente, los archivos de client.ovpn y ca.cart. Podemos hacer eso con SCP:

Una vez que hayamos descargado los archivos en nuestro ordenador, podemos crear un perfil OpenVPN unificado mediante la edición del archivo de plantilla client.ovpn e incluir la Autoridad de Certificación de los servidores, el certificado de clientes y su clave. También necesitamos hacer algunas modificaciones en el archivo:

  • Descomentar user nobody y group nogroup
  • Cambiar la línea remote my-server-1 1194 line con remote [SERVER-IP] 1194
  • Comentar las líneas de la Captura 7.
Captura 7: Fichero client.ovpn

Para combinar los archivos individuales en el único perfil unificado, el contenido de los archivos ca.crt, client1.crt y client1.key se pegan directamente en el perfil de .ovpn utilizando una sintaxis básica similar a XML. El código XML al final del archivo debe tener este formato:

Clientes OpenVPN

Para poder usar el archivo .opvn de configuración y conectarnos remotamente a nuestro servidor VPN podemos hacer uso de diferentes clientes VPN disponibles.

OpenVPN Connect ofrece versiones para PC, dispositivos Android e iOS. En nuestro caso vamos a utilizar otro cliente VPN para Mac OSX, llamado Tunnelblick. Una vez instalado solo necesitamos abrir nuestro archivo de perfil .ovpn y Tunnelblick configurará automáticamente la conexión VPN para que podamos utilizarla como podemos ver en Captura 8.

Captura 8: Tunnelblick Conectado

Podemos asegurarnos de que estamos conectados a la VPN usando cualquier servicio web para obtener nuestra IP pública como podemos ver en Captura 9 que detecta que todo está bien configurado.

Captura 9: Comprobando mi IP
0

XSLT en Python: lxml

En el artículo Transformaciones con XSLT vimos una introducción al lenguaje de transformaciones, sin embargo, no explicamos como utilizar debidamente esta tecnología. En este artículo explicaremos como realizar transformaciones XSLT en Python haciendo uso de la biblioteca lxml y veremos como montar un servidor web con Flask para hacer uso de nuestro procesador XSLT desde cualquier lugar.

Introducción

Tanto los documentos XML como las hojas de estilo en XSLT son completamente independientes de la plataforma que se vaya a utilizar para realizar las transformaciones. Podemos enlazar una hoja de estilos XSLT a un documento XML de forma permanente añadiendo un elemento <?xml-stylesheet ..?> justo después de la declaración XML como podemos ver en el Fragmento de Código 1. De esta forma, al abrir el documento con un navegador web, éste aplicará las transformaciones pertinentes de forma automática y podremos comprobar el resultado.

Sin embargo, si lo que queremos es generar documentos independientes es necesario utilizar un procesador XSLT que se encargue de aplicar al documento XML las reglas de transformación incluidas en la hoja de estilo XSLT y genere un documento final. La transformación se realiza de la siguiente forma:

  1. El procesador analiza el documento y construye el árbol del documento.
  2. El procesador recorre todos los nodos desde el nodo raíz, aplicando a cada nodo una plantilla, sustituyendo el nodo por el resultado.
  3. Cuando el procesador ha recorrido todos los nodos, se ha terminado la transformación.

Afortunadamente existen procesadores XSLT para casi todos los lenguajes de programación, como Perl, C, Java, etc. En nuestro caso hemos optado por implementar el procesador haciendo uso del lenguaje Python y su librería libxml.

Python

Python es un lenguaje muy potente y fácil de aprender. Maneja eficientes estructuras de datos de alto nivel y cuenta con un enfoque simple pero efectivo de programación orientada a objetos. Posee una sintaxis muy elegante y tipado dinámico, que junto con su carácter interpretado lo convierte en un lenguaje ideal para desarrollo rápido de aplicaciones en innumerables áreas. Python se encuentra en un gran número de aplicaciones web y de escritorio, por lo que es un lenguaje de aprendizaje casi obligatorio para un desarrollador actual, ya que permite resolver problemas de una forma muy eficiente en un corto espacio de tiempo. Además, cuenta con un repositorio de paquetes que permiten extender la funcionalidad de las aplicaciones de una forma sencilla, muy similar a como se hace con NodeJS.

El gestor de paquetes recomendado para Python se denomina pip, y se utiliza de un modo similar a npm o apt-get. Con él, podemos instalar el paquete lxml que nos permitirá procesar documentos XML y HTML de forma sencilla.

En el Fragmento de Código 2 podemos ver cómo aplicar una plantilla XLST a un documento XML como el que vimos en el Fragmento de Código 1.

Como podemos observar, aunque no hayamos visto el lenguaje Python hasta ahora, simplemente leyendo el código entendemos perfectamente lo que hace. Inicialmente se lee el fichero de entrada que se pasa como parámetro al método transforma_documento. Seguidamente se utiliza el contenido del fichero para obtener el árbol de nodos del documento XML y almacenarlos en la variable dom. A continuación se obtiene un objeto de transformación leyendo el fichero de hoja de estilos “hojaEstilos.xslt” en el que se han definido las transformaciones, cuyo contenido podemos ver en el Fragmento de Código 3. Se aplican las transformaciones en el árbol de nodos y se obtiene un nuevo árbol de documento que podemos convertir en una cadena de texto para devolverla como resultado para, si quisiéramos, escribirla en un nuevo fichero obteniendo finalmente nuestro fichero transformado.

Así, si abriéramos el fichero XML en un navegador obtendríamos un resultado parecido al que podemos observar en la siguiente captura.

Transformación XSLT de documento XML a contenido HTML

Flask

Python puede instalarse en cualquier sistema operativo actual. Sin embargo, si queremos utilizar código en este lenguaje desde un entorno web se hace necesario utilizar una infraestructura apropiada que permita desarrollar aplicaciones web o servicios sin necesidad de manejar detalles de bajo nivel como protocolos o manejo de procesos e hilos.

Entre las numerosas infraestructuras que podríamos utilizar nos hemos decantado por Flask, una infraestructura web minimalista que nos permite realizar peticiones a nuestro código de transformación de forma sencilla mediante el desarrollo de una API REST. En el Fragmento de Código 4 podemos ver un ejemplo sencillo de cómo podríamos utilizar nuestro código de transformación visto en el Fragmento de Código 2 utilizándolo como una biblioteca denominada publisher, que se corresponde con el nombre del fichero en el que hemos almacenado nuestras funciones transformadoras.

Para poder gestionar correctamente el servidor web, utilizamos las funciones render_template y request, con el objetivo de devolver ficheros estáticos, y de manejar las peticiones respectivamente. Como podemos observar es un código relativamente sencillo que nos permitirá obtener un documento transformado a partir de un documento que podemos enviar mediante un formulario HTML como el del Fragmento de Código 4.

Podéis encontrar el código fuente utilizado en este artículo en GitHub.

Conclusión

Utilizar Flask nos permitirá, entre otras cosas, poder mejorar la modularidad de un sistema en diferentes máquinas en caso de que fuera necesario, es decir, podríamos perfectamente instalar nuestro servicio de transformaciones en un servidor, y la aplicación web que utilice éste en otro distinto. Sin embargo, si quisiéramos utilizar tanto Flask como NodeJS en una misma máquina tendremos que utilizar aplicaciones intermedias como Virtual Environment  para mantener la aplicación Flask ejecutándose como servicio, uWSGI como interfaz web entre servidores web y el servicio creado con Virtual Environment y NGINX como servidor web para controlar todas las peticiones entre la aplicación web y el servicio de transformaciones en Python.

0