A major selling point of IoT is the ability to connect existing and new devices from almost anywhere. However, implementing such a promise in real life can be challenging. Connecting devices to a cloud-based solution can cause privacy and data sovereignty issues if they are allowed to connect and send data outside of their approved geographies as well as performance issues if they connect to resources in a geography that is significantly farther away.
The goal of this article is to articulate how to resolve this challenge using Azure IoT Hub, Device Provisioning Service (DPS), Functions and Maps. Using these Azure services, you will learn how to control an IoT device’s provisioning based on where they are connecting from.
This solution is based on a strictly PaaS/Serverless architecture and uses the process below to control device provisioning:
In this post we learned how to control where an IoT device can provision itself based on the country they are connecting from using Azure’s PaaS/serverless platform. With this solution, you can be confident that your devices are only connecting to their approved geographic locations.
If you would like to recreate this solution, you can review its GitHub, link below, for instructions on how to set it up end-to-end.
Let us know what you think by commenting below.
Geographically Provisioning IoT Devices on Azure | GitHub
Azure IoT Hub Device Provisioning Service | Overview
Azure IoT Hub Device Provisioning Service | Custom Allocation Policy
Azure Maps | Geolocation - Get IP To Location
Azure Maps | Search - Get Search Address Reverse
Azure IoT Hub | Deployment Stamps
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Microsoft.Azure.Devices.Shared; // For TwinCollection
using Microsoft.Azure.Devices.Provisioning.Service; // For TwinState
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
// Get request body
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
log.LogInformation("Request.Body:...");
log.LogInformation(requestBody);
var client = new HttpClient();
const string subscriptionKey = "ReplaceMeWithAzureMapsSubKey";
string ipAddress = data?.deviceRuntimeContext["payload"]["IpV4"];
log.LogInformation($"IP Address: {ipAddress}");
string gUri = $"https://atlas.microsoft.com/geolocation/ip/json?subscription-key={subscriptionKey}&api-version=1.0&ip={ipAddress}";
HttpResponseMessage response = await client.GetAsync(gUri);
string responseBody = await response.Content.ReadAsStringAsync();
dynamic locationInfo = JsonConvert.DeserializeObject(responseBody);
log.LogInformation($"Response: {responseBody}");
// Get registration ID of the device
string regId = data?.deviceRuntimeContext?.registrationId;
// Get country code
string countryCode = locationInfo["countryRegion"]["isoCode"]?.ToString();
log.LogInformation($"Country Code: {countryCode}");
string message = "Uncaught error";
bool fail = false;
ResponseObj obj = new ResponseObj();
string[] hubs = data?.linkedHubs.ToObject<string[]>();
obj.iotHubHostName = hubs.FirstOrDefault();
if (regId == null)
{
obj.iotHubHostName = null;
message = "Registration ID not provided for the device.";
log.LogInformation("Registration ID : NULL");
fail = true;
}
else if (countryCode == null || countryCode != "US")
{
obj.iotHubHostName = null;
message = "IP address of device is not from US";
log.LogInformation($"Country Code Not US: {countryCode}");
fail = true;
}
log.LogInformation("\nResponse");
log.LogInformation((obj.iotHubHostName != null) ? JsonConvert.SerializeObject(obj) : message);
return (fail)
? new BadRequestObjectResult(message)
: (ActionResult)new OkObjectResult(obj);
}
public class ResponseObj
{
public string iotHubHostName {get; set;}
public TwinState initialTwin {get; set;}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.