All Azure IoT solutions are built starting with Azure IoT Hub as the cloud-base message broker for the Internet of Things (IoT) solution. This service connects all IoT devices in the solution securely to Azure using per-device security and two-way communication with the devices. Another service used to more easily provision many IoT devices in an Azure IoT solution at scale is the Azure IoT Hub Device Provisioning Service (DPS). This service allows you to automate the provisioning of IoT devices as they connect to Azure IoT Hub at scale (think thousands or even millions of devices!)

Provisioning the Azure IoT Hub and DPS services in Azure can be done using a few different tools. This can be done using the Azure Portal, Azure CLI, PowerShell, or even ARM Templates. With the addition of Azure Bicep to more easily write declarative Azure Resource Manager (ARM) code, you can write Bicep code to create and manage the Azure IoT Hub and DPS services!

Let’s dig into how to do this!

Related: If you’re new to automating Azure resources using Azure Bicep, then we recommend you check out the “Get Started with Azure Bicep – Alternative to ARM Templates” article written by Chris Pietschmann. This will give you a great jump start to using Azure Bicep to manage Azure resource deployments.



Create Azure IoT Hub using Azure Bicep

Azure IoT Hub provides a highly scalable Internet of Things (IoT) message broker in the Azure cloud. The IoT devices that are part of the overall IoT solution connect to and communicate with Azure IoT Hub in the cloud. The IoT Hub securely connects to the devices individually, and provide 2-way communications to both gather device telemetry and send command and control commands to the devices.

Before we get started, let’s create a location variable that we can use to define the Azure Region (aka location) for Azure IoT Hub. Then we can use this variable later to define the Azure Region to use for the Azure IoT Hub DPS service too. With this variable, we can use the resourceGroup().location expression, just like would be used in an Azure ARM Template, to use the same location as the default location of the Azure Resource Group being used to organize the resources within.

// Set variable to default location for the Resource Group deployed to
var location = resourceGroup().location

To provision an Azure IoT Hub resource using Azure Bicep, the IotHubs resource type within the Microsoft.Devices Azure Resource Provider will be used. There are also a couple different Azure Resource Provider API versions that could be used for the Microsoft.Devices/IotHubs resource type. The below code example uses the 2020-04-01 API version; which is the most current version at the time of writing this.

Below is an example definition of an Azure IoT Hub resource in Azure Bicep assigning the name of b59iothub to the Azure IoT Hub resource being managed. Keep in mind the name of the Azure IoT Hub resource must be unique and between 3 and 50 characters long.

resource b59iothub 'Microsoft.Devices/IotHubs@2020-04-01' = {
  name: 'b59iothub'
  location: location
  sku: {
      name: 'F1'
      capacity: 1
  }
}

In the above, the sku block is defining the pricing tier name and capacity to use when provisioning the Azure IoT Hub resource. The capacity defines the number of provisioning IoT Hub Units for the service.

There are a number of options to choose from for the sku.name property of the Azure IoT Hub resource to define the pricing tier:

SKU Edition Tier Msgs/Day per IoT Hub Unit
Basic B1 400,000
B2 6,000,000
B3 300,000,000
Free (Standard) F1 8,000
Standard S1 400,000
S2 6,000,000
S3 300,000,000

Note: The Free (F1) pricing tier is a special type of Standard tier meant for DEV / TEST purposes, and is limited to only a single Free tier IoT Hub per Azure Subscription. The Free tier has a limit of 8,000 messages per day, and the ability to register up to 500 device identities. This device identity limit only applies to the Free tier.

Azure IoT Hub Units are the method used to scale the chosen SKU to handle a higher number of messages per day. At minimum, the sku.capacity for Azure IoT Hub will need to be set to 1 unit. To handle higher scalability, a higher number of units for the chosen SKU can be configured

