At the core of any Internet of Things (IoT) solution built with Microsoft Azure is the need to connect IoT devices to the cloud and send/retrieve event telemetry for those devices. When building an IoT solution using Azure IoT, the two primary services that you will use in almost every IoT solution are the Azure IoT Hub and Azure IoT Device Provisioning Service (DPS). Of course, you can easily create and manage these services from the Azure Portal, Azure CLi, and other tools, but you can also easily create and manage them using Terraform as well!

Let’s dig into how to do this!

Related: If you’re new to Terraform, or looking for a bit more information about it, then we recommend you check out our “Get Started with Terraform on Azure” article. This will give you a great jump start to both using Terraform for infrastructure automation, as well as some tips on using it with Microsoft Azure.



Create Azure IoT Hub

Azure IoT Hub is the highly scalable IoT messaging service to use for building IoT solutions in Microsoft Azure. This service provides a cloud-based message broker for connecting to, authenticating, and communicating with IoT devices. To get started with it, you need to create an instance of Azure IoT Hub within your Azure Subscription.

The Azure provider for Terraform exposes the azurerm_iothub resource type for managing Azure IoT Hub resource instances. At minimum, there are only a few property configurations to set for creating an Azure IoT Hub instance within your Azure Subscription.

  • name – The unique Name of the Azure IoT Hub resource instance in Azure.
  • resource_group_name – The name of the Azure Resource Group for which the IoT Hub resource will be organized within.
  • location – The Azure Region where the IoT Hub resource will be created.
  • sku – A sku block that defines the SKU (pricing tier) and capacity units of the IoT Hub.

Naming Requirements: The name of the Azure IoT Hub resource must meet the following requirements:

  • must be unique across all customers using Azure IoT Hub, as it’s used as part of the DNS name for the service endpoint.
  • must be between 3 and 50 characters long
  • can only be alphanumeric characters

Let’s take a look at some example Terraform using the azurerm provider to create / manage an instance of Azure IoT Hub:


# Create an Azure IoT Hub
resource "azurerm_iothub" "b59iothub" {
    name                = "b59iothub"

    # "azurerm_resource_group.b59" is an Azure Resource Group
    # defined elsewhere in the Terraform project
    resource_group_name = azurerm_resource_group.b59.name
    location            = azurerm_resource_group.b59.location

    # Define the Pricing Tier (SKU & Capacity)
    sku {
        name     = "S1"
        capacity = 1
    }
}

The sku block is used to specify the pricing tier and capacity units for the Azure IoT Hub. The sku.name defines the pricing tier, and the sku.capacity defines the number of provisioned Azure IoT Hub Units.

The possible value options for setting the Azure IoT Hub pricing tier using the sku.name property are as follows:

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)

The Azure IoT Hub Device Provisioning Service (DPS) provides a rich set of features for enabling zero-touch, just-in-time provisioning of devices with Azure IoT Hub. DPS can be used to provision millions of devices in a secure and scalable manner without requiring human intervention. Since DPS is a separate service, you will create Azure IoT Hub and DPS service instances as you build an Azure IoT solution.

The Azure provider for Terraform exposes the azurerm_iothub_dps resource type for managing Azure IoT Hub Device Provisioning Service (DPS) resource instances. At minimum, there are only a few property configurations to set for creating a DPS instance within your Azure Subscription.

  • name – The Name of the Azure IoT Hub DPS resource instance in Azure.
  • resource_group_name – The name of the Azure Resource Group for which the DPS resource will be organized within.
  • location – The Azure Region where the IoT Hub resource will be created.
  • sku – A sku block that defines the SKU (pricing tier) and capacity units of the IoT Hub.

Naming Requirements: The name of the Azure IoT Hub Device Provisioning Service (DPS) resource must meet the following requirements:

  • must be unique across all customers using Azure IoT Hub DPS, as it’s used as part of the DNS name for the service endpoint.
  • must be between 3 and 64 characters long
  • can only contain alphanumeric characters, or -
  • must not end with -

Let’s take a look at some example Terraform using the azurerm provider to create / manage an instance of Azure IoT Hub Device Provisioning Service (DPS):

# Create a Device Provisioning Service
resource "azurerm_iothub_dps" "b59dps" {
    name                = "b59dps"
    resource_group_name = azurerm_resource_group.b59.name
    location            = azurerm_resource_group.b59.location

    sku {
        name     = "S1"
        capacity = 1
    }
}

The sku block is used to specify the pricing tier and capacity units for the Azure IoT Hub Device Provisioning Service. The sku.name defines the pricing tier, and the sku.capacity defines the number of provisioned Azure IoT Hub Device Provisioning Service Units.

Currently, the Standard S1 SKU is the only option for the DPS service.

SKU Edition Tier
Standard S1

Also, currently, the only value used for the sku.capacity is 1.


Configure Azure IoT Hub DPS Linked Hub

