MQTT para conectar una web online con un backoffice remoto

1. Resumen

A continuación se presenta una solución basada en MQTT ([1] mqtt.org) para conectar una plataforma web de venta, gestión de producto y relación con el cliente para que use e interaccione con una base de datos remota en uno o varios servidores protegidos (sin conexión directa).

Durante la secunda parte, a partir del punto 5. Usando MQTT para conectar nuestros sistemas, detallamos los pasos necesarios para implementar dicha solución, incluyendo indicaciones técnicas y ejemplos concretos de código necesarios para desplegar la solución [1] MQTT.

Palabras clave: MQTT, Micro servicios, Hacking, Seguridad web, Python, Stashing MQTT

Para una lectura rápida de concepto, recomendamos leer (no más de 2 minutos) los tres primeros puntos, junto con las conclusiones:

2. Definición del problema

Varios de los desafíos a resolver con una plataforma de venta online y que tiene estar "conectada" en tiempo real con un backoffice remoto son:

  1. Tener la capacidad de integrar los productos contratados, cambios de precios, facturas, etc, con los sistemas de base de datos normalmente localizados en oficinas, separadas del datacenter.
  2. La seguridad y el control de la información: no parece una buena idea tener información contable, facturas, declaraciones 347 y todo tipo de movimientos en la propia máquina donde ejecuta la web.

    Un único fallo de seguridad en la programación de la web podría poner en riesgo toda esta información.

    Sin embargo, necesitamos poder proporcionar toda esta información al cliente debido a los enormes beneficios que esto proporciona: gestión ágil del producto y el acceso inmediato a la información que necesita el cliente.

  3. Protección frente hacking directo reduciendo la superficie de ataque. Efectívamente, abrir puertos TCP/UDP de aplicaciones de contabilidad, bases de datos, etc, aunque estén limitados por IP, es un riesgo enorme.

    Hay que contar con un diseño que espere lo mejor pero que se prepare para lo peor: la web puede ser hackeada y no por eso, el atacante debe tener acceso a puertos autorizados.

3. Desafios a resolver

Tras varias alternativas estudiadas, llegamos a la conclusión de que necesitábamos una solución que proporcione un [3] bajo acoplamiento entre la web de venta online y el sistema interno de gestión contable (con sus distintos componentes).

En concreto, los requisitos a cumplir son:

4. Diseño de la solución: MQTT al rescate

El protocol MQTT ([1] mqtt.org) define un estándar abierto para el intercambio de mensajes entre distintos participantes siguiendo un modelo de [4] PUBLISH-SUBSCRIBE.

En esencia, participantes sin conocimiento mútuo, ni conexión directa, ejecutando plataforma heterogenea, pueden intercambiar mensajes sin tener que obligarse a estar presentes en el momento del intercambio.

Las características que nos proporciona MQTT, junto con algunos añadidos nos resuelven los retos técnicos que tenemos. Veamos cómo.

5. Usando MQTT para conectar nuestros sistemas

Lo primero que necesitaremos es un Broker MQTT. Este es el componente servidor del protocolo MQTT. Es el encargado de autorizar a los participantes, hacer el almacenamiento de los mensajes y de hacer el rutado entre los componentes que publican y los subscriptores.

Existen varias implementaciones disponibles [1] y [2].

[5] http://www.steves-internet-guide.com/mqtt-hosting-brokers-and-servers/

[6] https://github.com/mqtt/mqtt.github.io/wiki/brokers

Nosotros usaremos [7] MyQttHub.com, una plataforma Cloud MQTT con toda la mecánica disponible, administración WEB y API REST.

MyQttHub.com nos proporciona un plan Open sin coste con capacidad para enviar 10.000 mensajes al día, 310.000 mensajes al mes. Sobrada capacidad de manera que tendríamos resuelta esta parte: no habría que preocuparse por mantener un sistema más.

Para ello, nos creamos una cuenta MyQttHub Open directamente desde la misma web, usando el formulario de subscripción: MyQttHub.com. Hay más información sobre el proceso en [3]:

[8] Cómo crear tu cuenta Open MyQttHub.com

Ahora, vayamos integrando paso a paso la solución en nuestro entorno. Comenzaremos con la parte privada de tu red (conectando una sede).

6. Conectando tu plataforma privada local al servidor MQTT

