Seguridad MQTT

Certificado autofirmado para MQTT: cuándo y cómo usarlo

Un tutorial práctico para crear una autoridad de certificación privada con OpenSSL, proteger un broker Mosquitto de laboratorio en el puerto 8883 y conectar clientes, además de los costes operativos que hacen más cómodos los certificados públicos en producción.

Ilustración de un certificado autofirmado para MQTT con una autoridad de certificación privada que firma el certificado de un broker en una red de laboratorio
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Un certificado autofirmado para MQTT te permite cifrar un broker de laboratorio o sin conexión a internet sin una autoridad de certificación pública. Si se hace de forma ingenua, o falla la verificación en todos los clientes o tienta a desactivar la verificación por completo. Este tutorial muestra el patrón correcto, una pequeña CA privada creada con OpenSSL; después configura Mosquitto en el puerto 8883, conecta clientes Python y de línea de comandos y explica cuándo un certificado de confianza pública te ahorra el esfuerzo.

Certificado autofirmado frente a CA privada

La expresión "certificado autofirmado" se usa para dos configuraciones distintas:

  • Un único certificado de servidor autofirmado: el certificado del broker se firma a sí mismo. Los clientes deben confiar en ese certificado exacto. Cuando caduca o cambia, hay que actualizar todos los clientes.
  • Una CA privada: creas tu propio certificado de CA raíz (autofirmado) y lo usas para firmar el certificado del broker. Los clientes confían en la CA, así que puedes reemitir libremente el certificado del broker mientras la CA no cambie.

El enfoque de CA privada es el que quieres casi siempre. Cuesta dos comandos de OpenSSL más y te evita redistribuir la confianza cada vez que cambia el certificado del servidor.

Cuándo tiene sentido un certificado autofirmado para MQTT

Escenario Autofirmado / CA privada Certificado de confianza pública
Pruebas en portátil o laboratorio Encaja bien Posible pero innecesario
Red de fábrica aislada, sin DNS público A menudo la única opción No es posible sin DNS público
Broker interno al que se accede por IP o con un nombre .local Viable Las CA públicas no emiten para estos nombres
Broker expuesto a internet para dispositivos y aplicaciones Evitar Muy preferible
Dashboards en navegador sobre WSS Engorroso (avisos del navegador) Funciona sin más
Clientes de terceros que no controlas Engorroso (deben instalar tu CA) Funciona sin más

Paso 1: crea la CA privada

Crea un directorio de trabajo y una clave y un certificado de CA. Protege ca.key: quien la tenga puede suplantar a tu broker.

mkdir -p ~/mqtt-ca && cd ~/mqtt-ca

openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
  -subj "/O=Example Lab/CN=Example Lab MQTT CA" -out ca.crt

Paso 2: crea el certificado del broker con un SAN

Los clientes TLS modernos ignoran el common name del certificado al comprobar el hostname y solo miran el Subject Alternative Name (SAN). Omitir el SAN es la razón más habitual por la que una configuración MQTT autofirmada falla la verificación. Incluye todos los nombres y direcciones IP que usarán los clientes.

openssl genrsa -out broker.key 2048
openssl req -new -key broker.key \
  -subj "/O=Example Lab/CN=mqtt.lab.local" -out broker.csr

cat > broker.ext <<'EOF'
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:mqtt.lab.local, DNS:localhost, IP:192.168.1.50
EOF

openssl x509 -req -in broker.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 397 -sha256 -extfile broker.ext -out broker.crt

Comprueba el resultado antes de usarlo:

openssl x509 -in broker.crt -noout -subject -issuer -dates -ext subjectAltName
openssl verify -CAfile ca.crt broker.crt

El segundo comando debería imprimir broker.crt: OK. Sustituye los nombres y la dirección IP por los tuyos.

Paso 3: configura Mosquitto para TLS

Copia los archivos al broker y crea una configuración de listener:

sudo mkdir -p /etc/mosquitto/certs
sudo cp ca.crt broker.crt broker.key /etc/mosquitto/certs/
sudo chown mosquitto: /etc/mosquitto/certs/broker.key
sudo chmod 600 /etc/mosquitto/certs/broker.key
# /etc/mosquitto/conf.d/tls.conf
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key

