VPN con Wireguard

29 de julio 2020ComentarioslinuxDavid Poza SuárezComentarios

En la situación de pandemia que vivimos por culpa del COVID19 muchísimos trabajadores están conectándose via VPN a sus empresas para poder operar de forma segura. Por ello, su gran utilidad no es el único motivo para conocer el término, sino que además se trata de una de las tecnologías de moda y por ello es interesante saber de qué se trata.

Wireguard es una aplicación de software libre multiplataforma (Linux, Windows, macOS, Android e iOS) que implementa un tunel VPN, con el objetivo de ser rápida y simple. Nació en 2016 y está escrita por Jason A. Donenfeld en C y Go y publicada bajo GPL.

Como siempre, vamos tratar de dar una definición sencilla de qué es una red privada virtual: Es la extensión segura de una red local sobre redes compartidas, siendo el ejemplo más común aquel en el que usamos como red compartida la red de Internet.

Gracias a una vpn obtenermos seguridad y confidencialidad, puediendo por ejemplo prestar servicios en internet sin exponerlos al público general que no usa la red privada. Además de enmascarar nuestra ip pública con la ip del servidor vpn.

5d1aa6dc28bc4ef5ab2f4ea28f6c0332

Sus características clave de Wireguard son:

  • Muy buen rendimiento, gracias a que el cifrado elegido y a que reside en el kernel de linux. De hecho en Marzo 2020, tras alcanzar su versión estable, se ha añadido al kernel 5.6.
  • Simple de configurar: Básicamente lo único que debemos hacer es crear los pares de claves pública/privada para cada peer.
  • Utiliza protocolos criptográficos de vanguardiasolo soporta el algoritmo de encriptado simétrico Chacha20, que parece ser tan seguro como AES (el estándar) pero posee un mejor rendimiento cuando se usan arquitecturas que no poseen este juego de instrucciones, como es ARM. Es por ello que ChaCha20 se plantea como su alternativa en caso de necesidad: https://medium.com/asecuritysite-when-bob-met-alice/aes-is-great-but-we-need-a-fall-back-meet-chacha-and-poly1305-76ee0ee61895
  • Se ha programado tratando de usar el menor número de líneas de código posible y eso lo hace más seguro. Esto se debe a que con menos código resulta fácilmente auditable, agilizando la detección y correción de agujeros de seguridad.
  • Usa únicamente el protocolo UDP, más simple y rápido que TCP, usado habitualmente para streaming, gaming, voip, etc. Admite que los paquetes lleguen desordenados o que se pierdan por el camino, requiriendo, de este modo, menos recursos que su contrapartida.
  • Incremento significativo de la duración de batería en móviles y laptops en comparación con openVPN.

Se estima que WireGuard tiene 4000 líneas de código frente a las 100.000 de openvpn, y en la práctica proporciona mejor rendimiento (tanto velocidad como latencia) que el protocolo IPsec y que OpenVPN.

Comparativa de rendimiento con las polulares alternativas openVPN e ipSec

Comparativa de rendimiento con las polulares alternativas openVPN e ipSec

Instalación

Ubuntu

Ya encontramos el paquete wireguard en las principales distros, como por ejemplo a partir de Ubuntu 18.04:

sudo apt install wireguard

En caso contrario añadimos el repo:

sudo add-apt-repository ppa:wireguard/wireguard

Raspberry OS

El paquete de wireguard no viene en los repositorios oficiales de RaspberryOS Buster:

sudo apt-get install raspberrypi-kernel-headers
echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee --append /etc/apt/sources.list.d/unstable.list
wget -O - https://ftp-master.debian.org/keys/archive-key-$(lsb\_release -sr).asc | sudo apt-key add -
sudo apt update
sudo apt install wireguard -y

Generamos las claves pública/privada

Las almacenaremos en /etc/wireguard/keys

mkdir /etc/wireguard/keys
chmod 700 /etc/wireguard/keys

Con el comando wg genkey generamos la clave privada, tee, como una redirección simple, la vuelca en un fichero, pero además lo muestra por la salida estándar, donde se redirige de nuevo a wg genkey** que al recibir la clave privada genera la clave pública.

wg genkey | tee server\_private\_key | wg pubkey > server\_public\_key

Volvemos a hacer lo mismo para las claves de tantos clientes como necesitemos.

wg genkey | tee client\_private\_key | wg pubkey > client\_public\_key

Una vez creados los ficheros de clave debemos darles permisos 600.

PSK

Como extra de seguridad podemos usar una presharedKey única para cada cliente. De este modo estamos añadiendo un cifrado simétrico. Podemos generarla con el siguiente comando:

wg genpsk > client1.psk

Cliente para Windows

Montar la parte servidor en Windows parece que no está oficialmente recomendada. Yo desde luego no me planteo esta opción, prefiero Linux, sobre todo si es un servicio que ha nacido pensando en este sistema. No obstante aquí hay una guía donde explican cómo es posible lograrlo: https://www.henrychang.ca/how-to-setup-wireguard-vpn-server-on-windows/

Para montar el cliente lo primero es descargar el instalador de wireguard: https://download.wireguard.com/windows-client Después será tan sencillo como importar el mismo fichero de configuración del cliente que hubieramos creado para linux.

Cuando activemos dicho perfil se habilitará un adaptador de red con el nombre que le hubieramos dado al fichero, del mismo modo que en linux:

Cuando activemos dicho perfil se habilitará un adaptador de red con el nombre que le hubieramos dado al fichero, del mismo modo que en linux:

Podemos apreciar que se le configuran los dns que hubieramos definido en el fichero .conf.

Podemos apreciar que se le configuran los dns que hubieramos definido en el fichero .conf.

Cliente para Android

Podemos descargar el cliente oficial del Google play store: https://play.google.com/store/apps/details?id=com.wireguard.android

Para configurar el cliente Android lo más fácil es crear el perfil mediante el código QR generado en el servidor.

Debemos tener instalado qrencode en el servidor: sudo apt install qrencode. De modo que podemos transformar la config del cliente en un código qr con el siguiente comando:

qrencode -t ansiutf8 < /etc/wireguard/wg0-client.conf

Una vez tengamos el código QR en pantalla vamos a:

Como podemos observar ya nos indica que ejecutemos el comando qrencode en el servidor.

Como podemos observar ya nos indica que ejecutemos el comando qrencode en el servidor.

Configuración

Vamos a ver cómo sería su configuración en un escenario "road warrior", dónde el bloque de configuración "Peer" de cada cliente hace referencia al servidor, mientras que el servidor tiene tantos bloques "Peer" como clientes tenga.

gráfico de https://www.thomas-krenn.com/en/wiki/WireGuard_Basics

gráfico de https://www.thomas-krenn.com/en/wiki/WireGuard_Basics

Perfil para el servidor

Cada archivo de configuración qute tengamos, uno por máquina, tendrá siempre dos bloques: interface y peer. El primero hace referencia a la interfaz de red (adaptador de red en Windows) que va a levantar para efectuar la conexión. Por otro lado el Peer hace referencia al cliente que va a estar conectándose en el otro extremo de la red.

Notación CIDR: Permite definir espacios de direcciones IP usando máscaras de subred, señalando al router qué parte de la dirección va a reservar para hosts. Por ejemplo la máscara 255.255.255.0 equivale a /24, dejando 8 bits para las direcciones de los hosts.

Interface del servidor

PrivateKey = <clave privada del servidor>
Address = 10.6.0.1/24       # Es ip virtual del servidor (10.6.0.1) y al mismo tiempo la red(10.6.0.0) que usaremos en notación CIDR /24 => 255.255.255.0.
ListenPort = 51820          # Es el puerto por defecto pero podemos cambiarlo, DEBEREMOS ABRIRLO EN EL FIREWALL Y EN EL ROUTER SI ESTAMOS DETRÁS DE NAT
DNS = 8.8.8.8 # El dns que van a usar los clientes

PARA LINUX SI ESTAMOS USANDO IPTABLES COMO FIREWALL

Con las siguientes línes permitimos la redirección del tráfico entre la interfaz virtual de wireguard y la # interfaz de red física.

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enxb827eb95b695 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o enxb827eb95b695 -j MASQUERADE

Borramos la regla cuando desactivamos la interfaz de wireguard

PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enxb827eb95b695 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o enxb827eb95b695 -j MASQUERADE

Peer del servidor

Tendremos tantos bloques peer como clientes de la vpn.

PublicKey = <clave pública del cliente>
PresharedKey = <PSK del cliente 1>
AllowedIPs = 10.6.0.2/32     # la ip de la máquina, al no estar indicando una red sino solo una dirección, no dejamos ningún bit para el direccionamiento, es decir /32 => 255.255.255.255

Perfil para el cliente

La configuración del cliente se almacena en linux en /etc/wireguard/wg0-client.conf (para una interfaz de nombre wg0-client).

Interface del cliente

Address = 10.6.0.2/24        # Es ip virtual del cliente (10.6.0.2) y al mismo tiempo la red(10.6.0.0) que usaremos en notación CIDR /24 => 255.255.255.0
PrivateKey = <clave privada del cliente>
DNS = 8.8.8.8 # El dns que van a usar los clientes

Peer del cliente

PublicKey = <clave pública del servidor>
PresharedKey = <PSK del cliente 1>         # mejora opcional en la seguridad.
Endpoint = <ip pública del servidor>:51820
AllowedIPs = 0.0.0.0/0       # en principio permitimos tráfico desde cualquier ip
PersistentKeepalive = 20     # Tiempo en segundos para enviar periodicamente mensajes "keepalive" para asegurar que no se pierde la conexión. Útil si estamos detrás de NAT. Por defecto viene deshabilitada a valor 0.

Preparando el servicio y arrancando

Habilitamos el IP forwarding (Ip routing) editando el fichero /etc/sysctl.conf y añadiendo:

net.ipv4.ip\_forward=1

El Ip forwarding es la capacidad del sistema operativo de aceptar paquetes en una interfaz y, a pesar de que no tengan como destino la propia máquina, redirigirlos a otra interfaz.

chown -v root:root /etc/wireguard/wg0.conf
chmod -v 600 /etc/wireguard/wg0.conf
sudo systemctl enable wg-quick@wg0.service
sudo wg

Para ver su estado:

sudo wg

Para reiniciar podemos desactivar y volver a activar la interfaz:

sudo wg-quick down wg0
sudo wg-quick up wg0

# o bien reinciar el servicio:

sudo systemctl restart wg-quick@wg0.service