The Standard S1, S2, and Basic B1, B2 SKU’s have a limit of up to 200 IoT Hub Units. Also. the Standard S3 and Basic B3 have a limit of up to 10 IoT Hub Units. If you require to move above these limits, then you will need to contact Microsoft support for assistance.

Related: If you’re looking for more about Azure IoT services, architecture, and how everything fits together, then we recommend you check out our “Introduction to Azure IoT for Administrators” article. This will give you a great jump start on the “what” and “why” of Microsoft Azure IoT solutions.

Create Azure IoT Hub Device Provisioning Service (DPS) using Azure Bicep

The Azure IoT Hub Device Provisioning Service (DPS) is a helper service for managing provisioning IoT devices withe Azure IoT Hub at scale. It provides zero-touch, just-in-time provisioning of IoT devices with Azure IoT Hub in an automated fashion without the need for human interaction

Azure IoT Hub can be used by itself using a manual process or even programatic automation of provisioning IoT devices in the Azure IoT Hub Device Registry. By adding the Device Provisioning Service (DPS) the IoT solution will have an automated way to provision IoT devices in Azure IoT Hub Device Registry in a manner than can much more easily scale to thousands or millions of IoT devices.

To provision Azure IoT Hub Device Provisioning Service (DPS) with Azure Bicep, the provisioningServices resource type within the Microsoft.Devices Resource Provider will be used. There are also a couple different Azure Resource Provider API versions that could be used for the Microsoft.Devices/provisioningServices resource type. The below code example uses the 2020-01-01 API version; which is the most current version at the time of writing this.

Below is an example definition of an Azure IoT Hub Device Provisioning Service (DPS) resource in Azure Bicep assigning the name of b59iotdps to the IoT Hub DPS resource. Keep in mind the name of the Azure IoT Hub resource must be unique and between 3 and 64 characters long.

resource b59iotdps 'Microsoft.Devices/provisioningServices@2020-01-01' = {
    name: 'b59iotdps'
    location: location
    sku: {
        name: 'S1'
        capacity: 1
    }
}

In the above, the sku block is defining the pricing tier with the name property and the scale capacity for the DPS service. At the time of writing, the Standard S1 value for sku.name is the only option for the DPS service. Also, 1 is the only supported value for the sku.capacity.

SKU Edition Tier
Standard S1

Configure Azure IoT Hub DPS Linked Hub using Azure Bicep

When provisioning the Azure IoT Hub Device Provisioning Service (DPS) to use for provisioning IoT devices with the Azure IoT Hub Device Registry, the DPS and IoT Hub services must be linked. This is done by configuring the Linked Hub fo the DPS instance to connect to the Azure IoT Hub where IoT devices will be provisioned.

Connecting the IoT Hub DPS service to Azure IoT Hub requires configuring DPS with the Connection String using a shared access key from Azure IoT Hub. The DPS service will then use this shared access key to connect to and manage the device registry for the IoT Hub. The default “iothubowner” shared access key on the Azure IoT Hub can be used, or a new key could be created if necessary on the Azure IoT Hub service.

Below is an example of Azure Bicep code to configure the IoT Hub DPS service with the necessary information to setup the Linked Hub:

resource b59iotdps 'Microsoft.Devices/provisioningServices@2020-01-01' = {
    name: 'b59iotdps'
    location: location
    sku: {
        name: 'S1'
        capacity: 1
    }

    properties: {
        iotHubs: [
            {
                connectionString: 'HostName=${b59iothub.name}.azure-devices.net;SharedAccessKeyName=${listKeys(b59iothub.id, '2020-04-01').value[0].keyName};SharedAccessKey=${listKeys(b59iothub.id, '2020-04-01').value[0].primaryKey}'
                location: location
            }
        ]
    }
}

In the above, the properties.iotHubs array is assigned an object value that contains the connectionString and location for the Azure IoT Hub to link to the DPS service. In this example, there is are a couple Azure Bicep expressions used to retrieve the shared access key for Azure IoT Hub and build a valid connection string using string interpolation.