# Exige también credenciales MQTT
allow_anonymous false
password_file /etc/mosquitto/passwd

Crea un usuario con sudo mosquitto_passwd -c /etc/mosquitto/passwd labuser, reinicia con sudo systemctl restart mosquitto y revisa journalctl -u mosquitto en busca de errores como archivos de clave ilegibles.

Paso 4: conecta los clientes

Cada cliente necesita ca.crt, nunca la clave de la CA. Con las herramientas de mosquitto:

mosquitto_sub -h mqtt.lab.local -p 8883 --cafile ca.crt \
  -u labuser -P 'your-password' -i lab-sub-1 -t "lab/#" -v

mosquitto_pub -h mqtt.lab.local -p 8883 --cafile ca.crt \
  -u labuser -P 'your-password' -i lab-pub-1 -t "lab/test" -m "hello private CA"

En Python con paho-mqtt 2.x:

import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="lab-python-1")
client.tls_set(ca_certs="ca.crt")          # confía solo en la CA privada
client.username_pw_set("labuser", "your-password")
client.connect("mqtt.lab.local", 8883)
client.loop_start()
client.publish("lab/test", "verified against private CA", qos=1).wait_for_publish()
client.loop_stop()
client.disconnect()

En Node.js, pasa ca: fs.readFileSync("ca.crt") en las opciones de MQTT.js. En un ESP32, incrusta el contenido de ca.crt y llama a setCACert(). Observa que la verificación sigue totalmente activada en todos los ejemplos: el cliente simplemente confía en tu CA en lugar de en una pública. Si te encuentras con errores de verificación, nuestra guía de SSL CERTIFICATE_VERIFY_FAILED en MQTT enumera las causas habituales.

Confiar en la CA privada en todo el sistema

Pasar --cafile a cada herramienta resulta tedioso en las máquinas del laboratorio. En una estación de trabajo Linux puedes añadir la CA al almacén del sistema operativo para que las herramientas que lo usan, como mosquitto_sub --capath /etc/ssl/certs, curl y la mayoría de los runtimes de lenguajes, confíen automáticamente en el broker del laboratorio:

# Debian / Ubuntu / Raspberry Pi OS
sudo cp ca.crt /usr/local/share/ca-certificates/example-lab-mqtt-ca.crt
sudo update-ca-certificates

En Windows, importa ca.crt en el almacén "Entidades de certificación raíz de confianza" con certutil -addstore -f Root ca.crt desde un símbolo del sistema con privilegios de administrador; en macOS, añádelo al llavero del Sistema y márcalo como de confianza. Hazlo de forma consciente. Todo lo firmado por la CA de tu laboratorio pasa a ser de confianza para esa máquina con cualquier fin, no solo MQTT, así que protege la clave de la CA en consecuencia y elimina la CA de las máquinas que salgan del laboratorio. Ten en cuenta que los clientes Python basados en certifi y Node.js ignoran el almacén del sistema operativo salvo que se configuren de otro modo, así que siguen necesitando el archivo de la CA.

Trampas que debes evitar

  1. SAN ausente: la verificación del hostname falla aunque la cadena sea válida.
  2. Distribuir el archivo equivocado: los clientes necesitan ca.crt, no broker.crt, y nunca ca.key.
  3. Desactivar la verificación: --insecure, tls_insecure_set(True) o rejectUnauthorized: false hacen inútil el certificado.
  4. Olvidar la caducidad: anota en un calendario la fecha de caducidad del certificado del broker y automatiza la renovación si puedes. Un certificado caducado desconecta a todos los clientes a la vez.
  5. Validez excesiva del certificado del servidor: los certificados de larga duración son cómodos, pero aumentan el impacto de una clave filtrada. Mantén la CA de larga duración y el certificado del broker más corto.
  6. Clave de la CA en el broker: guarda la clave de la CA offline. El broker solo necesita su propia clave y su certificado.
  7. Problemas de reloj: los dispositivos sin una hora precisa rechazan certificados válidos.

La misma CA privada también puede firmar certificados de cliente si quieres TLS mutuo; consulta mTLS en MQTT con certificados de cliente X.509.

Renovar el certificado del broker

