Registering Devices With IoT Hub Device Provisioning Service

Introduction

 
In this article we'll learn about the capabilities that Microsoft Azure provides to help us get our devices connected to the cloud. We'll start things off by looking at the device provisioning process at a high level. We'll learn about the roles involved, as well as the steps that need to be performed. We'll move on to looking at the solution Microsoft Azure provides for dealing with device provisioning challenges, Azure IoT Hub Device Provisioning Service. We'll learn about the core capabilities that this service provides, and see how these capabilities can help us streamline our device provisioning process. In order for a device to connect to our hub, our device needs some way to uniquely, securely identify itself. We'll look at the various methods that the Device Provisioning Service supports. Finally, we'll work together to create, configure, and use an instance of the Device Provisioning Service using a virtual device application that I've already created for you. Let's get started.
 
Road Map
  1. Azure IoT hub device provisioning system setup
  2. Configuring Azure IoT Hub DPS
  3. Creating an individual enrollment
  4. Auto provisioning a device
Pre requisites
 
An existing Azure IoT Hub service in the same resource group as our Device Provisioning Service. You can find the method of creating an IoT hub here.
 

Azure IoT Hub DPS Setup

 
I'm going to start by going to the Azure portal to create a new instance of the device provisioning service. Let's start by going to our resource group and let's add a new resource. We want to add a device provisioning service. Let's quickly create and now we can configure our service.
 
Registering Devices With IoT Hub Device Provisioning Service
 
Click on create and you will be directed to the service creation screen. Enter all the relevant information for the service. Make sure the resource group is the same as that of our IoT Hub Click. Click on create.
 
Registering Devices With IoT Hub Device Provisioning Service
 

Configuring Azure IoT Hub DPS

 
Now that we have our service, we need to tell it about which IoT hub or hubs we wanted to use. We just finished creating our device provisioning service. If you don't see it on your dashboard, you can get to it by going to your resource groups and drilling into the resource group that contains our service. Now what we need to do is link it to the IoT that we have that we already created. We can do that by going to (Our DPS ) > Linked IoT Hubs.
 
Registering Devices With IoT Hub Device Provisioning Service
 
After that click the add button and then we can choose our existing hub.
 
Registering Devices With IoT Hub Device Provisioning Service
 
I do want to point out that we can actually link any hub from our subscription or any subscription we have access to you. It doesn't even have to be in the same region we chose for our device provisioning service. We also need to choose an access policy. We could define a custom policy, but the built in IoT owner policy will work just fine. Our IoT device provisioning service and our hub are now linked. That means it's time to enroll a device.
 

Creating an Individual Enrollment

 
Now that we have a hub, and we have an instance of the Device Provisioning Service, that means we're ready to enroll a device. We are going to enroll a device manually. In a real solution, we would either enroll a trusted root certificate, which would allow any device signed by that certificate to be enrolled, or we would provide our device manufacturer with some automated mechanism for uploading device identities once they've been extracted from the physical hardware. You will need the. NET Core SDK version 2 or greater if you want to implement the code.
 
You will need to create a .Net Core project, which will have a Program.cs and add 2 files, name one Device.cs and the other CertificateFactory.cs.
 
Program.cs Code
  1. using System;  
  2. using System.IO;  
  3. using System.Security.Cryptography.X509Certificates;  
  4. using System.Threading.Tasks;  
  5.   
  6. namespace DeviceProvisioningSample  
  7. {  
  8.     class Program  
  9.     {  
  10.         static async Task Main(string[] args)  
  11.         {  
  12.             if (args == null || args.Length < 1)   
  13.             {  
  14.                 Console.WriteLine("You must specify an action!");  
  15.                 return;  
  16.             }  
  17.   
  18.             if (args[0] == "setup")   
  19.             {  
  20.                 CertificateFactory.CreateTestCert();  
  21.             }  
  22.             else  
  23.             {  
  24.                 var scopeId = args[0];  
  25.                 var device = new Device(scopeId);  
  26.                 await device.Provision();  
  27.                 await device.ConnectAndRun();  
  28.             }  
  29.         }  
  30.     }  
  31. }  