When implementing Azure IoT Hub Device Provisioning Service (DPS), it needs to be linked to Azure IoT Hub for the service to be able to provision millions of devices with the service. This is done by configuring the Linked Hub of the DPS instance to connect it with the Azure IoT Hub service where the devices will be provisioned using DPS.

Before the DPS service can be linked to an Azure IoT Hub, there needs to be a Shared Access Policy on the Azure IoT Hub. This Connection String from this policy will be used to configure DPS to connect to the Azure IoT Hub with. You can create a new policy just for this, or you can use the iothubowner Shared Access Policy of the Azure IoT Hub that gets created by default when creating a new instance of the service.

To setup a reference for the existing iothubowner Shared Access Policy on the Azure IoT Hub, the azurerm_iothub_shared_access_policy resource type in Terraform can be used. A Terraform data reference can be defined to create a reference tot he existing policy. Alternatively, a Terraform resource could be used to create a new Shared Access Policy, if that is required for the IoT solution.

When defining a data reference of the azurerm_iothub_shared_access_policy resource type in Terraform, there are three properties that need to be set to target the desired, existing Shared Access Policy:

  • name – The Name of the Azure IoT Hub Shared Access Policy.
  • resource_group_name – The name of the Azure Resource Group for which the Azure IoT Hub resource is organized within.
  • iothub_name – The Name of the Azure IoT Hub that contains the Shared Access Policy.

Here’s an example of using Terraform and the azurerm_iothub_shared_access_policy resource type to create a data reference to the existing Shared Access Policy:

# Create an IoT Hub Access Policy
data "azurerm_iothub_shared_access_policy" "b59iothub_iothubowner" {
    name                = "iothubowner"
    resource_group_name = azurerm_resource_group.b59.name
    iothub_name         = azurerm_iothub.b59iothub.name
}

To configure the Linked Hub to connect an Azure IoT Hub to the Device Provisioning Service, a linked_hub block needs to be added to the existing azurerm_iothub_dps resource. There are two required properties of this block to be configured:

  • connection_string – The connection string to connect to Azure IoT Hub.
  • location – The Azure Region of the Azure IoT Hub.
# Create a Device Provisioning Service
resource "azurerm_iothub_dps" "b59dps" {
    name                = "b59dps"
    resource_group_name = azurerm_resource_group.b59.name
    location            = azurerm_resource_group.b59.location

    sku {
        name     = "S1"
        capacity = 1
    }

    linked_hub {
        connection_string = data.azurerm_iothub_shared_access_policy.b59iothub_iothubowner.primary_connection_string
        location = azurerm_iothub.b59iothub.location
    }
}

Using the above example of referencing the existing iothubowner Shared Access Policy of the IoT Hub, the linked_hub.connection_string will be set to either the primary_connection_string or secondary_connection_string of the data.azurerm_iothub_shared_access_policy that was defined in the Terraform code.

Related: There are times when declarative Infrastructure as Code (IaC) with Terraform doesn’t fit the need. For those occasions, the Azure CLI offers an amazing command-line experience. We recommend you check out the “Azure CLI: Manage Azure IoT Hub Device Provisioning Service (DPS)” article to learn how to do this from the command-line with the Azure CLI.


Full Code Example

Here’s a combined, complete Terraform code example for creating an Azure IoT Hub, a Device Provisioning Service, and linking them together:

provider "azurerm" {
  # AzureRM provider 2.x
  version = "~>2.0"
  # v2.x required "features" block
  features {}
}

# Create a resource group
resource "azurerm_resource_group" "b59" {
  name     = "b59-iot-rg"
  location = "North Central US"
}

# Create an Azure IoT Hub
resource "azurerm_iothub" "b59iothub" {
    name                = "b59iothub"
    resource_group_name = azurerm_resource_group.b59.name
    location            = azurerm_resource_group.b59.location

    sku {
        name     = "S1"
        capacity = 1
    }
}

# Create an IoT Hub Access Policy
data "azurerm_iothub_shared_access_policy" "b59iothub_iothubowner" {
    name                = "iothubowner"
    resource_group_name = azurerm_resource_group.b59.name
    iothub_name         = azurerm_iothub.b59iothub.name
}

# Create a Device Provisioning Service
resource "azurerm_iothub_dps" "b59dps" {
    name                = "b59dps"
    resource_group_name = azurerm_resource_group.b59.name
    location            = azurerm_resource_group.b59.location

    sku {
        name     = "S1"
        capacity = 1
    }

    linked_hub {
        connection_string = data.azurerm_iothub_shared_access_policy.b59iothub_iothubowner.primary_connection_string
        location = azurerm_iothub.b59iothub.location
    }
}

Keep in mind that there are unique name requirements for resources in Azure when running this Azure IoT Terraform code example. You will likely need to rename the resources, otherwise you will receive “resource with this name already exists” type of error messages when attempting to run this Terraform code as-is.

Happy automating the deployment and management of your Azure IoT Hub and DPS solution infrastructure using Terraform!


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.