Kbsa: conectar Shelly a RabbitMQ mediante MQTT con mTLS

Resumen

Esta solución conecta de forma segura un dispositivo Shelly IP a RabbitMQ mediante el complemento MQTT usando TLS mutuo (mTLS), sin contraseñas y con autenticación mutua basada en certificados. Un único script de Bash instala y configura RabbitMQ, genera una CA privada y certificados de servidor y cliente, y después muestra una tabla con los valores de configuración. Cuando termina, el único paso manual en Shelly es cargar ca.crt, client.crt, y client.key, copia esos valores en la configuración de MQTT y guárdala. Admite la selección de la serie de RabbitMQ (--rmq-series 3.13|4.0|4.1, 4.1 de forma predeterminada) desde los repositorios Ubuntu noble de Team RabbitMQ y fuerza TLS 1.2 únicamente. En 4.x, el MQTT client_id se aplica desde el certificado SAN (URI) mientras que la autenticación nombre de usuario sigue proviniendo del certificado CN; en la versión 3.13, SAN->client_id la vinculación no está disponible. Puedes controlar el host de conexión (y el CN/SAN del certificado del servidor) mediante --connect-dns / --connect-ip. El script exporta los certificados de los dispositivos a /etc/mqtt-cert y, de forma predeterminada, también emite un certificado de monitorización (-mon) en /etc/mqtt-cert-monitor con archivos tarball en /tmp/.

Resultado: MQTT cifrado y autenticado mediante certificados, con acceso a temas basado en el principio de mínimo privilegio.

Enlace al script aquí.

Importante: este script es solo para desarrollo/pruebas, un ejemplo de lo que es posible hacer. Úsalo con cuidado y no lo implementes tal cual en producción.

Arquitectura

Esquema
[Shelly device] | | MQTT sobre TLS (mTLS) - puerto 8883 v [receptor MQTT de RabbitMQ] ---> [intercambio amq.topic] ---> [queues/subscriptions] | | | ‘-- ACL de temas limitadas a tu prefijo MQTT | ‘-- Interfaz de administración (HTTPS, 15671) 
  • Transporte: Shelly se comunica con RabbitMQ por el puerto 8883 (MQTTS). TLS es obligatorio; los clientes deben presentar un certificado válido (mTLS) y se fuerza únicamente TLS 1.2.

  • Identidad: el CN del certificado del dispositivo se asigna a un usuario de RabbitMQ (sin nombre de usuario ni contraseña en Shelly).

  • Vinculación del ID de cliente: se aplica desde el SAN del certificado (URI) en RabbitMQ 4.x. El nombre de usuario sigue proviniendo del CN; la versión 3.13 no admite SAN→client_id.

  • Autorización: las ACL de temas están restringidas al prefijo MQTT elegido (además de solo lectura en shellies/command por compatibilidad).

  • Multiarrendamiento: MQTT no transporta vhosts, por lo que las conexiones se enrutan a un vhost dedicado (por ejemplo, /shelly) mediante mqtt.vhost.

  • Gestión: interfaz HTTPS en 15671.

  • Puertos sin cifrar: Desactivados de forma predeterminada. Puedes mantener temporalmente 1883/15672 con --keep-plaintext durante la migración.

Referencia rápida

Inquietud

Decisión

Puerto (datos)

8883 / TCP (MQTTS con mTLS)

Puerto (administración)

15671 / TCP (interfaz de usuario de gestión HTTPS)

Identidad

Certificado CN -> usuario de RabbitMQ

ID de cliente

Proporcionado por el usuario en Shelly; en RabbitMQ 4.x se aplica a partir del SAN del certificado (URI). En 3.13, SAN-> client_id la vinculación no está disponible

Vhost

/shelly (se establece mediante mqtt.vhost)

Temas

Restringido a tu prefijo MQTT (tanto en formato con barra como con punto), además de acceso de solo lectura a shellies/command (shellies.command)

Secretos en el dispositivo

Solo la clave del cliente (sin contraseñas)

Texto sin cifrar

Desactivado de forma predeterminada; activación opcional con --keep-plaintext

Versión de TLS

Solo TLS 1.2

Requisitos previos

  • Entorno probado (en el momento de redactar): Ubuntu 24.04 LTS (amd64), RabbitMQ 4.1 (instalado mediante este script), firmware de Shelly 1.7.1.

  • Instalación: desde los repositorios de Team RabbitMQ fijados para Ubuntu noble.

  • Acceso: Shell en el host con privilegios de sudo; se necesita internet saliente para los repositorios apt.

  • Direccionamiento: IP/DNS estable del broker (el script puede detectarla automáticamente, pero es mejor fijarla).

  • Sincronización horaria: NTP habilitado (la validez del certificado depende de que la hora sea correcta).

  • Opcional: mosquitto-clients para realizar rápidamente pruebas de extremo a extremo.

