Skip to main content
ESPBoards

Broker MQTT Seguro en Contenedores Docker con HASS

Ejecutar un Broker MQTT local seguro con TLS y autenticación por certificado en contenedores Docker. Integrar dispositivos MQTT con Home Assistant en Raspberry Pi


Hoy vamos a configurar y ejecutar un Broker MQTT local con Mosquitto en contenedores Docker. Vamos a hacer que nuestras conexiones MQTT sean seguras configurando TLS y autenticación por certificado para los clientes. Luego vamos a integrar nuestro broker MQTT seguro con una instancia de Home Assistant que se ejecuta en Raspberry Pi.

¿Qué es MQTT? #

MQTT, que significa Message Queuing Telemetry Transport, es un protocolo de mensajería ligero y eficiente diseñado para la comunicación en entornos con recursos limitados, a menudo en el contexto del Internet de las Cosas, donde los dispositivos, como los microcontroladores, no tienen mucha potencia de procesamiento o memoria.

El protocolo MQTT sigue un modelo de publicación-suscripción, lo que permite a los dispositivos enviar mensajes y suscribirse a temas de interés. Supongamos que tienes un termostato inteligente (el publicador) que envía actualizaciones de temperatura a un tema llamado "Home/LivingRoom/Temp". Ahora, tu pantalla inteligente (el suscriptor) sintoniza ese tema específico, esperando las últimas noticias de temperatura.

De alguna manera, es como una estación de radio. La estación (tema) transmite, y cualquiera con una radio coincidente (suscriptor) puede captar la señal. Solo que no queremos transmitir nuestros datos a cualquiera, por lo tanto, autenticamos a los suscriptores. Pero hablaremos de esto más adelante en esta publicación.

Broker MQTT y Eclipse Mosquitto #

Siguiendo con la analogía de la estación de radio, imagina que no solo tenemos un termostato inteligente, sino muchos dispositivos MQTT (publicadores) que están enviando su información, ya sea temperatura, humedad, brillo de luz u otra cosa. Todos estos dispositivos están tratando de "tocar su canción" (enviar sus datos), y podrían querer hacerlo al mismo tiempo.

Si dejamos que cada dispositivo "toque su canción", sería un caos. Necesitamos a alguien que diga quién puede tocar cuándo. Y ahí es donde entra en juego el Broker MQTT.

El Broker MQTT es un servidor centralizado que se encarga de recibir, gestionar y distribuir mensajes entre dispositivos que se comunican utilizando el protocolo MQTT (Message Queuing Telemetry Transport).

Eclipse Mosquitto #

Mosquitto es una implementación específica de un broker MQTT, y es una de las opciones de código abierto más populares que existen. Desarrollado por la Eclipse Foundation, Mosquitto es un broker confiable y ligero que facilita la comunicación MQTT.

Y bien, ¿código abierto y más popular? Eso lo dice todo, utilizaremos Mosquitto como nuestro Broker MQTT.

¿Por qué ejecutar Mosquitto en un contenedor Docker? #

Según la documentación MQTT de Home Assistant, "El método de configuración recomendado es usar el complemento del broker MQTT Mosquitto.". Pero como nuestro Home Assistant está en el contenedor Docker, no tenemos una opción para Plugins de Home Assistant, como se describe en la instalación de Home Assistant.

Además, dado que ya tenemos una instancia de Home Assistant en ejecución en un contenedor Docker, como se describe en la publicación anterior, ¿por qué no simplemente iniciar otro contenedor al lado?

Configuración y ejecución del Broker Mosquitto #

Para configurar y ejecutar nuestro Broker Mosquitto local en un contenedor Docker, necesitaremos configurar el Broker Mosquitto y escribir un pequeño archivo docker-compose. Vamos a ello.

Conectar a Raspberry Pi #

Primero, ssh en raspberry, de la misma manera que se describe en la publicación "Home Assistant en Contenedores Docker en Raspberry Pi". Asegúrate de reemplazar la IP con la dirección IP local de tu Raspberry.

ssh rpi@192.168.1.10

