IoT Hub DPS: Creando dispositivos bajo demanda

Tiempo de lectura: 8 minutos
Imagen ornamental para la entrada "IoT Hub DPS: Creando dispositivos bajo demanda"

¡Otra semana más! parece que fue ayer cuando estábamos de vacaciones todavía, pero nada más lejos de la realidad. Arrancan nuevos proyectos en mi trabajo y por suerte siempre estoy ahí moviéndome en lo que me gusta, Kubernetes y IoT.
Es por eso qué hoy toca seguir hablando de IoT en Azure 🙂

En la última entrada planteamos cómo crear módulos especializados para desplegar sobre un dispositivo IoT Edge y hoy toca hablar de otra situación muy habitual al hablar de IoT: cómo aprovisionar los dispositivos.

¿En qué consiste aprovisionar dispositivos?

Hasta ahora, siempre que hemos trabajado con IoT Hub, hemos creado individualmente cada dispositivo, sea de IoT Hub o de IoT Edge, y hemos recuperado su cadena de conexión.

Existe otro modo en el que podemos registrar esos diferentes dispositivos que consiste en utilizar un servicio de Azure llamado Azure IoT Hub Device Provisioning Service (DPS). Este servicio nos va a permitir asociar diferentes IoT Hub, sobre los cuales se van a crear los dispositivos de manera automática.

Este gráfico (sacado de la documentación oficial) describe muy claramente cuál es el flujo que sigue IoT Hub DPS para crear un dispositivo nuevo:

1- El fabricante del dispositivo agrega la información de registro del dispositivo a la lista de inscripción en Azure Portal.
2- El dispositivo contacta con el punto de conexión de DPS configurado de fábrica. 
3- DPS valida la identidad del dispositivo.
4- DPS registra el dispositivo con un IoT Hub.
5- El centro de IoT devuelve la información del identificador de dispositivo a DPS.
6- DPS devuelve la información de conexión del centro de IoT al dispositivo. El dispositivo ya puede empezar a enviar datos directamente a la instancia de IoT Hub.
7- El dispositivo se conecta a IoT Hub.
8- Obtiene el estado deseado del dispositivo gemelo en la instancia de IoT Hub.
  1. El fabricante del dispositivo agrega la información de registro del dispositivo a la lista de inscripción en Azure Portal.
  2. El dispositivo contacta con el punto de conexión de DPS configurado de fábrica. 
  3. DPS valida la identidad del dispositivo.
  4. DPS registra el dispositivo con un IoT Hub.
  5. El centro de IoT devuelve la información del identificador de dispositivo a DPS.
  6. DPS devuelve la información de conexión del centro de IoT al dispositivo. El dispositivo ya puede empezar a enviar datos directamente a la instancia de IoT Hub.
  7. El dispositivo se conecta a IoT Hub.
  8. Obtiene el estado deseado del dispositivo gemelo en la instancia de IoT Hub.

¿Por qué aprovisionar dispositivos con IoT Hub DPS?

Crear manualmente los dispositivos está bien siempre que el número de dispositivos que queremos registrar no sea excesivamente grande, o siempre que cada dispositivo que creamos físicamente tenga algún proceso de fabricación individual.

Por ejemplo, si cada dispositivo es arrancado por un técnico para hacer algún proceso propio de la fabricación, no es descabellado que durante ese proceso se cree el dispositivo y se registre.

En cambio, imagina un escenario en el que no existe ese proceso manual y se fabrican en serie cientos de dispositivos iguales, que pueden ir a parar a cualquier lugar del mundo y caer en cualquier mano. En caso de estar en un escenario como el que acabo de describir, seguramente nos interese tener diferentes IoT Hub distintos desplegados en diferentes regiones y que los dispositivos se creen y conecten en el Hub más cercano pare reducir la latencia (geolocalización). Eso en el caso más exigente, pero otro caso quizás más común es aquél donde el usuario final no tiene los conocimientos o interés en configurar el dispositivo.

En este tipo de escenarios masivos en los que no hay intervención humana especializada durante el proceso de fabricación, es vital tener un sistema de aprovisionamiento automático.

Creando nuestro IoT Hub DPS

Doy por hecho que si estas leyendo esto, es porque conoces IoT Hub y como crearlo, por lo que voy a partir del punto en el que conoces como crear un IoT Hub y como funciona, así como en que consiste IoT Edge. En caso de que no sea así, te dejo unas entradas sobre el tema:

