Instalando un broker MQTT doméstico (III)

Instalando un broker MQTT doméstico (III)

Buenas, perdón por el retraso. Por fin he encontrado un hueco para poder continuar con esta serie. En el primer artículo explicaba que quería usar un thin client Fujitsu Futro S450 como broker MQTT permanente para mi entorno local. Además expliqué las actualizaciones que le hice al hardware para que pudiese correr un broker MQTT de forma más o menos holgada y por poco dinero. En el artículo anterior desgrané los pasos para el cambio de sistema operativo del thin client y procedí a la instalación de la primera versión del broker MQTT, que dejé funcionando con su configuración por defecto. En el presente artículo explicaré los pasos que hay que dar para que Mosquitto sirva MQTT sobre Secure Socket Layer/Transport Layer Security (SSL/TLS) de forma que la conexión de todos los clientes al broker sea segura y cifrada. Lo configuraré y dejaré funcionando de esta forma que es como lo necesito yo en mi casa. Realmente el 90% de este artículo no versa sobre la configuración de Mosquitto para usar SSL/TLS sino sobre todo lo que hay que hacer antes con certificados, autoridades de certificación, etcétera. Empecemos.

Infraestructura de clave pública “for dummies”

Veámoslo con un ejemplo. Desde hace años existe un timo en el cuál supuestos trabajadores de una empresa de distribución de gas va a tu casa a realizar “revisiones de la instalación” y cobran una barbaridad por ello. Estas personas se presentan con la indumentaria que utilizan los trabajadores de la empresa de gas e, incluso, muestran tarjetas identificativas para ser convincentes. Todo parece indicar que son trabajadores reales. ¿Cómo podemos estar seguros? Lo más razonable es llamar a la compañía de gas y preguntar si esas personas son quienes dicen ser y vienen realmente a realizar trabajos de mantenimiento de la instalación. A fin de cuentas, confiamos en que la compañía  de gas es quien dice ser (nos manda la factura todos los meses, tenemos el contrato firmado con ellos donde viene el teléfono…). ¡Si la empresa dice que son trabajadores suyos y vienen con fines lícitos, podemos confiar en ellos!

¡Que me perdonen los puristas! Grosso modo, en este ejemplo hemos visto lo muy, muy básico para entender una infraestructura de clave pública en el mundo de la informática y las telecomunicaciones. Existen dos actores que no se conocen y un tercero en el que se puede confiar y que puede actuar a modo de notario. Cuando un cliente MQTT (el propietario de la vienda) accede al broker Mosquitto (el supuesto trabajador de la compañía de gas), dicho cliente necesita contactar con una Autoridad de Certificación, CA, (la compañía de gas) para verificar que el broker Mosquitto es un broker lícito y no un impostor. Todo está mucho más automatizado que en el ejemplo. Mosquitto tendrá un certificado digital firmado por la CA y el clinte es capaz de verificar automáticamente que dicho certificado está firmado realmente por la CA. Si confiamos en la CA y la CA ha validado el certificado de Mosquitto, nuestro cliente MQTT podrá confiar en que está conectándose al Mosquitto esperado.

Además de la autenticación del Mosquitto, lo verdaderamente importante que ofrece TLS es el establecimiento de una comunicación cifrada entre el cliente MQTT y el Mosquitto una vez que ha quedado claro que el broker Mosquitto es quién dice ser. Y a partir de ahí la comunicación es segura entre ambos.

Los pasos, para llegar a este punto son, de forma simplificada, los siguientes:

  • El cliente MQTT solicita al broker Mosquitto el establecimiento de una conexión segura.
  • El broker Mosquitto envía su certificado digital X.509 al cliente MQTT. De forma muy resumida el certificado incluye una clave pública del Mosquitto, firmada por una CA de confianza y está asociado a el nombre de dominio y la dirección IP del servidor.
  • El cliente MQTT comprueba que el certificado del broker MQTT está realmente firmado por una CA en la que él, como cliente MQTT confía, en cuyo caso el broker MQTT será quien dice ser.
  • Si todo está OK, el cliente MQTT generará una clave simétrica (distinta para cada sesión) y la enviará al broker MQTT cifrada con la clave pública de éste (que se extrae del certificado X.509). Así, esta clave viajará segura hasta el broker MQTT puesto que sólo él sabe descifrar el mensaje.
  • Una vez el broker MQTT recibe y descifra la clave simétrica (distinta para cada sesión), tanto él como el cliente MQTT conocen la misma clave. Entonces pueden intercambiarse información con la seguridad de que ésta está cifrada y sólo ellos dos conocen la clave.