Estructura de carpetas y archivos #

Ahora, vamos a crear las carpetas y archivos vacíos necesarios.

Crea una carpeta raíz para el broker Mosquitto, la llamaremos "mosquitto" y cambiamos a ella:

mkdir mosquitto && cd mosquitto

A continuación, crea una carpeta de configuración y un archivo de configuración:

mkdir config && touch config/mosquitto.conf

Finalmente, crea un archivo docker-compose.yml vacío:

touch docker-compose.yml

La estructura final de carpetas y archivos debería ser así:

  • mosquitto
    • config
      • mosquitto.conf
    • docker-compose.yml

Configuración de Mosquitto #

Aunque sea mínima, aún necesitamos crear una configuración para el Broker Mosquitto. Abre el archivo config/mosquitto.conf para editarlo y completa lo siguiente:

allow_anonymous true
persistence false
listener 1883
  1. allow_anonymous true: Esta opción de configuración en Mosquitto controla si se permite la conexión de clientes anónimos (clientes sin un nombre de usuario). Configurarla en true permitirá usuarios anónimos, lo cual es perfecto para la primera prueba.

  2. persistence false: Esto significa que Mosquitto no almacenará ningún dato persistente entre reinicios del broker.

  3. listener 1883: Configura un listener en el puerto MQTT por defecto (1883). Los clientes pueden conectarse al broker en este puerto.

Docker compose #

La configuración del contenedor Docker (docker compose) también es bastante mínima. Abre el archivo docker-compose.yml para editarlo y completa lo siguiente:

version: "3.7"
services:
mqtt5:
image: eclipse-mosquitto
container_name: mqtt5
volumes:
- ./config:/mosquitto/config/
ports:
- '1883:1883'
networks:
- default
restart: unless-stopped

Esto usará una imagen de docker eclipse-mosquitto para el contenedor. Nombraremos al contenedor "mqtt5". Volumes es una opción importante, que montará la carpeta config/ que creamos anteriormente en el contenedor docker, lo que significa que el contenedor docker podrá acceder a la carpeta config/. Luego permitimos el puerto 1883 y configuramos una interfaz de red predeterminada.

Ejecutar el Contenedor Docker de Mosquitto #

Finalmente, estamos listos para ejecutar nuestro Contenedor Docker de MQTT Mosquitto. Antes de comenzar, obtén permisos de root escribiendo sudo su. Ejecuta el siguiente comando para iniciar el contenedor Docker:

docker-compose up -d

Espera a que termine y ejecuta:

docker ps

Deberías ver "Up xx seconds" en la columna de STATUS. Si ves algo diferente, como "Restarting", hay un problema.

Para la resolución de problemas, puedes verificar los registros de Mosquitto ejecutando:

docker logs mqtt5

Prueba del Broker Mosquitto #

Para probar el Broker Mosquitto, en una ventana de terminal ejecutaremos un Suscriptor MQTT, que se suscribirá a un tema proporcionado en una ventana de terminal. En otra ventana de terminal ejecutaremos un Publicador MQTT, que publicará mensajes MQTT.

En la ventana de terminal, ejecuta el comando del Suscriptor Mosquitto:

docker exec mqtt5 mosquitto_sub -h localhost -p 1883 -t test/topic

Deberías ver el cursor moverse a la siguiente línea y quedarse allí. Puede parecer que está atascado, pero no lo está. Esto significa que el Suscriptor MQTT está esperando mensajes.

Mantén esta ventana de terminal abierta y abre una nueva terminal. Conéctate a Raspberry Pi por SSH y ejecuta el comando del Publicador Mosquitto:

sudo docker exec mqtt5 mosquitto_pub -h localhost -p 1883 -t test/topic -m "Hello World!"

A la izquierda, puedes ver un Suscriptor MQTT que recibió un mensaje del Publicador MQTT que puedes ver en la terminal del lado derecho.

Asegurando el Broker MQTT #

