Automatizar la creación de clientes para WireGuard usando un Script
Si 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.
Hoy 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 ...
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:
-
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.
-
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.
-
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.
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
Comprobar el resultado
Para comprobar que funciona, basta con desplazarnos a la carpeta donde guardamos los scripts…
Y con esto damos por concluido nuestro objetivo para este artículo. Espero que te haya resultado útil.