Para poder "exportar" la información que necesitan tus usuarios, necesitas conectar tus sistemas al servidor MQTT. El proceso de configuración inicial es sencillo:

  1. Necesitarás un cliente satélite MQTT que haga de puente (MQTT bridge) entre la plataforma MQTT y tu sistema. Este cliente satélite se encargará de sostener la conexión y de mapear/transformar los mensajes recibidos desde la plataforma MQTT en comandos locales.
  2. Estos "comandos locales" encapsularán la parte específica de tu instalación. Ahora veremos esto. Primero, usaremos como cliente satélite MQTT MyQttSatellite. Es gratuito, sin límites ni costes.

    Para ello, sigue los pasos descritos el siguiente enlace para descargar instalar y conectar tu equipo:

    [9] MyQttSatellite: cliente MQTT para mapear mensajes a comandos

  3. Una vez conectado el cliente MQTT satélite tendrás que implementar la lógica para cada mensaje o API MQTT que vaya proporcionando tu solución. Para ello, elegiremos Python, aunque cualquier lenguaje te valdrá. Mira cómo lo hacemos con Python para adaptarlo a tu caso.
  4. En concreto, implementaremos soporte para las operaciones "alta de usuario" y "listado de productos". Estas dos operaciones te darán una visión de cómo se implementa una operación de modificación y una operación de consulta.
  5. Para la operación de "alta de usuario", crearemos una estructura básica como la que sigue. Usaremos JSON para la codificación de los mensajes aunque puedes usar XML, CSV o incluso formatos binarios como MessagePack sin problemas:
       #!/usr/bin/python
    
       import sys
       import json
    
       # leemos el mensaje recibido
       message     = open (sys.argv[1]).content
    
       # parseamos el mensaje Json
       newCustomer = json.loads (message)
       if not newCustomer:
           print "ERROR: failed to parse new customer mesasge, empty content received"
           sys.exit (-1)
    
       # implementa aquí la parte específica de alta de usuario en tu
       # base de datos local (consulta SQL, llamada API, etc..)
    
    
       # finalizamos reportando estado OK
       sys.exit (0)
    
  6. Para implementar soporte para una operación de consulta, tan solo tendrás que extender el ejemplo anterior imprimiendo la salida en un formato conocido para el receptor, junto con una cabecera (X-Publish-Reply-To-Topic). Más detalles sobre esto en:

    [10] Cómo generar respuestas MQTT con MyQttSatellite: uso de la cabecera X-Publish-Reply-To-Topic

  7. Ahora, con estos comandos definidos, actualiza tu configuracion MyQttSatellite para mapear topics a tus comandos dentro de /etc/MyQttSatellite/conf/application.conf . Por ejemplo:
      
       command-mapper = [
          "company/customer/new" -> comando_de_alta_de_cliente.py "
          "company/customer/list/products" -> comando_de_listado_de_productos_de_cliente.py "
       ]
    

Con esta parte, ya estarían descritos los pilares que necesitas para gestionar mensajes recibidos desde la plataforma MQTT en tus nodos de red privada.

7. Probando la integración MQTT antes de modificar la parte pública

Ahora, antes de tocar tu plataforma web para comenzar a enviar mensajes MQTT, necesitas probar que todo funciona y es correcto.

Esta es una ventaja que nos proporciona MQTT. Nos permite probar la implementación enviando mensajes con el formato esperado para ver cómo responde el sistema.

Para ello, conecta a tu cuenta MyQttHub.com y usa la función de publicar mensaje que tienes en la parte superior del panel:

[11] Cómo publicar mensajes MQTT desde la interfaz Web MyQtthub.com

Probar la solución de esta manera te permitirá controlar y comprobar cómo funciona el conector cliente MQTT junto con los comandos que vayas implementando.

Una vez estés listo, ya podrías integrar la parte web online para que se subscriba y genere los mensajes necesarios para interacturar con el sistema remoto.

8. Consideraciones de seguridad para tu web al conectar con el servidor MQTT

Llegados este punto solo resta conectar tu plataforma web con la solución MQTT. Antes de realizar ningún cambio, algunas recomendaciones sobre seguridad:

Efectívamente, la clave para obtener una seguridad adecuda es evitar que sea un cliente javascript MQTT o HTTP (javascript XmlHttpRpc) quien genere los mensajes MQTT en el lado web del navegador del usuario.

Al contrario, las claves para obtener buenos niveles de seguridad son:

Con estas consideraciones de seguridad hechas, ya solo resta elegir el formato de integración. Tenemos dos posibilidades:

Por facilicidad de integración y debido a que hace uso de una tecnología ámpliamente disponble, optaremos por integrar con HTTPS y el API REST.

9. Conectando tu web al servidor MQTT

Las partes a completar son:

  1. Crea un dispositivo MQTT con el que publicar los mensajes. Nunca reuses credenciales usadas por otros dispositivos. Para ello, sigue las indicaciones en:

    [13] Cómo gestionar dispositivos MQTT con MyQttHub.com

  2. Da igual si usas interfaz MQTT o HTTP, usa siempre TLS/SSL. De lo contrario estarás enviando información sensible sin cifrar por internet.
  3. Dado que potencialmente generarás varias conexiones concurrentes a la plataforma, tendrás que activar el Skip Connection Replace. Mira cómo se hace en el siguiente artículo y la motivación:

    [14] Cómo configurar Skip Connection Replace

  4. Ahora, elige la sección en el código de tu web donde deseas emitir el mensaje. Si es un alta de cliente tendría que ser hecho al final del alta en la web. Ahí tendrás que realizar una conexión web, y publicar el mensaje.