¡Eso es genial! ¡Tenemos el Broker MQTT Mosquitto funcionando! Pero hay algunas cosas que necesitamos solucionar... Primero, permitimos que cualquier persona publique mensajes MQTT sin autenticación, lo cual ya es una posible amenaza de seguridad. Segundo, nuestros mensajes están viajando por el aire en texto claro (sin cifrar) y podrían ser interceptados fácilmente. Vamos a solucionar ambos problemas.

Antes de continuar, asegúrate de detener el contenedor anterior del Broker MQTT:

sudo docker stop mqtt5

Generar claves #

Para asegurar nuestras conexiones MQTT, usaremos cifrado TLS y autenticación por certificado. Pero para esto, necesitaremos generar nuestro propio certificado de Autoridad Certificadora (CA), así como claves públicas y privadas del servidor y del cliente.

Ve a la carpeta mosquitto/config/:

cd config/

Crea un nuevo archivo. Escribiremos un script bash allí para generar los certificados y claves necesarios:

touch generate-keys.sh

Abre el archivo y completa lo siguiente:

#!/bin/bash

IP_ADDR="localhost"
INFO_CA="/C=BE/ST=Brussels/L=Brussels/O=espboards/OU=CA/CN=$IP_ADDR"
INFO_SERVER="/C=BE/ST=Brussels/L=Brussels/O=espboards/OU=Server/CN=$IP_ADDR"
INFO_CLIENT="/C=BE/ST=Brussels/L=Brussels/O=espboards/OU=Client/CN=$IP_ADDR"

function gen_CA () {
openssl req -x509 -nodes -sha256 -newkey rsa:2048 -subj "$INFO_CA" -days 365 -keyout ca.key -out ca.crt
}

function gen_server () {
openssl req -nodes -sha256 -new -subj "$INFO_SERVER" -keyout server.key -out server.csr
openssl x509 -req -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
}

function gen_client () {
openssl req -new -nodes -sha256 -subj "$INFO_CLIENT" -out client.csr -keyout client.key
openssl x509 -req -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
}

gen_CA
gen_server
gen_client

Guarda el archivo y otorga permisos de ejecución:

chmod +x generate-keys.sh

Ejecuta el script:

./generate-keys

Esto generará los certificados y claves necesarios. Deberías obtener una lista de estos archivos:

  • ca.crt
  • ca.key
  • ca.srl
  • client.crt
  • client.csr
  • client.key
  • server.crt
  • server.csr
  • server.key

Usar las claves en Mosquitto #

Edita el archivo mosquitto.conf para usar las claves generadas. Añade o actualiza las siguientes líneas en el archivo:

allow_anonymous false
listener 8883

cafile /mosquitto/config/certs/ca.crt
certfile /mosquitto/config/certs/server.crt
keyfile /mosquitto/config/certs/server.key

require_certificate true
use_identity_as_username true

Cambiar puertos en Docker Compose #

Abre el archivo docker-compose.yml para editarlo y cambia el mapeo de puertos a 8883:8883:

version: "3.7"
services:
mqtt5:
image: eclipse-mosquitto
container_name: mqtt5
volumes:
- ./config:/mosquitto/config/
ports:
- '8883:8883'
networks:
- default
restart: unless-stopped

Ejecutar Broker Mosquitto MQTT Seguro #

Ejecuta el comando docker-compose up para iniciar el Broker Mosquitto MQTT seguro:

docker-compose up -d

Verifica si el contenedor está en ejecución con docker ps. Si ves el contenedor mqtt5 con el estado "Up xx minutes", ¡tenemos éxito!

Prueba de la conexión segura con el Broker MQTT #

De la misma manera en que hemos probado antes, probemos los mensajes MQTT seguros esta vez. En una terminal, ejecuta el Suscriptor Mosquitto, pero esta vez proporciona el certificado del cliente, la clave del cliente y el certificado CA. Recuerda que las rutas deben ser rutas dentro de Docker, no de tu máquina local. También asegúrate de usar el puerto actualizado (8883):

docker exec mqtt5 mosquitto_sub -h localhost -p 8883 -t test/topic  --cert /mosquitto/config/certs/client.crt --key /mosquitto/config/certs/client.key --cafile /mosquitto/config/certs/ca.crt