Para mi propio uso interno, que será el objetivo del Mosquitto en cuestión, no necesito una CA “oficial” en la que confiar. En su lugar crearé mi propia CA para que actúe de notario de cara a todos los servicios que lo requieran en mi red interna.

Generando los certificados necesarios

Crear la Autoridad de Certificación propia

Para casi todos los pasos de este post, utilizaremos OpenSSL, que debemos haber instalado en aquel lugar donde vayamos a ejecutarlo. Yo voy a crear CA, certificados y demás en el Ubuntu Server del thin client Futro, así que de entrada lo instalo allí.

sudo apt-get update
sudo apt-get install openssl

Ahora creamos un directorio que almacenará lo necesario para crear la autoridad de certificación:

mkdir CA
cd CA

Y usamos OpenSSL para crear la autoridad de certificación.

openssl req -newkey rsa:1024 -x509 -nodes -days 3650 -extensions v3_ca -keyout MiCA.key -out MiCA.crt -subj "/CN=Mi Casa /O=www.manolodominguez.com /emailAddress=ingeniero@manolodominguez.com"

Lo cual hará que OpenSSL utilice la entropía existente en el equipo en ese momento para generar una clave y un certificado X.509 para la CA. Yo he seleccionado de 1024 bits y que el certificado de la CA dure 10 años. No necesito más puesto que lo que realmente necesito es que haya soporte TLS para el proyecto que me traigo entre manos, más que que la clave sea muy grande. La salida por pantalla será algo así:

Generating a 1024 bit RSA private key
....++++++
...................++++++
writing new private key to 'MiCA.key'

Para asegurarnos, OpenSSL nos permite consultar los datos del certificado generado:

openssl x509 -in MiCA.crt -nameopt multiline -subject -noout

La salida, si todo ha funcionado bien, debería ser como se muestra a continuación:

subject=
commonName                = Mi Casa
organizationName          = www.manolodominguez.com
emailAddress              = ingeniero@manolodominguez.com

Y con esto habremos creado nuestra propia autoridad de certificación que yo, en mi caso, he llamado MiCA. Veremos que se utilizará a continuación cuando se genere un certificado de servidor para el broker Mosquitto.

Generando el certificado de servidor para el broker Mosquitto

Pasos para crear el certificado de servidor para el Mosquitto (simplificado)

El siguiente paso consiste en crear un certificado de servidor para el Mosquitto al que nos vamos a conectar, el que está instalado en el thin client, y que este certificado esté firmado con el certificado de la CA, que daré fe, de esta forma, de que el Mosquitto es quien dice ser (imprescindible que nosotros confiemos en la “palabra” de la CA).

Generamos la clave para el Mosquitto, con OpenSSL:

openssl genrsa -out MiMosquitto.key 1024

Del mismo modo que para la CA, OpenSSL usará la entropía del equipo donde se ejecuta y generará una clave. Yo elegí para esta clave 1024 bits también. Y un par de segundos después tenemos la salida.

Generating RSA private key, 1024 bit long modulus
 .............++++++
 .................++++++
 e is 65537 (0x10001)

Y a partir de esta clave vamos a realizar una petición a nuestra CA para que firme el certificado para el broker Mosquitto. Para ello generamos el fichero MiMOsquitto.csr que es una petición de firma de certificado que utilizaremos en el paso siguiente. Aquí introducimos los datos identificativos del servidor/broker y usamos la clave que acabamos de crear para él:

openssl req -new -out MiMosquitto.csr -key MiMosquitto.key -subj "/CN=Mosquitto en el Fujitsu Futro /O=www.manolodominguez.com /emailAddress=ingeniero@manolodominguez.com"

Generación y firma del certificado de servidor

En el caso de una CA comercial, ésta utilizaría el fichero *.csr para generar un certificado para el servidor (el Mosquitto). Como estamos utilizando una CA propia que hemos creado ad-hoc, pues lo haremos también nosotros. Para siguiente paso nos “pondremos la gorra” de la CA que recibe la petición de firma de certificado.

La CA aporta información adicional para la creación y firma del certificado para el servidor. Para ello hay que crear un fichero de extensiones donde se describen parámetros del certificado (y por las que una CA comercial nos cobraría) y que OpenSSL obliga a crear con una sintaxis determinada (más información en la web de OpenSSL). Crearemos un fichero extensiones.txt, como si fuésemos la CA, con el siguiente contenido:

