Automatizar la creación de clientes para WireGuard usando un Script

Publicado por P. Ruiz en

VPNSi sueles leer mis artículos, ya sabes que soy un admirador de la automatización de tareas. Siempre que puedo, trato de evitar las tareas repetitivas, que nos ocupan tiempo para otras actividades más creativas (y, normalmente, más productivas), además de aburrirnos.

Para estas situaciones, una herramienta fantástica son los scripts. En ellos, puedes incluir secuencias de tareas, que pueden realizarse sin tu intervención.

Fundamentalmente, utilizo dos lenguajes de scripts en mi día a día: PowerShell, cuando trabajo con sistemas Windows y Bash Shell cuando lo hago con sistemas GNU/Linux.

WireGuard LogoHoy pretendemos automatizar la creación de archivos de configuración, para los usuarios de una VPN creada con WireGuard. En particular, la que venimos implementado desde hace varios artículos. Por lo tanto, usaremos Bash Shell.

De hecho, notarás que el script que te propongo hoy tiene bastante parecido con otros que te he presentado hace algún tiempo, para automatizar tareas en Proxmox VE. En realidad, el script de hoy no se va a ejecutar sobre Proxmox VE, pero sí en un contenedor dentro es este. Sin embargo, tú podrás usarlo en cualquier otra implementación que realices de WireGuard.

Puedes consultar todos los artículo publicados en  SomeBooks.es sobre WireGuard en este enlace.

La idea general

La idea de partida consiste en crear una subcarpeta, llamada datos, dentro de la carpeta donde se encuentre el script. En esa subcarpeta, crearemos un archivo de texto por cada grupo de usuarios que pretendamos crear.

El archivo (o archivos) tendrá un nombre descriptivo como departamento1.txt y, en su interior, escribiremos una línea por cada nombre de usuario que vayamos a configurar. Algo como:

usuario1
usuario2
usuario3
...

Por ejemplo, puedes usar el editor nano, asegurándote de guardar los cambios al salir.

Automatizar-la-creación-de-clientes-para-WireGuard-usando-un-Script-001

Al ejecutar el script, se creará un nuevo archivo de configuración, para cada usuario del archivo, dentro de la ruta /etc/wireguard/configs, que es la predeterminada de WireGuard.

Después de eso, solo tendríamos enviar cada archivo de configuración al usuario adecuado, para que pudiese iniciar su conexión a la VPN.

Desarrollando el script

Lo primero que tenemos que establecer es el modo en el que se ejecutará el script. Mi idea es incluir en la llamada al script tres argumentos:

  1. El nombre del archivo con la lista de usuarios (departamento1.txt en nuestro ejemplo de arriba). Lo incluiremos sin el nombre de la carpeta (en mi caso, datos), para no tener que escribirlo cada vez.

  2. La dirección IP del servidor al que accederá el cliente dentro de la red local. Con esto, evitaremos que todo el tráfico de Internet del cliente pase por la red del servidor. Si necesitas más información sobre este aspecto, puedes consultar el artículo Wireguard: Controlar el acceso de los clientes, que publicamos hace unos días en SomeBooks.es.

  3. Por último, el puerto al que debe conectarse el cliente, para que el router de nuestra red dirija los paquetes al servidor WireGuard. Si no sabes de lo que te hablo, echa un vistazo al artículo Instalar WireGuard en un contenedor Proxmox VE. Parte 2.

Por lo tanto, la ejecución de nuestro script debería ser algo como:

./nuevos_clientes.sh departamento1.txt 192.168.1.4 4000

Si revisas el artículo Instalar WireGuard en un contenedor Proxmox VE. Parte 2, comprobarás que instalamos WireGuard de forma que escuchara en el puerto predeterminado, es decir, en 51820. Sin embargo, allí te explicábamos que nosotros usaremos Duck DNS, para acceder a nuestro router desde el exterior.

Pues bien, el router escuchará en el puerto 4000 y reenviará los paquetes al puerto 51820.