En otra ventana de terminal, ejecuta el Publicador Mosquitto. De la misma manera que para el Suscriptor, proporciona los certificados y claves:

docker exec mqtt5 mosquitto_pub -h localhost -p 8883 -t test/topic -m "Hello Secure World!" --cert /mosquitto/config/certs/client.crt --key /mosquitto/config/certs/client.key --cafile /mosquitto/config/certs/ca.crt

En la imagen de abajo, a la izquierda ves una terminal con Mosquitto Subscribe, y a la derecha hay una terminal con Mosquitto Publish. La terminal del lado derecho (Publisher) envió un mensaje MQTT seguro a la terminal del lado izquierdo (Subscriber).

Integrar el broker MQTT local con Home Assistant #

Copiar certificados a tu computadora #

En tu máquina host (tu computadora portátil, por ejemplo), crea una carpeta donde desees almacenar temporalmente los certificados y copia los certificados desde Raspberry Pi, usando el siguiente comando:

scp -r rpi@192.168.129.13:~/mosquitto/config/certs/ certs/

Modo Avanzado en Home Assistant #

Para poder configurar la integración con un Broker MQTT seguro, necesitaremos el modo avanzado en Home Assistant. En la interfaz web de Home Assistant, ve al perfil de tu usuario y habilita el "Modo Avanzado".

Integración del Broker MQTT en Home Assistant #

  1. En la interfaz web de Home Assistant, ve a Configuración -> Dispositivos y Servicios
  2. Haz clic en "Agregar integración" y busca "MQTT"
  3. Selecciona "MQTT"
  4. En la ventana de diálogo, ingresa la siguiente información
EntradaValor
Brokerlocalhost
Port8883
Usar un certificado de cliente
Subir archivo del certificado del clienteclient.crt
Subir archivo de clave privadaclient.key
Validación del certificado del brokerPersonalizado
Subir archivo de certificado CA personalizadoca.crt
  1. Haz clic en "Siguiente", si la información proporcionada es correcta, deberías ver un mensaje de éxito.

Probar la Integración de Home Assistant con el Broker Mosquitto MQTT #

Nuevamente, en Configuración -> Dispositivos y Servicios, encuentra el servicio "MQTT", debajo de "Dispositivos configurados" y ábrelo. Junto a la entidad de integración "localhost", haz clic en "Configurar".

En la ventana que se abre, bajo "Escuchar un tema" ingresa el tema "test/topic" y haz clic en "Comenzar a escuchar".

En la sección "Publicar un paquete", ingresa el mismo tema "test/topic", ingresa un payload y haz clic en "Publicar". Deberías ver el contenido del payload siendo recibido en la sección "Escuchar un tema".

Consejo: Puedes suscribirte a TODOS los temas, escribiendo '#' como tema en la suscripción.

Limpieza #

Dado que las claves del cliente y otros archivos en el servidor en mosquitto/config/certs son restos de generar los pares de claves, queremos eliminarlos del servidor (Raspberry Pi). En Raspberry Pi, abre la carpeta mosquito/config/certs/ y elimina todo excepto estos:

  • ca.crt
  • server.crt
  • server.key

¿Qué sigue? #

Solo hemos probado los mensajes MQTT con un suscriptor MQTT simulado y un publicador MQTT simulado. Para aprovechar realmente nuestro Broker MQTT local, el siguiente paso lógico es integrar un dispositivo MQTT real, como un sensor de temperatura.

Conclusión #

Hemos configurado el Broker MQTT con Mosquitto en un contenedor Docker e integrado con Home Assistant. Pero repasando los pasos logrados, primero configuramos el Broker Mosquitto mínimo y lo probamos con los comandos mosquitto_sub y mosquitto_pub. Más tarde, aseguramos nuestro Broker Mosquitto añadiendo TLS y autenticación por certificado y probamos la comunicación segura. Finalmente, integramos el Broker Mosquitto MQTT seguro con la instancia de Home Assistant.