Aunque existen varias maneras de crear un IoT Hub DPS, a fin de simplificar al máximo vamos a utilizar Az Cli con su extension ‘iot‘.

Lo primero va a ser crear el servicio, para ello, basta con ejecutar:

 az iot dps create --name $dpsName --resource-group $rg --location $region

Esto nos va a devolver entre otras cosas, dos datos que necesitamos guardar para utilizar más adelante (aunque también los podemos recuperar más adelante desde Az Cli o desde el portal). Estos datos son ‘idScope‘ y ‘serviceOperationsHostName‘ y los vamos a necesitar cuando estemos configurando los dispositivos para auto aprovisionarse con IoT Hub DPS.

Lo siguiente que vamos a hacer una vez que se ha creado el servicio, es asociarlo con las instancias de IoT Hub donde queremos que sea posible aprovisionar dispositivos. Para esto vamos a necesitar tener una cadena de conexión con permisos de administración sobre cada uno de los IoT Hub que queremos conectar. Podemos conseguirla desde el portal o simplemente ejecutando:

$hubConnectionString=$(az iot hub show-connection-string --name $iotHubName --key primary --query connectionString -o tsv)

Y una vez que la tengamos, asociamos IoT Hub DPS con la instancia de IoT Hub ejecutando:

az iot dps linked-hub create --dps-name $dpsName --resource-group $rg --connection-string $hubConnectionString --location $region

Adicionalmente, podemos añadir el parámetro ‘–allocation-weight‘, que no es más que un valor de prioridad que podemos utilizar en el siguiente paso para decidir en que IoT Hub se van aprovisionar los dispositivos en caso de que exista más de uno asociado a la instancia de IoT Hub DPS.

Manejando las inscripciones

Vamos a pasar revista de lo que tenemos hasta el momento:

  • Tenemos un IoT Hub o varios.
  • Tenemos un IoT Hub DPS junto a su idScope y serviceOperationsHostName.
  • Hemos asociado nuestro/s IoT Hub con el DPS.

Ya casi estamos listos para poder empezar a utilizar nuestro IoT Hub DPS, solo nos falta registrar dentro del propio servicio el método por el que vamos a identificar a los dispositivos. Para esto tenemos 2 modelos:

  • Registrar dispositivos individualmente.
  • Crear grupos de registro.

Estos dos modelos nos van a permitir gestionar como queremos que se inscriban los diferentes dispositivos. Llegados a este punto, puede parecer un poco absurdo el hecho de registrar dispositivos individualmente, ¿no? Pues la verdad es que tiene todo el sentido del mundo ya que el hecho de utilizar IoT Hub DPS para un dispositivo individual nos garantiza que en caso de que borremos el dispositivo de IoT Hub por cualquier razón, se volverá a crear automáticamente sin necesidad de interacción humana. Por ejemplo, puede darse el caso de que una instancia de IoT Hub este sobrecargada y no la podamos escalar por ‘x’ razón, gracias a este aprovisionamiento individual, podríamos cambiar dispositivos concretos de un Hub a otro con un mínimo esfuerzo.
Por su parte en cambio, la inscripción de grupos nos va a permitir registrar múltiples dispositivos con un mismo sistema.

Independientemente del sistema de inscripción que elijamos, vamos a tener 2 mecanismos para que un dispositivo se identifique ante IoT Hub DPS y un tercero en caso de dispositivos individuales:

  • X.509
  • Clave Simétrica
  • TPM (dispositivos individuales)

Teniendo en cuenta estos dos tipos de registros y sus diferentes modos de identificación, vamos a crear una inscripción de grupo a modo de ejemplo (aunque una individual sería prácticamente igual). Para este proceso, vamos a necesitar tomar algunas decisiones: ¿Qué criterio vamos a usar para elegir el IoT Hub? Las opciones disponibles son:

  • Latencia mínima.
  • Peso de los IoT Hub.
  • Siempre al mismo.
  • Utilizar una Azure Function.

¿Qué instancias de IoT Hub queremos que sean elegibles para registrar el dispositivo? ¿Qué propiedades y/o tags queremos que tengan automáticamente los dispositivos? Estas últimas por ejemplo son muy útiles cuando queremos que un deployment de módulos se aplique directamente a los dispositivos IoT Edge.