Qué hace el script

  1. Instalar RabbitMQ (3.13 / 4.0 / 4.1) y el Erlang correspondiente en Ubuntu 24.04

    Utiliza los repositorios apt de Team RabbitMQ (la ruta recomendada actualmente) para obtener versiones modernas de Erlang/RabbitMQ. https://www.rabbitmq.com/docs/install-debian

  2. Configurar mediante rabbitmq.conf (no rabbitmq-env.conf)

    La configuración en tiempo de ejecución (listeners, TLS y complementos) se encuentra en rabbitmq.conf; rabbitmq-env.conf solo se utiliza para las variables de entorno. https://www.rabbitmq.com/docs/configure

  3. Habilitar los complementos de MQTT y gestión

    Activa la compatibilidad nativa con MQTT y la gestión/interfaz de usuario HTTPS, y habilita rabbitmq_auth_mechanism_ssl. https://www.rabbitmq.com/docs/mqtt

    1. Habilitar detailed_queues_endpoint indicador de función (detalle exclusivo de la interfaz de usuario para las colas).

  4. Exige TLS mutuo (mTLS) para MQTT

    Establece ssl_options.verify = verify_peer y ssl_options.fail_if_no_peer_cert = true por lo que los clientes deben presentar un certificado válido; fuerza únicamente TLS 1.2. https://www.rabbitmq.com/docs/mqtt#tls

  5. Inicio de sesión con certificado sin contraseña (CN → usuario)

    Habilita mqtt.ssl_cert_login = true y ssl_cert_login_from = common_nameEl usuario asignado debe existir en RabbitMQ (no se necesita contraseña). https://www.rabbitmq.com/docs/mqtt#tls-certificate-authentication

  6. Vincula el client_id de MQTT al SAN (URI) del certificado

    En RabbitMQ 4.1, establece

Bash
mqtt.ssl_cert_client_id_from = subject_alternative_name 

por lo que el CONNECT client_id debe coincidir con el SAN del certificado (evita la suplantación de identidad). https://www.rabbitmq.com/docs/mqtt#usage-of-client_id-extraction-from-client-certificates-for-authentication

Esto vincula client_id al certificado SAN (URI). Nombre de usuario siga procediendo de CN; si quieres que el nombre de usuario de SAN en su lugar, cambiarías a ssl_cert_login_from=subject_alternative_name y ssl_cert_login_san_type=uri en la configuración.

  1. Emitir dos certificados de cliente (mismo CN, SAN distintos)

    • dispositivo: SAN=URI:

    • monitor: SAN=URI:-mon

    • Perfiles de certificados: CA RSA-4096; servidor/cliente RSA-2048; validez de las hojas ≈ 825 días

Te permite suscribirte con el certificado de monitorización sin desconectar el dispositivo (ID de cliente distintos).

  1. Bloquear los escuchas y puertos

  2. Crear tenencia y permisos

  3. Salida que utilizas en Shelly

    Escribe una carpeta de exportación con ca.crt, client.crt, client.key e imprime una tabla con los valores exactos que debes copiar en la configuración de Shelly MQTT.

Implementación

  1. Ejecutar el script

Bash
./shelly-rmq-mqtt/setup-mqtt-mtls.sh \ --admin-user admin \ --admin-pass 'Sh3lly-i0T!' \ -C 'Shelly-Group' \ --client-id 'test-device' \ --vhost /shelly \ --mqtt-prefix 1pm-mini 

Precedencia del host de conexión (y CN del certificado): --connect-dns > --connect-ip > --ip (detección automática si no se especifica ninguno). Este valor elegido se convierte en el CN del certificado del servidor y es al que deben conectarse los clientes.

Indicadores útiles (según sea necesario)

Bash
Identidad / destino de conexión (al que se conectan los clientes; determina el CN/SAN del certificado) --connect-dns  # preferido: los clientes se conectan a este nombre --connect-ip  # los clientes se conectan a esta IP (si no hay DNS) Identidad del host (esta máquina) -i | --ip | --server-ip  # IP principal detectada por sustitución (usada en el resumen y SAN) MQTT / tenencia / temas -V | --vhost # valor predeterminado /shelly --mqtt-prefix  # ámbito de ACL del tema Certificados / resultados --tls-dir  # valor predeterminado /etc/rabbitmq-tls --export-dir  # valor predeterminado /etc/mqtt-cert --monitor-export-dir  # valor predeterminado /etc/mqtt-cert-monitor --no-monitor-cert # omitir -mon bundle --monitor-client-id  # valor predeterminado -mon --force-regen # rotar CA/servidor/cliente incluso si ya existen Versionado de RabbitMQ --rmq-series 3.13|4.0|4.1 # valor predeterminado 4.1 Autenticación / usuarios --admin-user  # administrador predeterminado -p | --admin-pass  # se genera automáticamente de forma predeterminada si se omite -C | --client-cn  # Shelly-Group predeterminado --client-id  # valor predeterminado =  Redes (compatibilidad temporal) --keep-plaintext # mantener abiertos 1883/15672 durante la migración Registro / diagnósticos -l | --log-level debug|info|warn|error -d | --debug # transmitir logs; sin indicador de progreso --debug-tls | --tls-debug # imprimir diagnósticos del certificado (o DEBUG_TLS=1) 


