Cómo Instalar y Asegurar el Broker de Mensajería MQTT Mosquitto en Ubuntu 20.04

Mosquitto es un broker de mensajes de código abierto que utiliza el Protocolo de Transporte de Telemetría de Colas de Mensajes (MQTT). El protocolo está diseñado para proporcionar una comunicación ligera a los dispositivos del Internet de las Cosas (IoT). Se utiliza habitualmente para el seguimiento GPS de vehículos, domótica, sensores medioambientales y recogida de datos a gran escala.

El protocolo MQTT se ejecuta sobre el modelo TCP/IP. Al ser ligero, su pequeña huella de código te permite crear aplicaciones para dispositivos con recursos mínimos. Se basa en el modelo publicar/suscribir. En este modelo, el cliente se conecta al servidor Mosquitto, que actúa como intermediario para enviar información a otros clientes suscritos a un canal.

En este tutorial, instalarás Mosquitto y configurarás el broker para que utilice SSL para proteger las comunicaciones.

Requisitos previos

  • Un servidor Ubuntu 20.04 con un usuario no root con privilegios sudo.
  • Un nombre de dominio (myqtt.example.com) apuntando a tu servidor.

Paso 1 – Instalar el Servidor y el Cliente Mosquitto

Ubuntu incluye la versión antigua 1.6 de Mosquitto. Para instalar la última versión, añade el repositorio oficial de Mosquitto.

$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa

Instala el servidor y el cliente de Mosquitto.

$ sudo apt install mosquitto mosquitto-clients

Comprueba el estado del servidor.

$ sudo systemctl status mosquitto
? mosquitto.service - Mosquitto MQTT Broker
     Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2022-01-25 09:18:40 UTC; 25s ago
       Docs: man:mosquitto.conf(5)
             man:mosquitto(8)
   Main PID: 119694 (mosquitto)
      Tasks: 1 (limit: 2274)
     Memory: 1.0M
     CGroup: /system.slice/mosquitto.service
             ??119694 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

Jan 25 09:18:39 <userid> systemd[1]: Starting Mosquitto MQTT Broker...
Jan 25 09:18:40 <userid> systemd[1]: Started Mosquitto MQTT Broker.

Paso 2 – Configurar la autenticación por contraseña MQTT

Mosquitto incluye una utilidad para generar un archivo de contraseñas llamado mosquitto_passwd. Mosquitto almacena todas las configuraciones en el directorio /etc/mosquitto.

Ejecuta el siguiente comando para generar un archivo de contraseña encriptado en /etc/mosquitto/passwd para el nombre de usuario username. Introduce una contraseña de tu elección.

$ sudo mosquitto_passwd -c /etc/mosquitto/passwd username
Password:
Reenter password:

A continuación, crea un archivo default.conf en el directorio /etc/mosquitto/conf.d y ábrelo para editarlo.

$ sudo nano /etc/mosquitto/conf.d/default.conf

Pega las siguientes líneas para especificar la ubicación del archivo de contraseña. Si omites el campo del oyente, siempre se conectará de forma anónima, independientemente de la configuración.

listener 1883
password_file /etc/mosquitto/passwd

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.

Reinicia el servidor Mosquitto para aplicar el cambio.

$ sudo systemctl restart mosquitto

Paso 3 – Probar el Cliente Mosquitto

Dependiendo del caso de uso, puedes utilizar el cliente Mosquitto para enviar y recibir mensajes sobre diferentes temas. Un cliente es un suscriptor o un publicador.

El siguiente paso es suscribirse a un tema. En el protocolo MQTT, un tema se refiere a una cadena utilizada por el servidor/corredor para filtrar mensajes para los clientes conectados. Aquí tienes algunos ejemplos de temas que puedes utilizar en una aplicación domótica.

  • casa/luces/sala de estar
  • casa/luces/cocina
  • casa/luces/dormitorio_principal
  • casa/luces/dormitorio_niños

Para suscribirte a un tema, ejecuta el comando mosquitto_sub -t seguido del tema. Por ejemplo, para suscribirte al tema home/lights/kitchen, ejecuta el siguiente comando.

$ mosquitto_sub -u username -P YOUR_PASSWORD -t "home/lights/kitchen"

No cierres la ventana existente. Abre una nueva ventana de terminal para publicar un mensaje en el tema home/lights/kitchen utilizando el siguiente comando.

$ mosquitto_pub -u username -P YOUR_PASSWORD -m "ON" -t "home/lights/kitchen"

Vuelve a la primera ventana de terminal y recibirás el mensaje ON.

ON

A continuación, envía el mensaje OFF sobre el mismo tema desde el segundo terminal.