Device.cs Code
  1. using System;  
  2. using System.IO;  
  3. using System.Security.Cryptography.X509Certificates;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using Microsoft.Azure.Devices.Provisioning.Client;  
  7. using Microsoft.Azure.Devices.Provisioning.Client.Transport;  
  8. using Microsoft.Azure.Devices.Shared;  
  9. using Microsoft.Azure.Devices.Client;  
  10.   
  11. namespace DeviceProvisioningSample  
  12. {  
  13.     public class Device  
  14.     {  
  15.         private string scopeId;  
  16.         private string assignedHub;  
  17.         private DeviceAuthenticationWithX509Certificate auth;  
  18.   
  19.         public Device(string scopeId)  
  20.         {  
  21.             this.scopeId = scopeId;  
  22.         }  
  23.   
  24.         public async Task Provision()  
  25.         {  
  26.             var certificate = LoadPrivateKey("key.pfx");  
  27.   
  28.             using (var securityProvider = new SecurityProviderX509Certificate(certificate))  
  29.             using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly))  
  30.             {  
  31.                 var client = ProvisioningDeviceClient.Create("global.azure-devices-provisioning.net"this.scopeId, securityProvider, transport);  
  32.   
  33.                 var result = await client.RegisterAsync();  
  34.   
  35.                 Console.WriteLine($"Provisioning result: {result.Status}");  
  36.   
  37.                 if (result.Status != ProvisioningRegistrationStatusType.Assigned)   
  38.                 {  
  39.                     throw new InvalidOperationException("Something went wrong while trying to provision.");  
  40.                 }  
  41.   
  42.                 this.assignedHub = result.AssignedHub;  
  43.                 this.auth = new DeviceAuthenticationWithX509Certificate(result.DeviceId, securityProvider.GetAuthenticationCertificate());  
  44.             }  
  45.         }  
  46.   
  47.         private static X509Certificate2 LoadPrivateKey(string key)  
  48.         {  
  49.             if (!File.Exists(key))   
  50.             {  
  51.                 Console.WriteLine("No private key found.  Execute `dotnet run setup` first.");  
  52.                 Environment.Exit(-1);  
  53.             }  
  54.   
  55.             var certificateCollection = new X509Certificate2Collection();  
  56.             certificateCollection.Import(key);  
  57.   
  58.             foreach (var element in certificateCollection)  
  59.             {  
  60.                 if (element.HasPrivateKey)  
  61.                 {  
  62.                     return element;  
  63.                 }  
  64.                 else  
  65.                 {  
  66.                     element.Dispose();  
  67.                 }  
  68.             }  
  69.   
  70.             throw new InvalidOperationException("No private key found.  Execute `dotnet run setup` first.");  
  71.         }  
  72.   
  73.         internal async Task ConnectAndRun()  
  74.         {  
  75.             using (var client = DeviceClient.Create(this.assignedHub, this.auth, TransportType.Amqp))  
  76.             {  
  77.                 Console.Write($"Connecting to hub: {this.assignedHub}... ");  
  78.                 await client.OpenAsync();  
  79.                 Console.WriteLine("Connected!");  
  80.   
  81.                 Console.Write("Sending D2C message... ");  
  82.                 await client.SendEventAsync(new Message(Encoding.UTF8.GetBytes("Hello from a provisiond device!")));  
  83.                 Console.WriteLine("Sent!");  
  84.                   
  85.                 Console.Write("Closing connection... ");  
  86.                 await client.CloseAsync();  
  87.                 Console.WriteLine("Connection Closed!");  
  88.             }  
  89.         }  
  90.     }  
  91. }  
CertificateFactory.cs Code
  1. using System;  
  2. using System.IO;  
  3. using System.Security.Cryptography;  
  4. using System.Security.Cryptography.X509Certificates;  
  5.   
  6. namespace DeviceProvisioningSample  
  7. {  
  8.     public static class CertificateFactory  
  9.     {  
  10.         public static void CreateTestCert()  
  11.         {  
  12.             var ecdsa = ECDsa.Create();   
  13.             var request = new CertificateRequest("cn=globomantics-prov-dev-01", ecdsa, HashAlgorithmName.SHA256);  
  14.             var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1));  
  15.   
  16.             // Create PFX (PKCS #12) with private key  
  17.             Console.WriteLine("Writing private key to key.pfx...");  
  18.             File.WriteAllBytes("key.pfx", certificate.Export(X509ContentType.Pfx));  
  19.   
  20.             // Create Base 64 encoded CER (public key only)  
  21.             Console.WriteLine("Writing public certificate to cert.cer...");  
  22.             File.WriteAllText("cert.cer""-----BEGIN CERTIFICATE-----\r\n"  
  23.                 + Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)  
  24.                 + "\r\n-----END CERTIFICATE-----");  
  25.         }  
  26.     }  
  27. }  
We're going to add a new device enrollment through the Azure portal.
 
