Tutorial: TLS, autenticación de cliente X.509 y autorización de control de acceso basado en atributos (ABAC) con el corredor MQTT de Operaciones de IoT de Azure
Este tutorial le guía para configurar el corredor MQTT de Operaciones de IoT de Azure con cifrado TLS y autenticación de cliente X.509. Incluye instrucciones paso a paso y scripts para crear certificados tanto para el corredor como para los clientes. El tutorial explica cómo configurar el corredor MQTT con diferentes autoridades de certificación raíz (CA) para el cliente y el corredor. También trata la configuración de una directiva de autorización de control de acceso basado en atributos (ABAC) basada en la cadena de certificados de cliente. Por último, el tutorial usa el cliente de Mosquito para probar varios escenarios para asegurarse de que la configuración funciona correctamente.
El tutorial simula un entorno en el que Operaciones de IoT de Azure está instalado en una fábrica de Contoso, con dispositivos fabricados por Fabrikam. Para que la autenticación TLS y X.509 funcionen:
- El corredor MQTT de Operaciones de IoT de Azure, instalado en una fábrica de Contoso, debe confiar en la CA raíz de Fabrikam
- Los sensores de Fabrikam, como los termostatos, deben confiar en la CA raíz de Contoso
- Cada entidad debe tener su propio certificado de hoja emitido por la CA raíz correcta
Requisitos previos
Para utilizar este tutorial, necesitará:
- Un clúster de Kubernetes con reenvío de puertos habilitado para el puerto 8883.
- Operaciones de IoT de Azure implementado sin un cliente de escucha de equilibrador de carga existente.
- Acceso de Kubectl al clúster para crear secretos de Kubernetes y asignaciones de configuración.
- Cliente de Mosquitto para publicar y suscribirse a mensajes de MQTT que se ejecutan en la misma máquina que el clúster de Kubernetes para el acceso de
localhost
. Para no usarlocalhost
, consulte la sección Opcional: Usar un nombre de host real o una dirección IP en lugar delocalhost
. - CLI de step para crear certificados.
Sugerencia
Para cumplir estos requisitos, use el codespace de inicio rápido. El codespace de inicio rápido simplifica el proceso de configuración proporcionando estos componentes de forma predeterminada.
Además, es útil estar familiarizado con la criptografía de clave pública y con términos como CA raíz, clave privada y certificados intermedios.
Opcional: use un nombre de host real o una dirección IP en lugar de localhost
Para simplificar este tutorial, usamos localhost
para acceder al corredor MQTT. Este enfoque garantiza que el certificado de servidor del corredor tenga un nombre alternativo del firmante (SAN) que coincida con el nombre de host usado para acceder al corredor. El uso de localhost
simplifica la configuración, ya que la SAN ya está configurada correctamente.
En un escenario real, usaría el nombre de host o la IP externa del corredor en lugar de localhost
y se conectaría a él desde otro dispositivo de la red. En este caso, debe determinar el nombre de host o la dirección IP correctos y usarlos como SAN al crear el certificado de servidor:
- Si el nombre de host o la dirección IP ya se conocen (por ejemplo, a través de un registro DNS o una dirección IP estática), úselos como SAN al crear el certificado de servidor. A continuación, conéctese al corredor mediante ese nombre de host o IP en lugar de
localhost
. - Si aún no se conoce el nombre de host o la dirección IP, puede usar un servicio de marcador de posición para determinar la dirección IP externa:
- Cree el servicio de LoadBalancer en un puerto que no se esté usando (como 8080):
kubectl create service loadbalancer placeholder-service --tcp=8080:8080
- Recupere la dirección IP externa:
kubectl get svc placeholder-service
- Si la dirección IP externa:
- Muestra un valor como
192.168.X.X
: use esa dirección IP como SAN al crear el certificado de servidor y el secreto. A continuación, conéctese al corredor mediante esa dirección IP en lugar delocalhost
. - Muestra
<pending>
: es posible que la distribución de Kubernetes que use no admita la asignación automática de una dirección IP externa. Para buscar la dirección IP externa, siga los pasos descritos en la documentación de Kubernetes para el entorno de distribución y host. También es posible que tenga que configurar enrutamiento de puerto o una VPN en función de la configuración de red.
- Muestra un valor como
- Después de determinar la dirección IP externa, elimine el servicio de marcador de posición:
kubectl delete svc placeholder-service
- Cree el servicio de LoadBalancer en un puerto que no se esté usando (como 8080):
Este método garantiza que el certificado de servidor coincida con la dirección IP externa, lo que permite el acceso seguro al corredor MQTT.
Preparación de certificados del lado servidor y cadena completa
En primer lugar, cree una CA raíz en el servidor. Esta CA es independiente de la CA raíz del lado del cliente que se crea más tarde. Para mantener la separación clara, denominamos todo el lado servidor "Contoso". Para facilitar los pasos posteriores, omitimos la contraseña para cifrar la clave privada. Esta práctica solo es aceptable en una configuración del tutorial.
step certificate create "Contoso Root CA" \
contoso_root_ca.crt contoso_root_ca.key \
--profile root-ca \
--no-password --insecure
A continuación, cree una CA intermedia firmada por esta CA raíz.
step certificate create "Contoso Intermediate CA 1" \
contoso_intermediate_ca.crt contoso_intermediate_ca.key \
--profile intermediate-ca \
--ca ./contoso_root_ca.crt --ca-key ./contoso_root_ca.key \
--no-password --insecure
Por último, use esta CA intermedia para firmar un certificado de servidor para el front-end del corredor MQTT. Aquí, localhost
es el nombre alternativo del firmante (SAN) que se usa para el tutorial.
step certificate create mqtts-endpoint \
mqtts-endpoint.crt mqtts-endpoint.key \
--profile leaf \
--ca ./contoso_intermediate_ca.crt --ca-key ./contoso_intermediate_ca.key \
--bundle \
--san localhost \
--not-after 2400h --no-password --insecure
Con la marca --bundle
, el certificado de servidor se agrupa con el certificado intermedio de firma. El protocolo de enlace TLS requiere que la agrupación compruebe la cadena completa.
Preparación de certificados del lado cliente y cadena completa
Del mismo modo, cree la CA raíz para Fabrikam y la CA intermedia.
step certificate create --profile root-ca "Fabrikam Root CA" \
fabrikam_root_ca.crt fabrikam_root_ca.key \
--no-password --insecure
step certificate create "Fabrikam Intermediate CA 1" \
fabrikam_intermediate_ca.crt fabrikam_intermediate_ca.key \
--profile intermediate-ca \
--ca ./fabrikam_root_ca.crt --ca-key ./fabrikam_root_ca.key \
--no-password --insecure
A continuación, genere certificados de cliente para un termostato, hidrómetro, calentador y bombilla.
# Create a client certificate for the thermostat
step certificate create thermostat thermostat.crt thermostat.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the hygrometer
step certificate create hygrometer hygrometer.crt hygrometer.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the heater
step certificate create heater heater.crt heater.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the lightbulb
step certificate create lightbulb lightbulb.crt lightbulb.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
Configuración de Kubernetes
Importe el certificado de servidor recién generado y la clave privada en un secreto de Kubernetes. Este secreto se usa para configurar un cliente de escucha TLS para el corredor MQTT más adelante.
kubectl create secret tls broker-server-cert -n azure-iot-operations \
--cert mqtts-endpoint.crt \
--key mqtts-endpoint.key
Además, cree una asignación de configuración para que contenga la CA raíz de Fabrikam (lado cliente). Esta asignación de configuración es necesaria para que el corredor MQTT confíe en él para la autenticación X.509.
kubectl create configmap fabrikam-ca -n azure-iot-operations \
--from-file=client_ca.pem=fabrikam_root_ca.crt
Configuración del corredor MQTT
Los pasos siguientes configuran el corredor MQTT con el cifrado TLS y la autenticación de cliente X.509. En el tutorial se usa Azure Portal para configurar el corredor MQTT.
Autenticación
Para permitir que los clientes se autentiquen mediante certificados X.509 emitidos por la CA raíz de Fabrikam, cree una directiva de autenticación que confíe en el certificado de CA raíz de Fabrikam y asigne los certificados de cliente a atributos de autorización para ABAC.
En Azure Portal, vaya a su instancia de IoT Hub.
En Componentes, seleccione MQTT Broker.
Seleccione la pestaña Autenticación.
Seleccione Crear directiva de autenticación.
En Nombre de directiva, escriba
x509-auth
.Para agregar un nuevo método, seleccione Agregar método.
Elija el tipo de método X.509 en la lista desplegable y seleccione Agregar detalles para configurar el método.
En el panel Detalles de autenticación X.509, especifique el nombre de ConfigMap
fabrikam-ca
del certificado de CA de confianza de Fabrikam y los atributos.{ "trustedClientCaCert": "fabrikam-ca", "authorizationAttributes": { "thermostat": { "subject": "CN = thermostat", "attributes": { "group": "thermostat_group" } }, "hygrometer": { "subject": "CN = hygrometer", "attributes": { "group": "hygrometer_group" } }, "intermediate": { "subject": "CN = Fabrikam Intermediate CA 1", "attributes": { "manufacturer": "fabrikam" } } } }
Seleccione Aplicar y, después, Agregar para guardar los cambios.
Agente de escucha
Con la directiva de autenticación vigente, cree un cliente de escucha que use la directiva de autenticación X.509. Además, dado que la autenticación X.509 requiere TLS, configure el cliente de escucha para que use el certificado de servidor de Contoso y la clave privada creadas anteriormente.
En Azure Portal, vaya a su instancia de IoT Hub.
En Componentes, seleccione MQTT Broker.
Seleccione cliente de escucha de corredor MQTT para LoadBalancer>Crear. Escriba la siguiente configuración:
Configuración Descripción Nombre Escriba mqtts-endpoint
.Nombre del servicio Nombre del servicio Kubernetes. Déjelo vacío para usar el nombre del cliente de escucha mqtts-endpoint
como nombre del servicio.Tipo de servicio. LoadBalancer ya seleccionado. En Puertos, escriba la siguiente configuración para el primer puerto:
Configuración Descripción Port Escriba 8883 Autenticación Elija x509-auth Autorización Elija Ninguno. Protocolo Elegir MQTT TLS Seleccione Agregar. En el panel configuración de TLS , escriba los valores siguientes:
Configuración Descripción Modo TLS Elija manual Nombre del emisor Escriba broker-server-cert
.Seleccione Aplicar y Crear cliente de escucha.
Después de un minuto o dos, se crea el servicio de LoadBalancer de mqtts-endpoint
.
$ kubectl get service mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.43.28.140 XXX.XX.X.X 8883:30988/TCP 104s
En lugar de usar la dirección IP externa, se usa localhost
para el tutorial.
Sugerencia
La configuración de codespace configura automáticamente el enrutamiento de puertos para 8883. Para configurar otros entornos, consulte Uso del enrutamiento de puertos.
Uso de un único cliente de Mosquito para publicar mensajes a través de TLS
Desde la misma carpeta que los archivos de certificados: contoso_root_ca.crt
, thermostat.crt
y thermostat.key
, use el cliente de Mosquito para publicar un mensaje. La marca --cafile contoso_root_ca.crt
es para que Mosquito realice la comprobación del certificado de servidor.
mosquitto_pub -t "example/topic" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
La publicación se realiza correctamente porque Mosquito usa un certificado de cliente que se basa en fabrikam_root_ca.crt
. El agente MQTT confía en este certificado por la directiva de autenticación x509-auth
creada anteriormente. Además, el corredor MQTT permite actualmente a los clientes autenticados publicar en cualquier tema.
Client thermostat sending CONNECT
Client thermostat received CONNACK (0)
Client thermostat sending PUBLISH (d0, q1, r0, m1, 'example/topic', ... (31 bytes))
Client thermostat received PUBACK (Mid: 1, RC:0)
Client thermostat sending DISCONNECT
Configuración de la autorización en temas devMQTT para varios clientes mediante X.509
Para restringir el acceso a temas MQTT basados en los atributos de certificado de cliente, cree una directiva de autorización que asigne los atributos de certificado de cliente a las acciones permitidas en temas específicos.
En Azure Portal, vaya a su instancia de IoT Hub.
En Componentes, seleccione MQTT Broker.
Seleccione la pestaña Authorization (Autorización).
Seleccione Crear directiva de autorización.
En Nombre de directiva, escriba
abac-authz
.En Reglas, escriba las siguientes reglas:
[ { "principals": { "attributes": [ { "group": "thermostat_group" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "telemetry/temperature" ] } ] }, { "principals": { "attributes": [ { "group": "hygrometer_group" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "telemetry/humidity" ] } ] }, { "principals": { "attributes": [ { "manufacturer": "fabrikam" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "health/heartbeat" ] } ] }, { "principals": { "usernames": [ "heater" ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Subscribe", "topics": [ "telemetry/temperature", "telemetry/humidity" ] } ] } ]
Seleccione Agregar para guardar los cambios.
A continuación, actualice el cliente de escucha del corredor MQTT para usar la nueva directiva de autorización.
- Seleccione la pestaña Clientes de escucha.
- Seleccione el agente de escucha mqtts-endpoint.
- En Puertos>8883>Autorización, elija abac-authz.
- Seleccione Guardar.
Publicación de mensajes en un tema restringido
En esta sección, se prueban las directivas de autorización recién aplicadas.
En primer lugar, conéctese con thermostat
e intente publicar en el tema telemetry/humidity
:
mosquitto_pub -t "telemetry/humidity" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
Como thermostat
forma parte de thermostat_group
, que no puede publicar en el tema de la humedad, la publicación falla.
Client thermostat sending CONNECT
Client thermostat received CONNACK (0)
Client thermostat sending PUBLISH (d0, q1, r0, m1, 'telemetry/humidity', ... (6 bytes))
Client thermostat received PUBACK (Mid: 1, RC:135)
Warning: Publish 1 failed: Not authorized.
Cambie la publicación a telemetry/temperature
, lo que está permitido y la publicación tiene éxito. Deje el comando en ejecución.
mosquitto_pub -t "telemetry/temperature" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--repeat 10000 \
--repeat-delay 3 \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
Suscribirse a mensajes en temas restringidos
En una sesión de terminal independiente, conéctese con heater
para suscribirse a health/heartbeat
.
mosquitto_sub -q 1 -t "health/heartbeat" -d -V mqttv5 \
-i heater \
-h localhost \
--key heater.key \
--cert heater.crt \
--cafile contoso_root_ca.crt
Puesto que heater
no está autorizado para suscribirse al tema de latido, se produce un error en la suscripción. Aquí, el código 135 significa que no está autorizado.
Client heater sending CONNECT
Client heater received CONNACK (0)
Client heater sending SUBSCRIBE (Mid: 1, Topic: health/heartbeat, QoS: 1, Options: 0x00)
Client heater received SUBACK
Subscribed (mid: 1): 135
Cambie el tema de suscripción a telemetry/temperature
, al que thermostat
todavía está enviando mensajes.
mosquitto_sub -q 1 -t "telemetry/temperature" -d -V mqttv5 \
-i heater \
-h localhost \
--key heater.key \
--cert heater.crt \
--cafile contoso_root_ca.crt
Ahora heater
comienza a recibir mensajes porque está autorizado con su nombre de usuario.
En otra sesión de terminal independiente, publique mensajes en health/heartbeat
con lightbulb
:
mosquitto_pub -q 1 -t "health/heartbeat" -m "example heartbeat" -d -V mqttv5 \
-i lightbulb \
-h localhost \
--repeat 100 \
--repeat-delay 3 \
--key lightbulb.key \
--cert lightbulb.crt \
--cafile contoso_root_ca.crt
La publicación se realiza correctamente porque lightbulb
tiene un certificado intermedio con CN = Fabrikam Intermediate CA 1
, que se asigna al atributo manufacturer=fabrikam
. Los clientes con ese atributo pueden publicar en health/heartbeat
. Cuando el cliente comienza a enviar mensajes, heater
iniciado anteriormente no recibe nada.
Limpieza de recursos
Para limpiar los recursos creados en este tutorial, elimine el cliente de escucha y las directivas de autenticación y autorización.
- En Azure Portal, vaya a su instancia de IoT Hub.
- En Componentes, seleccione MQTT Broker.
- Seleccione la pestaña Clientes de escucha.
- Seleccione la casilla situada junto al cliente de escucha mqtts-endpoint.
- Seleccione Eliminar.
- Confirme la eliminación.
- Seleccione la pestaña Autenticación.
- Active la casilla situada junto a x509-auth.
- Seleccione Eliminar.
- Confirme la eliminación.
- Seleccione la pestaña Authorization (Autorización).
- Active la casilla situada junto a abac-authz.
- Seleccione Eliminar.
- Confirme la eliminación.
Elimine también el secreto de Kubernetes y la asignación de configuración.
kubectl delete secret broker-server-cert -n azure-iot-operations
kubectl delete configmap fabrikam-ca -n azure-iot-operations
Por último, elimine los certificados y las claves generados anteriormente.
rm contoso_root_ca.crt contoso_root_ca.key contoso_intermediate_ca.crt contoso_intermediate_ca.key mqtts-endpoint.crt mqtts-endpoint.key
rm fabrikam_root_ca.crt fabrikam_root_ca.key fabrikam_intermediate_ca.crt fabrikam_intermediate_ca.key thermostat.crt thermostat.key hygrometer.crt hygrometer.key heater.crt heater.key lightbulb.crt lightbulb.key