Tutorial: Provision for geo latency
This tutorial shows how to securely provision multiple simulated symmetric key devices to a group of IoT Hubs using an allocation policy. IoT Hub Device Provisioning Service (DPS) supports various allocation scenarios through its built-in allocation policies and its support for custom allocation policies.
Provisioning for Geolocation/Geo latency is a common allocation scenario. As a device moves between locations, network latency is improved by having the device provisioned to the IoT hub that's closest to each location. In this scenario, a group of IoT hubs, which span across regions, are selected for enrollments. The built-in Lowest latency allocation policy is selected for these enrollments. This policy causes the Device Provisioning Service to evaluate device latency and determine the closet IoT hub out of the group of IoT hubs.
This tutorial uses a simulated device sample from the Azure IoT C SDK to demonstrate how to provision devices across regions. You'll perform the following steps in this tutorial:
- Use the Azure CLI to create two regional IoT hubs (China North 2 and China East)
- Create an enrollment that provisions devices based on geolocation (lowest latency)
- Use the Azure CLI to create two regional Linux VMs to act as devices in the same regions (China North 2 and China East)
- Set up the development environment for the Azure IoT C SDK on both Linux VMs
- Simulate the devices and verify that they're provisioned to the IoT hub in the closest region.
Important
Some regions may, from time to time, enforce restrictions on the creation of Virtual Machines. At the time of writing this guide, the chinanorth2 and chinaeast regions permitted the creation of VMs. If you're unable to create in either one of those regions, you can try a different region. To learn more about choosing Azure geographical regions when creating VMs, see Regions for virtual machines in Azure
Prerequisites
If you don't have an Azure subscription, create a trial subscription before you begin.
Complete the steps in Set up IoT Hub Device Provisioning Service with the Azure portal.
If you prefer to run CLI reference commands locally, install the Azure CLI. If you're running on Windows or macOS, consider running Azure CLI in a Docker container. For more information, see How to run the Azure CLI in a Docker container.
If you're using a local installation, sign in to the Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal. For other sign-in options, see Sign in with the Azure CLI.
When you're prompted, install the Azure CLI extension on first use. For more information about extensions, see Use extensions with the Azure CLI.
Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade.
Create two regional IoT hubs
In this section, you'll create an Azure resource group, and two new regional IoT hub resources. One IoT hub will be for the China North 2 region and the other will be for the China East region.
Important
It's recommended that you use the same resource group for all resources created in this tutorial. This will make clean up easier after you're finished.
In the Azure local Shell, create a resource group with the following az group create command:
az group create --name contoso-us-resource-group --location chinaeast
Create an IoT hub in the chinaeast location, and add it to the resource group you created with the following az iot hub create command(replace
{unique-hub-name}
with your own unique name):az iot hub create --name {unique-hub-name} --resource-group contoso-us-resource-group --location chinaeast --sku S1
This command may take a few minutes to complete.
Now, create an IoT hub in the chinanorth2 location, and add it to the resource group you created with the following az iot hub create command(replace
{unique-hub-name}
with your own unique name):az iot hub create --name {unique-hub-name} --resource-group contoso-us-resource-group --location chinanorth2 --sku S1
This command may take a few minutes to complete.
Create an enrollment for geo latency
In this section, you'll create a new enrollment group for your devices.
For simplicity, this tutorial uses Symmetric key attestation with the enrollment. For a more secure solution, consider using X.509 certificate attestation with a chain of trust.
Sign in to the Azure portal and navigate to your Device Provisioning Service instance.
Select Manage enrollments from the Settings section of the navigation menu.
Select Add enrollment group.
On the Registration + provisioning tab of the Add enrollment group page, provide the following information to configure the enrollment group details:
Field Description Attestation Select Symmetric key as the Attestation mechanism. Symmetric key settings Check the Generate symmetric keys automatically box. Group name Name your group contoso-us-devices, or provide your own group name. The enrollment group name is a case-insensitive string (up to 128 characters long) of alphanumeric characters plus the special characters: '-'
,'.'
,'_'
,':'
. The last character must be alphanumeric or dash ('-'
).Select Next: IoT hubs.
Use the following steps to add your two IoT hubs to the enrollment group:
On the IoT hubs tab of the Add enrollment group page, select Add link to IoT hub in the Target IoT hubs section.
On the Add link to IoT hub page, select the IoT hub that you created in the chinaeast region and assign it the iothubowner access.
Select Save.
Select Add link to IoT hub again, and follow the same steps to add the IoT hub that you created in the chinanorth2 region.
In the Target IoT hubs dropdown menu, select both IoT hubs.
For the Allocation policy, select Lowest latency.
Select Review + create.
On the Review + create tab, verify all of your values then select Create.
Once your enrollment group is created, select its name contoso-us-devices from the enrollment groups list.
Copy the Primary key. This key will be used later to generate unique device keys for both simulated devices.
Create regional Linux VMs
In this section, you create two regional Linux virtual machines (VMs), one in China North 2 and one in China East 2. These VMs run a device simulation sample from each region to demonstrate device provisioning for devices from both regions.
To make clean-up easier, add these VMs to the same resource group that contains the IoT hubs that were created, contoso-us-resource-group.
In the Azure local Shell, run the following command to create an China East region VM after making the following parameter changes in the command:
--name: Enter a unique name for your China East regional device VM.
--admin-username: Use your own admin user name.
--admin-password: Use your own admin password.
az vm create \ --resource-group contoso-us-resource-group \ --name ContosoSimDeviceEast \ --location chinaeast \ --image Canonical:UbuntuServer:18.04-LTS:18.04.201809110 \ --admin-username contosoadmin \ --admin-password myContosoPassword2018 \ --authentication-type password --public-ip-sku Standard
This command will take a few minutes to complete.
Once the command has completed, copy the publicIpAddress value for your China East region VM.
In the Azure local Shell, run the command to create a China North 2 region VM after making the following parameter changes in the command:
--name: Enter a unique name for your China North 2 regional device VM.
--admin-username: Use your own admin user name.
--admin-password: Use your own admin password.
az vm create \ --resource-group contoso-us-resource-group \ --name ContosoSimDeviceWest2 \ --location chinanorth2 \ --image Canonical:UbuntuServer:18.04-LTS:18.04.201809110 \ --admin-username contosoadmin \ --admin-password myContosoPassword2018 \ --authentication-type password --public-ip-sku Standard
This command will take a few minutes to complete.
Once the command has completed, copy the publicIpAddress value for your China North 2 region VM.
Open two command-line shells.
Connect to one of the regional VMs in each shell using SSH.
Pass your admin username and the public IP address that you copied as parameters to SSH. Enter the admin password when prompted.
ssh contosoadmin@1.2.3.4 contosoadmin@ContosoSimDeviceEast:~$
ssh contosoadmin@5.6.7.8 contosoadmin@ContosoSimDeviceWest:~$
Prepare the Azure IoT C SDK development environment
In this section, you'll clone the Azure IoT C SDK on each VM. The SDK contains a sample that simulates a device provisioning from each region.
For each VM:
Install CMake, g++, gcc, and Git using the following commands:
sudo apt-get update sudo apt-get install cmake build-essential libssl-dev libcurl4-openssl-dev uuid-dev git-all
Find and copy the tag name for the latest release of the SDK.
Clone the Azure IoT Device SDK for C on both VMs. Use the tag you found in the previous step as the value for the
-b
parameter, for example:lts_01_2023
.git clone -b <release-tag> https://github.com/Azure/azure-iot-sdk-c.git cd azure-iot-sdk-c git submodule update --init
You should expect this operation to take several minutes to complete.
Create a new cmake folder inside the repository and change to that folder.
mkdir ~/azure-iot-sdk-c/cmake cd ~/azure-iot-sdk-c/cmake
Run the following command, which builds a version of the SDK specific to your development client platform:
cmake -Dhsm_type_symm_key:BOOL=ON -Duse_prov_client:BOOL=ON ..
Once the build succeeds, the last few output lines will look similar to the following output:
-- IoT Client SDK Version = 1.7.0 -- Provisioning SDK Version = 1.7.0 -- Looking for include file stdint.h -- Looking for include file stdint.h - found -- Looking for include file stdbool.h -- Looking for include file stdbool.h - found -- target architecture: x86_64 -- Performing Test CXX_FLAG_CXX11 -- Performing Test CXX_FLAG_CXX11 - Success -- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so (found version "1.1.1") -- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so (found version "7.58.0") -- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so -- target architecture: x86_64 -- iothub architecture: x86_64 -- Configuring done -- Generating done -- Build files have been written to: /home/contosoadmin/azure-iot-sdk-c/azure-iot-sdk-c
Derive unique device keys
When using symmetric key attestation with group enrollments, you don't use the enrollment group keys directly. Instead, you derive a unique key from the enrollment group key for each device.
In this part of the tutorial, you'll generate a device key from the group master key to compute an HMAC-SHA256 of the unique registration ID for the device. The result will then be converted into Base64 format.
Important
Don't include your group master key in your device code.
For both chinaeast and chinanorth2 devices:
Generate your unique key using openssl. You'll use the following Bash shell script (replace
{primary-key}
with the enrollment group's Primary Key that you copied earlier and replace{contoso-simdevice}
with your own unique registration ID for each device. The registration ID is a case-insensitive string (up to 128 characters long) of alphanumeric characters plus the special characters:'-'
,'.'
,'_'
,':'
. The last character must be alphanumeric or dash ('-'
).KEY={primary-key} REG_ID={contoso-simdevice} keybytes=$(echo $KEY | base64 --decode | xxd -p -u -c 1000) echo -n $REG_ID | openssl sha256 -mac HMAC -macopt hexkey:$keybytes -binary | base64
The script will output something like the following key:
p3w2DQr9WqEGBLUSlFi1jPQ7UWQL4siAGy75HFTFbf8=
Now each device has its own derived device key and unique registration ID to perform symmetric key attestation with the enrollment group during the provisioning process.
Simulate the devices from each region
In this section, you'll update a provisioning sample in the Azure IoT C SDK for both of the regional VMs.
The sample code simulates a device boot sequence that sends the provisioning request to your Device Provisioning Service instance. The boot sequence causes the device to be recognized and assigned to the IoT hub that is closest based on latency.
In the Azure portal, select the Overview tab for your Device Provisioning Service and note down the ID Scope value.
On both VMS, open ~/azure-iot-sdk-c/provisioning_client/samples/prov_dev_client_sample/prov_dev_client_sample.c for editing.
vi ~/azure-iot-sdk-c/provisioning_client/samples/prov_dev_client_sample/prov_dev_client_sample.c
On both VMs, find the
id_scope
constant, and replace the value with your ID Scope value that you copied earlier.static const char* id_scope = "0ne00002193";
On both VMs, find the definition for the
main()
function in the same file. Make sure thehsm_type
variable is set toSECURE_DEVICE_TYPE_SYMMETRIC_KEY
as shown below to match the enrollment group attestation method.Save your changes to the files on both VMs.
SECURE_DEVICE_TYPE hsm_type; //hsm_type = SECURE_DEVICE_TYPE_TPM; //hsm_type = SECURE_DEVICE_TYPE_X509; hsm_type = SECURE_DEVICE_TYPE_SYMMETRIC_KEY;
On both VMs, find the call to
prov_dev_set_symmetric_key_info()
in prov_dev_client_sample.c which is commented out.// Set the symmetric key if using they auth type //prov_dev_set_symmetric_key_info("<symm_registration_id>", "<symmetric_Key>");
Uncomment the function calls, and replace the placeholder values (including the angle brackets) with the unique registration IDs and derived device keys for each device that you derived in the previous section. The keys shown below are examples. Use the keys you generated earlier.
China East:
// Set the symmetric key if using they auth type prov_dev_set_symmetric_key_info("contoso-simdevice-east", "p3w2DQr9WqEGBLUSlFi1jPQ7UWQL4siAGy75HFTFbf8=");
China North:
// Set the symmetric key if using they auth type prov_dev_set_symmetric_key_info("contoso-simdevice-west", "J5n4NY2GiBYy7Mp4lDDa5CbEe6zDU/c62rhjCuFWxnc=");
On both VMs, save the file.
On both VMs, navigate to the sample folder shown below, and build the sample.
cd ~/azure-iot-sdk-c/cmake/provisioning_client/samples/prov_dev_client_sample/ cmake --build . --target prov_dev_client_sample --config Debug
Once the build succeeds, run prov_dev_client_sample.exe on both VMs to simulate a device from each region. Notice that each device is allocated to the IoT hub closest to the simulated device's region.
Run the simulation:
~/azure-iot-sdk-c/cmake/provisioning_client/samples/prov_dev_client_sample/prov_dev_client_sample
Example output from the China East VM:
contosoadmin@ContosoSimDeviceEast:~/azure-iot-sdk-c/cmake/provisioning_client/samples/prov_dev_client_sample$ ./prov_dev_client_sample Provisioning API Version: 1.2.9 Registering Device Provisioning Status: PROV_DEVICE_REG_STATUS_CONNECTED Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Registration Information received from service: contoso-east-hub.azure-devices.cn, deviceId: contoso-simdevice-east Press enter key to exit:
Example output from the China North VM:
contosoadmin@ContosoSimDeviceWest:~/azure-iot-sdk-c/cmake/provisioning_client/samples/prov_dev_client_sample$ ./prov_dev_client_sample Provisioning API Version: 1.2.9 Registering Device Provisioning Status: PROV_DEVICE_REG_STATUS_CONNECTED Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING Registration Information received from service: contoso-west-hub.azure-devices.cn, deviceId: contoso-simdevice-west Press enter key to exit:
Clean up resources
If you plan to continue working with resources created in this tutorial, you can leave them. Otherwise, use the following steps to delete all resources created by this tutorial to avoid unnecessary charges.
The steps here assume that you created all resources in this tutorial as instructed in the same resource group named contoso-us-resource-group.
Important
Deleting a resource group is irreversible. The resource group and all the resources contained in it are permanently deleted. Make sure that you don't accidentally delete the wrong resource group or resources. If you created the IoT Hub inside an existing resource group that contains resources you want to keep, only delete the IoT Hub resource itself instead of deleting the resource group.
To delete the resource group by name:
Sign in to the Azure portal.
Select Resource groups.
In the Filter by name... textbox, type the name of the resource group containing your resources, contoso-us-resource-group.
To the right of your resource group in the result list, click ... then Delete resource group.
You'll be asked to confirm the deletion of the resource group. Type the name of your resource group again to confirm, and then select Delete. After a few moments, the resource group and all of its contained resources are deleted.
Next steps
To learn more about custom allocation policies, see