Como WireGuard escucha en su puerto predeterminado, creará los archivos de configuración para conectar al puerto predeterminado, pero nosotros debemos cambiar ese puerto por el que usa el router (que es quien recibe los paquetes en primera instancia.

Una vez aclarado el modo en el que debemos ejecutar el script, vamos a centrarnos en como construirlo.

Obviamente, lo primero será asegurarnos de que se reciben los argumentos adecuados. Podemos hacerlo de un modo más preciso, pero como voy a ser el único usuario de mi propio script, solo comprobaré el número de argumentos y, en caso de que no coincida, se mostrará un mensaje con la sintaxis esperada. Algo como esto:

if [[ $# -lt 3 ]]; then
    echo "Uso: $0 <archivo_clientes> <ip_permitida> <puerto>"
    exit 1
fi

Una vez que se haya pasado esta comprobación, pasaremos a inicializar variables con los valores recibidos. Podrías pensar que es un paso innecesario, pero hará que el script quede más legible. Será algo así:

archivo_clientes="$1"
ip_permitida="$2"
nuevo_puerto="$3"

También aprovecharemos para crear variables con los directorios que usaremos de forma predeterminada y el puerto configurado en WireGuard. Así, si en algún momento necesitamos cambiar sus valores, estarán en un sitio muy fácil de localizar, sin tener que hacer cambios en el resto del script.

dir_datos="./datos"
dir_configuraciones="/etc/wireguard/configs"
puerto_predeterminado="51820"

Como antes, puedes pensar que es innecesario, pero también crearé una variable con la ruta completa del archivo de datos, uniendo el directorio que usamos de forma predeterminada y el nombre del archivo que hemos recibido como argumento. En definitiva, algo como esto:

ruta_archivo_clientes="${dir_datos}/${archivo_clientes}"

Una vez resuelto el aspecto de las inicializaciones, y antes de que el el script se ponga a trabajar, debemos asegurarnos de que no hemos cometido un error al escribir el nombre del archivo de datos. De lo contrario, después se produciría un error de ejecución que nos afearía el resultado. Afortunadamente, es tan sencillo como esto:

if [[ ! -f "${ruta_archivo_clientes}" ]]; then
    echo "No existe el archivo ${ruta_archivo_clientes}"
    exit 1
fi

Una vez que hemos completado todos los preparativos, es el momento de comenzar la tarea. Básicamente, realizaremos un proceso repetitivo que vaya leyendo las líneas del archivo, una a una. Lo conseguiremos con una estructura como esta:

while IFS= read -r cliente || [[ -n "$cliente" ]]; do
    ...
done < "${ruta_archivo_clientes}"

Así, en cada iteración del bucle, la variable $cliente tendrá el nombre de una de las cuentas contenidas en el archivo. En nuestro ejemplo, la primera vez valdrá usuario1, la segunda usuario1, etc.

Por lo tanto, dentro del bucle usaremos la variable $cliente para crear el archivo de configuración. Por ejemplo, así:

pivpn add -n "${cliente}"

En realidad, si usáramos solo valores predeterminados, con esto habríamos terminado, pero nosotros tenemos que cambiar datos del archivo de configuración, por lo tanto, crearemos una nueva variable con su nombre, incluida la ruta completa. Algo como esto:

archivo_config="${dir_configuraciones}/${cliente}.conf"

A continuación, comprobamos que el archivo se haya creado correctamente y, en caso contrario avisamos de la situación y terminamos. La instrucción será así:

if [[ -f "${archivo_config}" ]]; then
    ...
else
    echo "No se ha creado el cliente ${cliente}"
fi

En el caso de que sí se haya creado el archivo (el espacio ocupado por los puntos suspensivos del if anterior), usamos el comando sed para buscar en su interior el puerto predeterminado y las direcciones IP permitidas, para sustituirlos por los nuevos valores que deben tener. Algo como esto:

sed -i "s/${puerto_predeterminado}/${nuevo_puerto}/g" "${archivo_config}"
sed -i "/AllowedIPs/c\AllowedIPs = ${ip_permitida}/32" "${archivo_config}"

Ponerlo todo junto

Una vez que tenemos claro como va a actuar el script, solo queda ponerlo todo junto en un archivo de texto con el nombre nuevos_clientes.sh (o como hayas decidido llamarlo tú).

nano /scripts/nuevos_clientes.sh

El contenido será este:

#!/bin/bash

# Verificar si se proporcionaron suficientes argumentos
if [[ $# -lt 3 ]]; then
    echo "Uso: $0 <archivo_clientes> <ip_permitida> <puerto>"
    exit 1
fi

# Valores iniciales
archivo_clientes="$1"
ip_permitida="$2"
nuevo_puerto="$3"
dir_datos="./datos"
dir_configuraciones="/etc/wireguard/configs"
puerto_predeterminado="51820"
ruta_archivo_clientes="${dir_datos}/${archivo_clientes}"

# Asegurar que existe el archivo
if [[ ! -f "${ruta_archivo_clientes}" ]]; then
    echo "No existe el archivo ${ruta_archivo_clientes}"
    exit 1
fi

# Leer cada nombre de cliente y generar el archivo de configuración
while IFS= read -r cliente || [[ -n "$cliente" ]]; do
    pivpn add -n "${cliente}"

    # Nombre esperado del archivo de configuración
    archivo_config="${dir_configuraciones}/${cliente}.conf"

    # Comprobar que el archivo se ha creado
    if [[ -f "${archivo_config}" ]]; then
        # Sustituir el puerto
        sed -i "s/${puerto_predeterminado}/${nuevo_puerto}/g" "${archivo_config}"

        # Cambiar AllowedIPs para redirigir solo el tráfico de la dirección IP permitida
        sed -i "/AllowedIPs/c\AllowedIPs = ${ip_permitida}/32" "${archivo_config}"

        echo "Creado el cliente ${cliente}"
    else
        echo "No se ha creado el cliente ${cliente}"
    fi
done < "${ruta_archivo_clientes}"

echo "Proceso completo"

Como ves, he añadido algunos comentarios para ayudarte a identificar cada parte del script en el futuro. Ahora solo queda grabar los cambios.

Como antes, usamos nano y nos aseguramos de guardar los cambios antes de salir.

Automatizar-la-creación-de-clientes-para-WireGuard-usando-un-Script-002

El último paso será darle al script los permisos necesarios para que pueda ejecutarse. Por ejemplo, puedes usar una orden como esta:

chmod 700 /scripts/nuevos_clientes.sh

Otorgamos privilegios de ejecución solo para el propietario, es decir, para el usuario root.

Automatizar-la-creación-de-clientes-para-WireGuard-usando-un-Script-003

Comprobar el resultado

Para comprobar que funciona, basta con desplazarnos a la carpeta donde guardamos los scripts…

… Y ejecutarlo con la orden que indicábamos al principio del articulo

Automatizar-la-creación-de-clientes-para-WireGuard-usando-un-Script-004

Y con esto damos por concluido nuestro objetivo para este artículo. Espero que te haya resultado útil.