Categories
Azure Internet of Things IoT Hub Microsoft

Azure IoT Hub deployment with ARM template and how to retrieve the primary connection string

In this article we will create an ARM template that will deploy an IoT Hub and output the primary connection string along with the Event Hub compatible connection string.

If you are building an IoT solution and need reliable and secure communications between your IoT devices and your cloud-hosted solution backend then you are probably looking at the following Azure product: Azure IoT Hub.

Today we will focus on creating an Azure Resource Manager template to easily setup and deploy an IoT Hub to a resource group. Our ARM template will be created in a new Azure Resource Group deployment project in Visual Studio.

 

Creation

Let’s declare the parameters of the ARM template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "iotHubName": {
      "type": "string",
      "defaultValue": "[concat('myIoTHub', uniqueString(resourceGroup().id))]"
    },
    "iotHubSkuName": {
      "type": "string",
      "defaultValue": "F1",
      "allowedValues": [
        "F1",
        "B1",
        "B2",
        "B3",
        "S1",
        "S2",
        "S3"
      ]
    },
    "iotHubSkuCapacity": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1
    },
    "iotHubMessageRetentionInDays": {
      "type": "int",
      "defaultValue": 1,
      "allowedValues": [ 1, 2, 3, 4, 5, 6, 7 ]
    },
    "iotHubPartitionCount": {
      "type": "int",
      "defaultValue": 2,
      "minValue": 2
    }
  }
  ...
}
  • iotHubName: the name of the IoT Hub. If no parameter is provided a default name such as myIoTHubesf732tk64rr6 is generated.
  • iotHubSkuName: the pricing tier of the IoT Hub. If no parameter is provided the pricing tier will be free.
  • iotHubSkuCapacity: the pricing tier and the capacity determine the maximum daily quota of messages that you can send. If no parameter is provided the capacity is set to 1.
  • iotHubMessageRetentionInDays: specifies how long the IoT hub will maintain device-to-cloud events.
  • iotHubPartitionCount: the number of partitions relates the device-to-cloud messages to the number of simultaneous readers of these messages. If no parameter is provided the number is set to 2.

 

Now we will declare the resources for the IoT Hub:

{
  ...
  "resources": [
    {
      "apiVersion": "2018-04-01",
      "name": "[parameters('iotHubName')]",
      "type": "Microsoft.Devices/IotHubs",
      "location": "[resourceGroup().location]",
      "sku": {
        "name": "[parameters('iotHubSkuName')]",
        "capacity": "[parameters('iotHubSkuCapacity')]"
      },
      "properties": {
        "eventHubEndpoints": {
          "events": {
            "retentionTimeInDays": "[parameters('iotHubMessageRetentionInDays')]",
            "partitionCount": "[parameters('iotHubPartitionCount')]"
          },
          "operationsMonitoringEvents": {
            "retentionTimeInDays": "[parameters('iotHubMessageRetentionInDays')]",
            "partitionCount": "[parameters('iotHubPartitionCount')]"
          }
        }
      }
    }
  ]
  ...
}

We can pay attention to several things here:

  • The hub is declared with the following type: Microsoft.Devices/IotHubs.
  • The sku is composed by the SkuName and SkuCapacity.

 

And to finish, we will output the connection string and the Event Hub compatible connection string of the IoT hub:

{
  ...
  "outputs": {
    "IoTHubConnectionString": {
      "type": "string",
      "value": "[concat('HostName=', reference(resourceId('Microsoft.Devices/IoTHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).hostName, ';SharedAccessKeyName=iothubowner;SharedAccessKey=', listKeys(resourceId('Microsoft.Devices/IotHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).value[0].primaryKey)]"
    },
    "IoTHubEventHubCompatibleConnectionString": {
      "type": "string",
      "value": "[concat('Endpoint=', reference(resourceId('Microsoft.Devices/IoTHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).eventHubEndpoints.events.endpoint, ';SharedAccessKeyName=iothubowner;SharedAccessKey=', listKeys(resourceId('Microsoft.Devices/IotHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).value[0].primaryKey, ';EntityPath=', reference(resourceId('Microsoft.Devices/IoTHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).eventHubEndpoints.events.path)]"
    }
  }
}

As you can notice, we take advantage of the ARM template function listKeys and the ARM template function providers.

The function providers is useful to get the latest API version for a specific namespace, whereas listkeys is the function that will allow us to get the properties for a specific key name.

By default when a new IoT hub is created, five access policies are created: iothubowner, service, device, registryRead and registryReadWrite. In our template we retrieve the primary connection string for the first one.

 

Example of use

The ARM template is now ready, let’s open a Windows PowerShell and try it:

.\Deploy-AzureResourceGroup.ps1 -ResourceGroupName 'MyResourceGroupName' -ResourceGroupLocation 'canadaeast' -TemplateFile '.\azuredeploy.json'

...

OutputsString      :
                     Name                                      Type                       Value
                     ===============                           =========================  ==========
                     ioTHubConnectionString                    String                     HostName=myIoTHubfkr54oehqy5pa.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=Vs38UdjTt5Wj1cV3Wji8e5bOx6nSsYJ/JA6ZrO6WOiA=
                     ioTHubEventHubCompatibleConnectionString  String                     Endpoint=sb://ihsuprodblres036dednamespace.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=Vs38UdjTt5Wj1cV3Wji8e5bOx6nSsYJ/JA6ZrO6WOiA=;EntityPath=iothub-ehub-myiothubfk-1163803-9a6e8b6b6c

If everything goes well, you should see the same kind of output as above.

 

To go further

In the template we are outputting the connection string as an example. But in a more advance scenario with Azure Functions you could directly set the Function App application setting that require the connection string like the following:

{
  ...
  "resources": [
    {
      "apiVersion": "2016-08-01",
      "name": "[parameters('functionAppName']",
      "type": "Microsoft.Web/sites",
      "location": "[resourceGroup().location]",
      "kind": "functionapp",
      "dependsOn": [
        ...
        "[concat('Microsoft.Devices/IoTHubs', parameters('iotHubName'))]"
      ],
      "properties": {
        "siteConfig": {
          "appSettings": [
            {
              "name": "IoTHubConnectionString",
              "value": "[concat('Endpoint=', reference(resourceId('Microsoft.Devices/IoTHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).eventHubEndpoints.events.endpoint, ';SharedAccessKeyName=iothubowner;SharedAccessKey=', listKeys(resourceId('Microsoft.Devices/IotHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).value[0].primaryKey, ';EntityPath=', reference(resourceId('Microsoft.Devices/IoTHubs', parameters('iotHubName')), providers('Microsoft.Devices', 'IoTHubs').apiVersions[0]).eventHubEndpoints.events.path)]"
            }
          ]
        }
      }
    }
  ]
  ...
}

 

Summary

We have seen how to create an ARM template that will deploy an Azure IoT Hub and output the connection string and the Event Hub compatible connection string.

 

You can get the project source code here:

Browse the GitHub repository

 

Please feel free to comment or contact me if you have any question about this article.