Compartir a través de


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

Diagrama que muestra la relación de confianza de las raíces de la CA del lado cliente y del servidor.

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 usar localhost, consulte la sección Opcional: Usar un nombre de host real o una dirección IP en lugar de localhost.
  • 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:
    1. Cree el servicio de LoadBalancer en un puerto que no se esté usando (como 8080):
      kubectl create service loadbalancer placeholder-service --tcp=8080:8080
      
    2. Recupere la dirección IP externa:
      kubectl get svc placeholder-service
      
    3. 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 de localhost.
      • 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.
    4. Después de determinar la dirección IP externa, elimine el servicio de marcador de posición:
      kubectl delete svc placeholder-service
      

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.

  1. En Azure Portal, vaya a su instancia de IoT Hub.

  2. En Componentes, seleccione MQTT Broker.

  3. Seleccione la pestaña Autenticación.

  4. Seleccione Crear directiva de autenticación.

  5. En Nombre de directiva, escriba x509-auth.

  6. Para agregar un nuevo método, seleccione Agregar método.

  7. Elija el tipo de método X.509 en la lista desplegable y seleccione Agregar detalles para configurar el método.

  8. 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"
          }
        }
      }
    }
    
  9. Seleccione Aplicar y, después, Agregar para guardar los cambios.

Recorte de pantalla que muestra cómo usar Azure Portal para crear el método de autenticación X.509 del corredor MQTT.

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.

  1. En Azure Portal, vaya a su instancia de IoT Hub.

  2. En Componentes, seleccione MQTT Broker.

  3. 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.
  4. 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.
  5. 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.
  6. Seleccione Aplicar y Crear cliente de escucha.

Recorte de pantalla que muestra el método de Azure Portal para establecer un cliente de escucha con puerto TLS.

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.

  1. En Azure Portal, vaya a su instancia de IoT Hub.

  2. En Componentes, seleccione MQTT Broker.

  3. Seleccione la pestaña Authorization (Autorización).

  4. Seleccione Crear directiva de autorización.

  5. En Nombre de directiva, escriba abac-authz.

  6. 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"
            ]
          }
        ]
      }
    ]
    
  7. Seleccione Agregar para guardar los cambios.

Recorte de pantalla que muestra Azure Portal para configurar una directiva de autorización.

A continuación, actualice el cliente de escucha del corredor MQTT para usar la nueva directiva de autorización.

  1. Seleccione la pestaña Clientes de escucha.
  2. Seleccione el agente de escucha mqtts-endpoint.
  3. En Puertos>8883>Autorización, elija abac-authz.
  4. Seleccione Guardar.

Recorte de pantalla que muestra el uso de Azure Portal para migrar un vínculo a una directiva de autorización.

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.

  1. En Azure Portal, vaya a su instancia de IoT Hub.
  2. En Componentes, seleccione MQTT Broker.
  3. Seleccione la pestaña Clientes de escucha.
  4. Seleccione la casilla situada junto al cliente de escucha mqtts-endpoint.
  5. Seleccione Eliminar.
  6. Confirme la eliminación.
  7. Seleccione la pestaña Autenticación.
  8. Active la casilla situada junto a x509-auth.
  9. Seleccione Eliminar.
  10. Confirme la eliminación.
  11. Seleccione la pestaña Authorization (Autorización).
  12. Active la casilla situada junto a abac-authz.
  13. Seleccione Eliminar.
  14. 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