Como la CA privada no cambia, la renovación solo afecta al broker. Genera una clave nueva (o reutiliza la anterior si tu política lo permite), crea una nueva CSR, fírmala con la misma CA y el mismo archivo broker.ext y sustituye los archivos en el broker:

openssl genrsa -out broker-new.key 2048
openssl req -new -key broker-new.key -subj "/O=Example Lab/CN=mqtt.lab.local" -out broker-new.csr
openssl x509 -req -in broker-new.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 397 -sha256 -extfile broker.ext -out broker-new.crt

sudo cp broker-new.crt /etc/mosquitto/certs/broker.crt
sudo cp broker-new.key /etc/mosquitto/certs/broker.key
sudo systemctl restart mosquitto

Los clientes no cambian, porque confían en ca.crt y no en el certificado del broker. Esta es la recompensa del patrón de CA privada frente a un certificado autofirmado aislado, en el que cada cliente necesitaría el archivo nuevo. Merece la pena añadir una sencilla tarea cron que te avise un mes antes de la caducidad:

openssl x509 -checkend 2592000 -noout -in /etc/mosquitto/certs/broker.crt \
  || echo "MQTT broker certificate expires within 30 days"

El coste operativo del que nadie habla

Una CA privada es fácil el primer día. El coste aparece después: distribuir ca.crt a cada cliente nuevo, explicar los avisos del navegador cuando alguien abre un dashboard por WSS, renovar el certificado del broker antes de que caduque, sustituir la propia CA tras una década o tras el compromiso de una clave y documentarlo todo para el siguiente ingeniero. En un sistema expuesto a internet, ese esfuerzo no aporta nada que un certificado de confianza pública no ofrezca ya.

Esa es la razón principal para usar un broker MQTT gestionado en producción. ConnectMQ presenta un certificado de Let's Encrypt en el que ya confían los sistemas operativos, los navegadores, Python y Node.js, y lo renueva automáticamente. Los clientes se conectan al puerto 8883 o a WebSocket seguro en el 8084 sin archivos de CA que distribuir, salvo incrustar una raíz pública estándar en los microcontroladores. Puedes confirmarlo en segundos en el servidor MQTT público gratuito, pensado solo para pruebas y prototipos, nunca para datos de producción:

mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -i pubca-test-3e8b -t "connectmq/demo/3e8b/#" -v

Para comparar modelos de alojamiento, lee nuestra guía de broker MQTT en la nube, y para la lista completa de pasos de refuerzo consulta configuración TLS en MQTT.

Empieza con ConnectMQ

Olvídate de la CA privada para tu broker de producción. Regístrate en ConnectMQ en app.connectmq.com, elige el plan gratuito Serverless sin tarjeta de crédito, crea un broker y conéctate por el puerto 8883 con el usuario, la contraseña y el client ID generados. ConnectMQ se encarga de los certificados y las renovaciones; reserva tu configuración autofirmada para el laboratorio, que es donde debe estar.

Preguntas frecuentes

¿Puedo usar un certificado autofirmado en MQTT en producción?

Puedes en redes cerradas en las que controlas todos los clientes, siempre que operes una CA privada como es debido y gestiones las renovaciones. En brokers expuestos a internet, un certificado de confianza pública es más sencillo y evita distribuir la confianza a cada cliente.

¿Por qué mi cliente rechaza el certificado incluso con el archivo de la CA?

La razón más habitual es un Subject Alternative Name ausente o incorrecto. Compruébalo con openssl x509 -noout -ext subjectAltName -in broker.crt y asegúrate de que incluye el hostname que usan los clientes.

¿Puedo obtener un certificado de Let's Encrypt para un broker interno?

Solo para un nombre de dominio público que controles, usando validación por DNS. Las CA públicas no emiten certificados para direcciones IP privadas ni para nombres .local.

¿Tengo que reiniciar Mosquitto después de renovar el certificado?

Mosquitto carga los certificados al arrancar, así que planifica un reinicio o una recarga tras la renovación y prueba después con openssl s_client.

Artículos relacionados

Cómo rotar credenciales MQTT sin tiempo de inactividad

Una estrategia de doble credencial paso a paso para rotar usuarios y contraseñas MQTT en toda una flota: prepara la nueva credencial, cambia con respaldo, verifica y solo entonces revoca la antigua.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.