We just need to go to our Device Provisioning Service and then into Manage enrollments.
 
Registering Devices With IoT Hub Device Provisioning Service
 
There are two tabs here, one for group enrollments and one for individual enrollments. We haven't enrolled anything yet, so both are empty. We're going to add an individual enrollment.
 
Registering Devices With IoT Hub Device Provisioning Service
 
We're going to go with X. 509 for our attestation mechanism, but we could switch to another option if we wanted. Since we're using X. 509 attestation, we have to upload a certificate, and that's where the .Net Core application that we’ve created comes in.
 
We're going to use the. NET Core CLI to run this project. So let's go ahead and navigate into the folder with our project. Now let's go over to our terminal and let's change to that directory. We can do cd, and then we can paste in that path that we copied. There we go. Now let's execute this command to generate an X. 509 certificate for us to test with, dotnet run setup.
 
Registering Devices With IoT Hub Device Provisioning Service
 
And as we can see from the output, we now have a private key and a certificate.
 
Registering Devices With IoT Hub Device Provisioning Service
 
Let's choose that certificate and click Open, and now our certificate has been uploaded.
 
Registering Devices With IoT Hub Device Provisioning Service
 
There is no need to upload a secondary certificate for the sake of this article.
 
Further down is where we could assign a device ID. If we don't do this, it will use the common name from the X. 509 certificate. I'm going to go ahead and give mine a name, dps-sample-01.
 
Registering Devices With IoT Hub Device Provisioning Service
 
We can also choose how we want this device to be assigned to a hub. We only have a single hub, so it doesn't really matter what we select, but if we had more than one hub we could choose a different strategy to control how it was assigned to one of the available linked hubs. Here select “Evenly weighted distribution” option.
 
Registering Devices With IoT Hub Device Provisioning Service
 
The final set of options deal with how this device should be configured if we're using device twins. We're not going to cover device twins in this article. For now everything is configured the way we want, so all that's left to do is click this Save button, which is up at the top. And there we go, our device is now enrolled. All that's left is to actually provision it, which we'll do in the next.
 

Auto-provisioning a Device

 
So far, we've configured Azure IoT Hub Device Provisioning Service, we've enrolled our device, we're now ready for the moment of truth, auto-provisioning a device. We don't have a real device for us to use, but that's okay. The sample application we created can act as a virtual device too. So let's get to it. Let's use this virtual device to see auto-provisioning in action. We've already enrolled our virtual devices certificate with our Device Provisioning Service, but there's still one more thing we need to do before we can actually test this out. We need to tell our device how to connect to the Device Provisioning Service. For that, we'll need to go back over to the portal. Most of the heavy lifting is done for us because I used the Azure IoT Hub SDK, so all we really need to do is go into our Device Provisioning Service, and then copy this value here, the ID Scope.
 
Registering Devices With IoT Hub Device Provisioning Service
 
Now I can go back over to my terminal, and now we’re going to run our app again, but this time I'm going to pass in that ID Scope like this, dotnet run, and then the ID Scope that I copied from the Device Provisioning Service.
 
Registering Devices With IoT Hub Device Provisioning Service
 
Let's go ahead and run this command, and then we'll watch the output to see what's happening. As you can see, our device has now been assigned to a hub, and it's able to send data to the hub. So everything looks good here, but let's doublecheck and make sure. If the Device Provisioning Service truly did its thing, then we should see that our device has been added to our hub. So let's go back over to the Azure portal, let's go back over to our dashboard, and then let's go into our IoT hub, not the Device Provisioning Service. We want to see our list of devices, so let's scroll down a bit and go into IoT devices here under Explorers. And sure enough, there's our device.
 
Registering Devices With IoT Hub Device Provisioning Service
 
If you'll recall, when we enrolled our device I actually named my device dps-sample-01, and that's what the Device Provisioning Service assigned as the device ID. So everything here looks good.
 

Summary

 
This article was all about the Azure IoT Hub Device Provisioning Service. We learned about the device provisioning process, its challenges, and how Microsoft solution addresses those challenges. We learned how to create and configure a new instance of the Device Provisioning Service through the Azure portal, and we saw how to enroll a device using X. 509 certificates. We also discussed the other methods of device enrollment that the Device Provisioning Service supports, including Trusted Platform Modules and symmetric keys. We wrapped things up by putting all the pieces together. We enrolled the device, then watched as a virtual device connected to the Device Provisioning Service and our hub. We can use IoT Hub to enable two-way communication with the devices, and now with the Device Provisioning Service we can easily scale to the high volumes of devices.