El script se ejecutará, recorrerá cada paso y mostrará un indicador de éxito y un error si se produce.

Pasos del script
Pasos del script

Cuando termine, consulta la tabla de resumen en la parte inferior:

  • IP/puertos del broker

  • ID de cliente y prefijo MQTT

  • Rutas a ca.crt, client.crt, client.key (carpeta de exportación)

  • Opciones de configuración de Shelly

  • URL de administración: https://:15671 (o https://:15671 si CN es una IP)

  • Usuario y contraseña de administrador (la contraseña se genera automáticamente, a menos que pases --admin-pass)

  • Ruta del archivo de log: /tmp/rabbitmq-mqtt-setup.log

Tabla de resumen
Tabla de resumen del script
  1. Subir certificados a Shelly

    1. Abre Interfaz web de Shelly → Configuración → Configuración de TLS.

    2. Sube los tres archivos de la carpeta de exportación del script:

      • Certificado de CA: ca.crt

      • Certificado del cliente: client.crt

      • Clave privada del cliente: client.key

    3. Sube cada archivo individualmente: selecciona el archivo, haz clic en Subir y espera la ventana emergente que confirme que se ha realizado correctamente. Repite el proceso con los tres.

Configuración de Shelly del script
Configuración de Shelly del script
  1. Configurar Shelly MQTT

    1. Abre Interfaz web de Shelly → Configuración → MQTT.

    2. Configura los valores del script:

Habilitar: Seleccionado TLS del usuario: Seleccionado Usar certificado de cliente: Habilitado Habilitar «Control MQTT»: Habilitado Habilitar RPC sobre MQTT: Habilitado Notificaciones de estado de RPC sobre MQTT: Habilitado Actualización de estado genérica sobre MQTT: Habilitado Servidor: Valor del script ID de cliente: Valor del script Prefijo MQTT: Valor del script Nombre de usuario / Contraseña: Dejar en blanco 
  1. Haz clic en Guardar configuración y reinicia el dispositivo

Una vez finalizada la configuración, el dispositivo debería verse así:

Interfaz web de configuración de MQTT de Shelly
Interfaz web de configuración de MQTT de Shelly
  1. Después de que Shelly se reinicie, ejecuta el comando de supervisión que muestra el resumen del script. Se genera automáticamente a partir de los valores que proporcionaste y utiliza el certificado de supervisión (con un client_id distinto), por lo que no desconectará el dispositivo. Deberías ver mensajes fluyendo de Shelly a RabbitMQ.

Comando de supervisión listo para ejecutar
Comando de supervisión listo para ejecutar

Deberías ver que Shelly se conecta y publica.

Supervisión de mensajes de Shelly a RabbitMQ
Supervisión de mensajes de Shelly a RabbitMQ

También puedes confirmar que la conexión se realizó correctamente en la interfaz web de Shelly: el icono de MQTT de la esquina superior derecha muestra dos flechas cuando está conectado. Si ves las flechas, el dispositivo está vinculado activamente a RabbitMQ mediante MQTT/TLS.

Indicador de conexión MQTT de Shelly correcta
Indicador de conexión MQTT de Shelly correcta

También puedes ver un indicador en la interfaz web de RabbitMQ, en Conexiones

Información de conexión de la interfaz web de RabbitMQ
Interfaz web de RabbitMQ: estado de la conexión
Interfaz web de RabbitMQ: información de conexión
Interfaz web de RabbitMQ: información de conexión

El script también muestra un resumen de depuración de certificados que te ayuda a ver qué certificados se generaron para minimizar los problemas que puedan surgir. Ten en cuenta que debes utilizar la Indicador --debug-tls.

Pasos para depurar certificados
Pasos para depurar certificados

Solución de problemas

  1. Sincronización horaria: asegúrate de que los relojes del bróker y de Shelly sean correctos (NTP). Una hora desfasada interrumpe TLS.

  2. Se han cargado tres archivos: ca.crt, client.crt, client.key (cada uno por separado, con una ventana emergente de confirmación).

  3. Client ID frente a SAN: en RabbitMQ 4.1, el Client ID debe coincidir con el SAN (URI) del certificado. Si difieren, se rechaza la conexión.

    • En RabbitMQ 3.13, no se admite vincular client_id desde SAN; solo se utiliza CN->username.

  4. El usuario del CN existe: el CN del certificado debe coincidir con un usuario existente de RabbitMQ (no se necesita contraseña con mTLS).

  5. Puertos: usa 8883 (MQTTS). 1883/15672 están desactivados, a menos que hayas ejecutado el script con --keep-plaintext.

  6. Firewall: si UFW está activo, el script abre 8883 y 15671; de lo contrario, no cambia las reglas del firewall.

  7. Prefijo: los temas deben estar bajo tu prefijo de MQTT o las ACL de RabbitMQ los bloquearán.

  8. Coincidencia entre clave y certificado: Si las conexiones fallan, ejecuta con --debug-tls y comprueba la línea “key <-> cert match” tanto para el servidor como para el cliente.