$ mosquitto_pub -u username -P YOUR_PASSWORD -m "OFF" -t "home/lights/kitchen"

El primer terminal mostrará el mensaje recién publicado.

ON
OFF

Si intentas enviar un comentario no autenticado, fallará. Por ejemplo, prueba el siguiente comando.

$ mosquitto_sub -t "home/lights/sitting_room"
Connection error: Connection Refused: not authorised.

No es recomendable, pero debes añadir la siguiente línea al archivo /etc/mosquitto/conf.d/default.conf si quieres ejecutar los comandos sin autenticación.

allow_anonymous true

Paso 4 – Instalar SSL

Para instalar un certificado SSL utilizando Let’s Encrypt, necesitamos descargar la herramienta Certbot. Para ello utilizaremos el instalador de paquetes Snapd.

Instala el instalador Snap.

$ sudo apt install snapd

Asegúrate de que tu versión de Snapd está actualizada.

$ sudo snap install core 
$ sudo snap refresh core

Instala Certbot.

$ sudo snap install --classic certbot

Utiliza el siguiente comando para asegurarte de que se ejecuta el comando Certbot creando un enlace simbólico al directorio /usr/bin.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Genera un certificado SSL.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d mqtt.example.com

El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/mqtt.example.com de tu servidor.

Genera un certificado de grupo Diffie-Hellman.

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Crea un directorio raíz web de desafío para la renovación automática de Let’s Encrypt.

$ sudo mkdir -p /var/lib/letsencrypt

Crea un Cron Job para renovar el SSL. Se ejecutará cada día para comprobar el certificado y renovarlo si es necesario. Para ello, primero, crea el archivo /etc/cron.daily/certbot-renew y ábrelo para editarlo.

$ sudo nano /etc/cron.daily/certbot-renew

Pega el siguiente código.

#!/bin/sh
certbot renew --cert-name mqtt.example.com --webroot -w /var/lib/letsencrypt/

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando te lo pida.

Cambia los permisos del archivo de la tarea para que sea ejecutable.

$ sudo chmod +x /etc/cron.daily/certbot-renew

Paso 5 – Configurar MQTT SSL

Ahora que ya tenemos listos los certificados SSL, tenemos que proporcionar a Mosquitto acceso a ellos. Para ello, tenemos que copiar los certificados a una ubicación desde la que Mosquitto pueda acceder a ellos.

$ sudo cp /etc/letsencrypt/live/mqtt.example.com/fullchain.pem /etc/mosquitto/certs/server.pem
$ sudo cp /etc/letsencrypt/live/mqtt.example.com/privkey.pem /etc/mosquitto/certs/server.key

Cambia la propiedad del directorio /etc/mosquitto/certs al usuario mosquitto creado durante la instalación.

$ sudo chown mosquitto: /etc/mosquitto/certs

El siguiente paso para habilitar el cifrado SSL para Mosquitto es especificar la ubicación de los certificados SSL. Abre el archivo de configuración para editarlo.

$ sudo nano /etc/mosquitto/conf.d/default.conf

Pega el siguiente código al final del archivo.

. . .
listener 8883
certfile /etc/mosquitto/certs/server.pem
cafile  /etc/ssl/certs/ISRG_Root_X1.pem
keyfile /etc/mosquitto/certs/server.key
dhparamfile /etc/ssl/certs/dhparam.pem

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida. Asegúrate de dejar una nueva línea al final del archivo.

La parte listener 8883 configura la escucha encriptada. Es el puerto estándar para MQTT + SSL, denominado MQTTS. Las cuatro líneas siguientes especifican la ubicación de los archivos SSL.

Reinicia Mosquitto para actualizar la configuración.

$ sudo systemctl restart mosquitto

Tendrás que actualizar el cortafuegos para permitir las conexiones al puerto 8883.

$ sudo ufw allow 8883

A continuación, tenemos que probar la funcionalidad utilizando el comando mosquitto_pub.

$ mosquitto_pub -h mqtt.example.com -t "home/lights/kitchen" -m "hello" -p 8883 --capath /etc/ssl/certs/ -u username -P YOUR_PASSWORD

Como puedes ver, hemos incluido algunos parámetros adicionales, como el número de puerto y la ruta a los certificados SSL. Siempre que necesites utilizar SSL, tendrás que especificar el nombre de host completo, es decir, mqtt.example.com en lugar de localhost; de lo contrario, daría error.

También tendrás que añadir siempre la directiva --capath. Indica al cliente Mosquitto que busque los certificados raíz instalados por el sistema operativo.

Paso 6 – Configurar la renovación SSL

Certbot renovará automáticamente tu certificado antes de que caduque. Pero hay que decirle que copie los certificados renovados en el directorio /etc/mosquitto/certs y que reinicie el servicio Mosquitto.