The Azure IoT Hub connection string is built using the following format:

HostName=<iot-hub-name>.azure-devices.net;SharedAccessKeyName=<key-name>;SharedAccessKey=<key-value>

The retrieval of the <iot-hub-name> in the connection string is done by referencing the .name property of the Azure IoT Hub resource within the Azure Bicep code. This allows you to reference the name of the Azure IoT Hub service that’s provisioned in Azure without hard coding it within the expression here.

The retrieval of the shared access key name and key value is performed by using Azure Bicep expressions that utilize the listKeys ARM function (just as would be done in an ARM JSON Template) to reference the shared access keys of the Azure IoT Hub resource provisioned in Azure. This is done since the key is not known at provisioning time until the Azure IoT Hub resource is created within Microsoft Azure.

Here’s the individual Azure Bicep expressions for retrieving the shared access key name and value:

${listKeys(b59iothub.id, '2020-04-01').value[0].keyName}
${listKeys(b59iothub.id, '2020-04-01').value[0].primaryKey}

The ARM listKeys function accepts two arguments; the Azure resource id and api version. The Azure resource id for the Azure IoT Hub is referenced with the .id property of the Azure Bicep resource; similar to how the name is referenced previously. This allows the Bicep code to easily reference the Azure resource Id for the resource without needing to hard code and / or manually build out the full resource value.

The result of the listKeys function returns back an object with a value array property containing the shared access keys for the Azure IoT Hub service. The value at index zero (0) by default will be the iothubowner shared access key on the Azure IoT Hub service. Then, the keyName and primaryKey properties of the shared access key are the name and key values required to built out the full Azure IoT Hub connection string needed.

Related: If for some reason you need to use the Azure CLI to provision and manage Azure IoT Hub Device Provisioning Service (DPS) resources, then you may find the “Azure CLI: Manage Azure IoT Hub Device Provisioning Service (DPS)” article written by Chris Pietschmann to be helpful as well.

Full Code Example

Here’s a complete Azure Bicep code example for creating an Azure IoT Hub, a DPS service, and linking them together:

// Set variable to default location for the Resource Group deployed to
var location = resourceGroup().location


resource b59iothub 'Microsoft.Devices/IotHubs@2020-04-01' = {
  name: 'b59iothub'
  location: location
  sku: {
      name: 'F1'
      capacity: 1
  }
}


resource b59iotdps 'Microsoft.Devices/provisioningServices@2020-01-01' = {
    name: 'b59iotdps'
    location: location
    sku: {
        name: 'S1'
        capacity: 1
    }

    properties: {
        iotHubs: [
            {
                connectionString: 'HostName=${b59iothub.name}.azure-devices.net;SharedAccessKeyName=${listKeys(b59iothub.id, '2020-04-01').value[0].keyName};SharedAccessKey=${listKeys(b59iothub.id, '2020-04-01').value[0].primaryKey}'
                location: location
            }
        ]
    }
}

When using the above code, keep in mind the uniqueness and other naming requirements of the Azure IoT Hub and DPS services. Azure Bicep may not return errors in these requirements automatically. You will need to name the resources as needed for your organization and solution. If the unique names already exist within Azure, then you will see a “resource with this name already exists” type of error message when attempting to deploy the resulting ARM Template after compiling the Azure Bicep code.

Happy managing the deployment and connection of Azure IoT Hub and Device Provisioning Service (DPS) for use in building out Internet of Things (IoT) solutions in Microsoft Azure using Azure Bicep!


Microsoft MVP

Chris is the Founder of Build5Nines.com and a Microsoft MVP in Azure & IoT with 20 years of experience designing and building Cloud & Enterprise systems. He is also a Microsoft Certified: Azure Solutions Architect, developer, Microsoft Certified Trainer (MCT), and Cloud Advocate. He has a passion for technology and sharing what he learns with others to help enable them to learn faster and be more productive.