En este caso para probar, vamos a crear dos grupos de inscripción, uno que sirva para dispositivos IoT Edge y añada el tag {"IoTEdge" : "FixedBuffer"} y otro que sirva para IoT Hub y tenga el tag {"IoTHub" : "FixedBuffer"}.

Para eso, vamos a ejecutar:

# Grupo para IoT Edge
az iot dps enrollment-group create -g $rg --dps-name $dpsName --enrollment-id "IoTEdge" --primary-key $primaryKey --secondary-key $secondayKey --initial-twin-tags "{'IoTEdge' : 'FixedBuffer'}" --edge-enabled=true
# Grupo para IoT Hub
az iot dps enrollment-group create -g $rg --dps-name $dpsName --enrollment-id "IoTHub" --primary-key $primaryKey --secondary-key $secondayKey --initial-twin-tags "{'IoTHub' : 'FixedBuffer'}" --edge-enabled=false
# Verificamos que se han creado
az iot dps enrollment-group list --dps-name $dpsName --resource-group $rg

Probando IoT Hub DPS

Con esto que hemos hecho ya estamos preparados para poder empezar a aprovisionar nuestros dispositivos. Bueno, en realidad no del todo… He elegido aprovisionar grupos ya que tiene un paso más respecto a aprovisionar dispositivos individuales.

No es una buena idea el distribuir de manera masiva una clave que permite registrar tantos dispositivos quieras de manera automática. Es por esto que IoT Hub DPS trabaja con una clave derivada cuando se trata de inscripción de grupos. Esta clave derivada se puede calcular utilizando HMACSHA256, para lo cual la propia documentación nos ofrece un código de ejemplo.

Probar el aprovisionamiento de un dispositivo IoT Hub es muy sencillo ya que basta con que nos bajemos el repositorio de ejemplos de IoT, y ejecutemos el ejemplo ‘ProvisioningDeviceSamples‘ seleccionando el proyecto de inicio en ‘SymmetricKeySample‘. El propio fichero Program.cs nos guía mediante comentarios sobre que tenemos que rellenar y donde para poder validar el funcionamiento.

En mi caso, una vez ejecutado se ha registrado un dispositivo llamado ‘sample-iot-hub’, al que al consultar sus tags con az iot hub device-identity list --ee false -n $iotHubName --query="[*].tags" me devuelve esto:

{
  "IoTHub": "FixedBuffer"
}

De igual modo, vamos a probar que se registra correctamente si el dispositivo es de tipo Edge. Esto requiere que configuremos su fichero config.yaml y le indiquemos los datos que necesita para poder conectarse (que son los mismos que en el caso anterior). Para poder probar que todo esto funciona de manera más sencilla, he creado una imagen Docker que a la que indicándole las variables de entorno ‘SCOPE_ID‘ y ‘SYMMETRIC_KEY‘, va a registrar un dispositivo IoT Edge con el nombre del contenedor utilizando IoT Hub DPS. No es una imagen 100% funcional, pero para la prueba que vamos a hacer nosotros es suficiente. Puedes ver el código de la imagen en GitHub si tienes interés 🙂

docker run --privileged=true -e SCOPE_ID=$SCOPE_ID -e SYMMETRIC_KEY=$primaryKey jorturfer/iot-edge-dps-post

Una vez se ejecute y se conecte, puedo comprobar que se ha aprovisionado correctamente ejecutando az iot hub device-identity list --ee true -n $iotHubName --query="[*].tags", que esta vez me devolverá:

{
  "IoTEdge": "FixedBuffer"
}

Conclusión

Una vez más, me dejo muchas cosas chulas en el tintero, pero la verdad es que si las revisásemos todas en detalle, ni yo mismo leería mi entrada por el tamaño final…

Hemos hecho una pequeña aproximación al aprovisionamiento de dispositivos utilizando IoT Hub DPS ya que es una herramienta que personalmente me parece muy potente y útil. Respecto a su coste hay que decir también que, aunque sí tiene coste, es ridículo a cambio del trabajo que ahorra, nada más y nada menos que €0,085 por cada 1.000 operaciones.

En futuras entradas, me gustaría unificar todos y cada uno de estos conceptos que hemos ido planteando tanto aquí como en las entradas que escribí para Plain Concepts en una entrada con una ejemplo funcional E2E. ¿Qué opinas? ¿Crees que sería interesante? ¿Conocías previamente IoT Hub Device Provisioning Service?

Deja un comentario