[ MisExtensiones ]
basicConstraints        = critical,CA:false
keyUsage                = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid,issuer:always
subjectAltName          = IP:192.168.1.20
subjectAltName          = IP:127.0.0.1
subjectAltName          = DNS:localhost
subjectAltName          = DNS:futro-s450
certificatePolicies     = @polsection

[polsection]
policyIdentifier    = 1.3.5.8
CPS.1               = "http://localhost"
userNotice.1        = @notice

[notice]
explicitText        = "Estas extensiones son para los certificados de servidor de mi red local"
organization        = "www.ManoloDominguez.com"
noticeNumbers       = 1

Donde hay cosas que aparecen porque tienen que aparecer pero hay otros parámetros que son importantes. La web de OpenSSL explica claramente para qué vale cada parámetro. Lo más esencial es que aparezcan los parámetros subjectAltName para cada una de las direcciones IP a las que el Futro responderá y cada uno de los nombres de dominio que utilizará. En este caso como el Futro será un elemento en una LAN privada, usará IP y nombres de dominios privados. 192.168.1.20 es la IP del thin client, 127.0.0.1 es su IP de loopback y tanto localhost como futro-s450 resuelven en la red local a estas IPs. Si usamos estos datos y luego cambiamos la IP del thin client, el certificado dejará de ser válido y no se podrá establecer una conexión TLS con él.

Ahora, nuestra CA utilizará su certificado y clave privada (MiCA.crt y MyCA.key), la solicitud de firma de certificado recibida (Mosquitto.csr) y el fichero de extensiones (extensiones.txt) para generar y firmar el certificado para el broker.

openssl x509 -req -in MiMosquitto.csr -CA MiCA.crt -CAkey MiCA.key -CAcreateserial -CAserial MiCA.srl -out MiMosquitto.crt -days 3650 -extfile extensiones.txt -extensions MisExtensiones

La salida de este comando es algo así:

Signature ok
subject=/CN=Mosquitto en el Fujitsu Futro /O=www.manolodominguez.com /emailAddress=ingeniero@manolodominguez.com
Getting CA Private Key

Con lo cual ya tendremos generado un certificado de servidor apropiado para nuestro broker MQTT y estará firmado por una CA de confianza (nuestra MiCA).

Preparando Mosquitto para trabajar con TLS

Situando los certificados y claves en los lugares correspondientes

Todos los pasos de este artículo, hasta el momento, los hemos realizado en el directorio CA dentro del thin client donde está instalado el broker Mosquitto. Allí tendremos lo siguiente:

MiCA.crt -> Certificado de la CA (público).
MiCA.key -> Clave privada de la CA.
MiCA.srl -> Número de certificados creados por la CA. Por si generamos más.

MiMosquitto.crt -> Certificado de servidor para Mosquitto (público, firmado por la CA).
MiMosquitto.csr -> Petición de firma de certificado.
MiMosquitto.key -> Clave privada del Mosquitto.

Que deberemos mover a sus lugares correspondientes de donde Mosquitto los cargará según corresponda:

sudo cp MiCA.* /etc/mosquitto/certs/
sudo cp MiMosquitto.* /etc/mosquitto/certs/

Una vez en el directorio de destino, es buena idea proteger las claves privadas (los *.key) para que no puedan ser leídos por cualquiera.

Configurando Mosquitto

Con los certificados creados y situados en el lugar correspondiente, llega la hora de configurar Mosquitto para que haga uso de ellos y sirva conexiones TLS. Para ello editamos el correspondiente fichero de configuración:

sudo vi /etc/mosquitto/conf.d/tls.conf

Y ponemos este contenido:

listener 8883
tls_version tlsv1
cafile /etc/mosquitto/certs/MiCA.crt
certfile /etc/mosquitto/certs/MiMosquitto.crt
keyfile /etc/mosquitto/certs/MiMosquitto.key
require_certificate false

Esto indica a Mosquitto, por orden:

  1. En qué puerto escuchar para establecer conexiones TLS.
  2. La versión de TLS a utilizar.
  3. El certificado de la autoridad de certificación que firmó el certificado de servidor para el Mosquitto.
  4. El certificado de servidor del Mosquitto, firmado por la autoridad de certificación de la linea anterior.
  5. La clave privada del Mosquitto.
  6. Que no requiera a los clientes que se autentiquen con un certificado.