Vamos a hacerlo creando un script de shell. Crea un archivo mosquitto-copy.sh en el directorio /etc/letsencrypt/renewal-hooks/deploy.

$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/mosquitto-copy.sh

Pega en él el siguiente código. Sustituye el valor de la variable MY_DOMAIN por tu dominio. La variable ${RENEWED_LINEAGE} apunta al directorio /etc/letsencrypt/live/mqtt.example.com durante la renovación.

# Set which domain this script will be run for
MY_DOMAIN=mqtt.example.com
# Set the directory that the certificates will be copied to.
CERTIFICATE_DIR=/etc/mosquitto/certs

if [ "${RENEWED_DOMAINS}" = "${MY_DOMAIN}" ]; then
	# Copy new certificate to Mosquitto directory
	cp ${RENEWED_LINEAGE}/fullchain.pem ${CERTIFICATE_DIR}/server.pem
	cp ${RENEWED_LINEAGE}/privkey.pem ${CERTIFICATE_DIR}/server.key

	# Set ownership to Mosquitto
	chown mosquitto: ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key

	# Ensure permissions are restrictive
	chmod 0600 ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key

	# Tell Mosquitto to reload certificates and configuration
	pkill -HUP -x mosquitto
fi

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.

Haz que el archivo sea ejecutable.

$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto-copy.sh

Este script se ejecutará automáticamente en cada renovación correcta del certificado.

Si estás ejecutando Mosquitto y un servidor web como Nginx, tienes que indicar a Certbot que detenga el servidor antes de la renovación y lo inicie de nuevo una vez finalizada. Para ello, abre el archivo etc/letsencrypt/renewal/mqtt.example.com.conf.

$ sudo nano /etc/letsencrypt/renewal/mqtt.example.com.conf

Añade las siguientes líneas al final del archivo. Cambia los comandos según el servidor web que estés utilizando.

pre_hook = systemctl stop nginx
post_hook = systemctl start nginx

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te solicite.

Ejecuta un simulacro de Certbot para verificarlo.

$ sudo certbot renew --dry-run

Si no ves errores, significa que todo está configurado.

Paso 7 – Configurar Websockets

Puedes configurar Mosquitto para que utilice el protocolo MQTT desde los navegadores mediante Javascript utilizando la funcionalidad Websockets. Para activarla, abre el archivo de configuración.

$ sudo nano /etc/mosquitto/conf.d/default.conf

Pega las siguientes líneas al final del archivo.

. . .
listener 8083
protocol websockets
certfile /etc/mosquitto/certs/server.pem
cafile  /etc/ssl/certs/ISRG_Root_X1.pem
keyfile /etc/mosquitto/certs/server.key
dhparamfile /etc/ssl/certs/dhparam.pem

Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.

Si te fijas, es el mismo bloque que el que utilizamos para habilitar SSL, excepto por los campos de número de puerto y protocolo. 8083 es el puerto más utilizado por MQTT para hablar utilizando WebSockets.

Reinicia el servicio Mosquitto.

$ sudo systemctl restart mosquitto

Abre el puerto 8083.

$ sudo ufw allow 8083

Necesitamos utilizar un cliente MQTT basado en navegador para probar la funcionalidad de WebSockets. Hay muchos clientes disponibles, pero utilizaremos el cliente Websocket HiveMQ para nuestro propósito. Inicia el cliente en tu navegador y verás lo siguiente.

Cliente Websockets HiveMQ

Como se muestra en la captura de pantalla anterior, rellena los campos como se indica.

  • El host debe ser el dominio de tu servidor Mosquitto, mqtt.ejemplo.com.
  • El puerto debe ser 8083.
  • El campo ClientID puedes dejarlo como está.
  • El nombre de usuario debe ser tu nombre de usuario de Mosquitto.
  • La contraseña debe ser la contraseña que creaste anteriormente.
  • Marca la casilla SSL.

Pulsa el botón Conectar, y el cliente HiveMQ se conectará a tu servidor Mosquitto.

Una vez conectado, introduce home/lights/kitchen como tema, introduce cualquier mensaje y pulsa Publicar.

Mosquitto Websocket Publicar

Aparecerá un mensaje en la ventana de tu terminal mosquitto_sub confirmando que la conexión se ha realizado correctamente.

Mosquitto Websockets Terminal Respuesta

Esto demuestra que la implementación de Websockets se ha realizado correctamente.

Conclusión

Esto concluye nuestra configuración de un servidor MQTT seguro, protegido por contraseña y encriptado con SSL en una máquina basada en Ubuntu 20.04. Si tienes alguna pregunta, publícala en los comentarios a continuación.

También te podría gustar...