To prevent the Internet of Things from becoming the largest attack surface in the history of computing, security at scale is paramount.
Any company that wants to be taken seriously as an IoT platform player has to provide cloud-scale telemetry ingestion while also delivering security to millions of events per second without skipping a beat. This is no easy task and therefore narrows down the field in this space dramatically. Microsoft Azure IoT services accomplishes this task through the use of Shared Access Signatures (SAS). They provide delegated, limited access to resources such as Event Hubs for a specified period of time with a specified set of permissions. Of course it does this without having to share the account access keys you created in the previous Event Hub article. You might remember creating a Shared Access Policy with Send permissions. You gave that policy a name and were given a connection string that includes the account access key which you used to test out a .NET IoT client. Good for testing. Career-limiting for production. That’s why you’re reading this article.
In regards to securely sending telemetry to Event Hubs, IoT devices and field gateways claim access to the Event Hub by presenting a SAS token. This token consists of the resource URI being accessed, and an expiry signed with the account access key. Basically, a URL-encoded string that is passed along every time telemetry is sent. Each IoT device needs its own distinct SAS token and that’s what you’re going to learn today.
To more easily create SAS tokens for your IoT clients, I want you to create a simple app to do the work for you. Launch Visual Studio and create a new C#, Windows Forms application and call it SASToken. From the Solution Explorer, right-click on References and select Manage NuGet Packages…
In the Search Online box type Azure Service Bus and install version 2.7.5 or later. Since you’ll be using the SharedAccessSignatureTokenProvider class to create a shared access signature for your publisher, add using Microsoft.ServiceBus; above the namespace with all the other using statements in the default Form class.
The next thing I want you to do is create a function called CreateSASToken() inside the Form class as shown below:
This function simplifies the creation of a SAS token by inputting values found on the Azure portal for your Event Hub. Let’s walk through the parameters of this function and where you can find the required values:
- EventHubUri: This is found on the Dashboard page of your Event Hub under Event Hub URL. Don’t include the last part of the URL after the final dash /
- EventHubName: This is found at the top of your Event Hub Dashboard page.
- Publisher: This is a unique name you get to create for the IoT device that’s sending the telemetry to the Event Hub.
- PolicyName: This is found on the Configure page of your Event Hub and is the name of the shared access policy you created with Send permissions.
- PolicyKey: At the bottom of your Event Hub’s Configure page is a section called shared access key generator. Select the correct Policy Name from the dropdown box and copy the Primary Key in the text box below it.
- Expiration: Enter the number of minutes you want your token to be valid. This TimeSpan code can be changed so you can use days or hours as well.
With the function up and running, you can now create unique tokens for each of your Publishers rather than insecurely using the same connection string for all of them. This also means that your Event Hub can prevent individual Publishers from sending telemetry if any of them have been compromised. To make better use of this function, follow along and build a simple data entry form.
Load the default Form in the Visual Studio and add the following UI controls and associated properties:
- Label: Text = Event Hub Uri:
- TextBox: Name = txtEventHubUri
- Label: Text = Event Hub Name:
- TextBox: Name = txtEventHubName
- Label: Text = Publisher:
- TextBox: Name = txtPublisher
- Label: Text = Policy Name:
- TextBox: Name = txtPolicyName
- Label: Text = Policy Key:
- TextBox: Name = txtPolicyKey
- Button: Name = btnCreateSAS Text = Create SAS Token
- Label: Text = SAS Token:
- TextBox: Name = txtSASToken
In order to bring things to life, create a click event for the Button and add the following code:
The code calls the CreateSASToken() function you created and passes in the values you type or paste into the TextBoxes. I hard-coded in 60 minutes but you can make that any number you like and you could even add a NumericUpDown control. The function returns a SAS token as a string and displays it in the TextBox at the bottom of the Form.
At this point, go ahead and run the app you just built. Type in or paste the appropriate values from the Azure portal into the TextBoxes. I called my Publisher 007 but you can call it anything you want. Click the button and you should get a SAS token as shown below:
While you now have an easy way to create SAS tokens, this won’t suffice at large scale. You’ll need to use what you’ve learned here to build a secure, on-premises or cloud-based token service to support deployment to thousands or even millions of individual IoT devices.
With your unique SAS token in hand, it’s time to modify the the app you created in the previous Event Hub article. Load the ContosoIoTConsole solution in Visual Studio and get ready to make a few changes.
Just like you did with the SAS token app, add using Microsoft.ServiceBus; above the namespace with all the other using statements in the Program class. Next, delete the first two lines of code inside Main() where you previously created a connectionString and an EventHubClient. In place of the deleted code you’ll declare a string called sasToken and paste in the long SAS token string that was generated by the Windows app you just built. Next, you’ll declare a connectionString and use the ServiceBusConnectionStringBuilder along with your Service Bus URI, Event Hub name, Publisher name, and SAS token to create it instead of reading the account access key from App.config like the previous article. In the final, new line of code, you’ll create an EventHubSender based on this new connection string. Every other line of code below stays the same. Your updated ContosoIoTConsole app should look like the code below with your Event Hub values substituted for mine:
All that’s left to do is try it out by running the console app and then checking your Event Hub Dashboard a few minutes later to see if a new message arrived.
By following the directions and code in this article, you’ve made the leap to getting an IoT client to send telemetry to Event Hubs more securely. While Event Hubs has always required transport via TLS, by presenting a SAS token, Event Hubs knows who the IoT client is and what permissions it has. A SAS token’s ability to gain access to Event Hubs doesn’t last forever due to the expiration limitations you place on it when creating a new token which is a good thing. Furthermore, Event Hubs give you device blacklisting capabilities by revoking individual publishers based on the unique name you gave them. Expired tokens and revoked publishers will result in errors being thrown in the client code when a publisher attempts to send telemetry to an Event Hub. Keep in mind that when you do a mass deployment, your IoT clients and field gateways won’t have this information hard-coded like the example we just walked through. It must be encrypted and will often be baked into the hardware silicon as the IoT devices are being manufactured. Stay secure!