Hay muchos más parámetros de configuración en Mosquitto. Algunos (sólo algunos) de ellos los veremos en la última entrega de esta serie de artículos. De momento, reiniciamos el Mosquitto para que haga uso de la nueva configuración.

sudo /etc/init.d/mosquitto restart

Probando conexiones seguras hacia el Mosquitto

Lo primero será comprobar que Mosquitto está escuchando en los puertos adecuados, señal de que estará utilizando la nueva configuración que le hemos proporcionado y no la configuración por defecto:

netstat -ln --tcp

Nos debe salir esto:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:8883            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp6       0      0 :::8883                 :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN

 

Que significa que está asociado a todas las interfaces de red, tanto para IPv4 como para IPv6, escuchando en el puerto 8883 (el que especificamos en la configuración y que es el puerto utilizado para conexiones MQTT sobre TLS).

Y una vez que hemos hecho esta prueba, ya podemos probar a conectarnos vía TLS al Mosquitto. Esto lo haremos desde la misma red local, pero en remoto, no en el thin client. De los artículos anteriores ya tenemos instalado el cliente de Mosquitto (mosquitto_pub, para publicar en un topic y mosquitto_sub para suscribirse a un topic). Dos particularidades:

  1. Necesitaremos el certificado de la CA que haya firmado el certificado de servidor del Mosquitto; la que creamos nosotros ad-hoc, MiCA. Esto es así porque como no estamos usando una CA reconocida mundialmente, sin este fichero los clientes que intenten conectarse no tendrán forma de comprobar si el certificado de servidor es auténtico o no. Lo copiamos a la máquina desde la que vayamos a hacer la prueba.
  2. No estamos usando nombres de dominio o IPs públicas. Los clientes que usan TLS suelen comprobar que el nombre de dominio y la IP del servidor (el broker) al que nos conectamos son públicos y dados de alta en el DNS. Como no es el caso, hay que indicarlo con el parámetro –insecure en cada uno de los comandos. Así sólo comprueba que hay un certificado de servidor y que ese certificado de servidor está firmado por una CA en la que confiamos.

Ahora sí, vamos allá. Abrimos un terminal y nos suscribimos, vía TLS, al topic “UnTopicCualquiera” del broker MQTT (recordemos que tenía la IP 192.168.1.20).

mosquitto_sub --cafile MiCA.crt --tls-version tlsv1 --insecure -h 192.168.1.20 -p 8883 -t "UnTopicCualquiera" -v

Permanecerá a la “escucha”, esperando que alguien publique algo en ese topic. Ahora abrimos otro terminal, como si fuera otro cliente que está en otra máquina en el otro lado del mundo. Y publicamos algo, vía TLS, en el topic “UnTopicCualquiera” del broker.

mosquitto_pub --cafile MiCA.crt --tls-version tlsv1 --insecure -h 192.168.1.20 -p 8883 -t "UnTopicCualquiera" -m Hola

Tras ejecutar el comando, éste vuelve a la shell. Se supone que ha conectado con el broker vía TLS, ha publicado algo en el topic que hemos comentado y se ha desconectado.

Si volvemos al terminal del cliente que se había suscrito, vemos que le ha llegado el mensaje en cuanto el otro cliente ha publicado en el topic al que se había suscrito.

UnTopicCualquiera Hola

Así que, ya tenemos funcionando nuestro broker MQTT Mosquitto, en el thin client Fujitsu Futro S450, sirviendo conexiones sobre TLS. El 90% de lo que pretendíamos al inicio de esta serie.

Conclusiones y siguientes pasos

Entender a fondo OpenSSL no es algo trivial; ni seguramente bonito. Os pido disculpas porque este artículo ha quedado un poco denso, pero me parecía esencial entender aunque sea a de forma muy ligera los entresijos que hay por detrás. Pero crear una CA y un certificado de servidor es algo que se puede hacer sin demasiados problemas con sólo rastrear un poco por la red. El resto, configurar Mosquitto para que funcione con TLS es algo muy, muy sencillo una vez que se tienen los certificados adecuados. Y en pocos pasos y echándole sólo un rato, se puede tener un broker seguro bastante decente.

En el próximo artículo de esta serie, el último, abordaré la autenticación de usuarios y ACLs soportada por Mosquitto. Ya comenté en artículos anteriores que tengo un broker MQTT que todo esto lo soporta conectándolo a MySQL, pero para este caso concreto usaré los mecanismos básicos que proporciona MySQL.

Y… nada más. Como siempre, cualquier comentario será bienvenido.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

diecisiete + Trece =