Para ello, sigue las indicaciones del siguiente artículo que explica cómo realizar esta operación con Python. El ejemplo se puede adaptar fácilmente al lenguaje de programación que uses ya que estamos hablando de hacer consultas HTTPS:

[15] Usando el API REST de MyQttHub.com con python (httplib)

10. Almacenamiento ordenado de mensajes MQTT y soporte de reenvío

Con la solución desplegada, teniendo tu plataforma web conectanda a tu gestión interna vía interfaz MQTT, ya puedes pasar a hablar del almacenamiento ordenado de los mensajes intercambiados y del reenvío de mensajes.

Esta característica es fundamental para trazar qué pasó, cuándo y quién solicitó el cambio. También es necesaria para soportar situaciones de fallo durante el proceso de mensajes o la recepción de mensajes pendientes al no estar disponible.

Estas dos características (almacenamiento y reenvío) están fuertemente relacionadas pero se gestionan de manera independiente:

Efectívamente, con el primer soporte (el Reenvío MQTT) ya tenemos cubierto la capacidad de recibir los mensajes de alta y modificación de nuestra base de datos en el caso de que la conectividad en las sedes locales no esté disponible o haya problemas temporales con los servidores localizados en las mismas.

Además, los mensajes que reenvíe la plataforma se recibirán en orden: así aseguramos que los cambios que reciba la base de datos tendrán la misma cronología que cuando se produjeron.

Por otro lado, en el caso del Stashing, cada plataforma o Broker/MQTT lo configura de manera distinta. En el caso de MyQttHub.com sigue los siguientes pasos para crear un Stash y un filtro que ordene el almacenamiento de los mensajes que te interesan:

[2] Stashing MQTT para almacenamiento ordenado de los mensajes

Una vez creado el stashing tendrás todos los mensajes almacenados, en orden y con la capacidad para:

11. Conclusiones y revisión de la solución MQTT

Hemos presentado un escenario donde necesitábamos resolver el problema de interxión de una plataforma web online junto con un backend de almacenamiento (un sistema de gestión) de manera [3] desacoplada y segura.

La solución presentada, basada en MQTT, nos permite resolver la comunicación entre ambas sin conexión directa.

También nos resuelve el problema de no tener que almacenar información sensible en la web: podemos seguir almacenándola en nuestro sistema de gestión interno (backoffice) y dar "APIs MQTT" para proporcionar acceso "selectivo" a los datos necesarios.

La solución también nos proporciona un almacenamiento de todas las solicitudes de cambio lanzadas desde el portal online. Esto permite trazar en orden qué ocurrió o realizar el reenvío de ciertas operaciones.

La solución basa en MQTT también nos resuelve que los participantes (la web online y el backoffice privado) no tengan que estar presentes en el intercambio: el backoffice puede reconectar más tarde para procesar todos los mensajes que tenga pendiente (y en el orden en el que fueron enviados).

Durante este artículo hemos podido trabajar distintos aspectos del protocolo MQTT, la plataforma Cloud MQTT MyQttHub.com y las distintas características de dispositivos, reenvío y almacenamiento duradero (Stashing).

Referencias

  1. [1] https://mqtt.org : MQTT estándar abierto para la IoT.
  2. [2] https://support.asplhosting.com/t/gestionando-y-usando-el-stashing-de-myqtthub-almacenando-mensajes-mqtt-encajando-con-ciertos-filtros : Stashing MQTT, almacenamiento ordenado y duradero.
  3. [3] https://es.wikipedia.org/wiki/Acoplamiento_(inform%C3%A1tica) : Bajo acoplamiento (término informático)
  4. [4] https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern : Patrón PUBLISH-SUBSCRIBE para el intercambio de mensajes.
  5. [5] http://www.steves-internet-guide.com/mqtt-hosting-brokers-and-servers/
  6. [6] https://github.com/mqtt/mqtt.github.io/wiki/brokers
  7. [7] MyQttHub.com : Plataforma Cloud MQTT
  8. [8] https://support.asplhosting.com/t/como-crear-tu-cuenta-myqtthub-com-open
  9. [9] MyQttSatellite: cliente MQTT para mapear mensajes a comandos
  10. [10] Cómo generar respuestas MQTT con MyQttSatellite: uso de la cabecera X-Publish-Reply-To-Topic
  11. [11] Cómo publicar mensajes MQTT desde la interfaz Web MyQtthub.com
  12. [12] API REST HTTPS de MyQttHub.com
  13. [13] Cómo gestionar dispositivos MQTT con MyQttHub.com
  14. [14] Cómo configurar Skip Connection Replace
  15. [15] Usando el API REST de MyQttHub.com con python (httplib)
  16. [16] Descarga de mensajes MQTT almacenados en un Stash