Tutorial: Provision devices using symmetric key enrollment groups

This tutorial shows how to securely provision multiple simulated symmetric key devices to a single IoT Hub using an enrollment group.

The Azure IoT Hub Device Provisioning Service supports two types of enrollments for provisioning devices:

  • Enrollment groups: Used to enroll multiple related devices. This tutorial demonstrates provisioning with enrollment groups.
  • Individual enrollments: Used to enroll a single device.

The Azure IoT Hub Device Provisioning Service supports three forms of authentication for provisioning devices:

  • X.509 certificates
  • Trusted platform module (TPM)
  • Symmetric keys - This tutorial demonstrates symmetric key attestation

Some devices may not have a certificate, TPM, or any other security feature that can be used to securely identify the device. For such devices, the Azure IoT Hub Device Provisioning Service (DPS) includes symmetric key attestation. Symmetric key attestation can be used to identify a device based on unique information like the MAC address or a serial number.

In this tutorial, you complete the following objectives:

  • Define a unique registration ID for each device.
  • Create an enrollment group that uses symmetric key attestation.
  • Produce a device key for each device using its unique registration ID and shared enrollment group key.
  • Provision devices using the device key and sample code in the Azure IoT device SDKs.

This tutorial is oriented toward a Windows-based workstation. However, you can perform the procedures on Linux. For a Linux example, see Tutorial: Provision for geo latency.

Note

If you've previously completed Quickstart: Provision a simulated symmetric key device and still have your Azure resources and development environment set up, you can proceed to Create a symmetric key enrollment group in this tutorial.

Prerequisites

  • If you're using a Windows development environment, install Visual Studio 2022 with the 'Desktop development with C++' workload enabled. Visual Studio 2019, Visual Studio 2017, and Visual Studio 2015 are also supported. For Linux or macOS, see the appropriate section in Prepare your development environment in the SDK documentation.

  • Install the latest CMake build system. Make sure you check the option that adds the CMake executable to your path.

    Important

    Confirm that the Visual Studio prerequisites (Visual Studio and the 'Desktop development with C++' workload) are installed on your machine, before starting the CMake installation. Once the prerequisites are in place, and the download is verified, install the CMake build system. Also, be aware that older versions of the CMake build system fail to generate the solution file used in this article. Make sure to use the latest version of CMake.

  • Install .NET SDK 6.0 or later on your Windows-based machine. You can use the following command to check your version.

    dotnet --info
    
  • Install Python 3.7 or later installed on your Windows-based machine. You can check your version of Python by running python --version.
  • Install the latest version of Git. Make sure that Git is added to the environment variables accessible to the command window. See Software Freedom Conservancy's Git client tools for the latest version of git tools to install, which includes Git Bash, the command-line app that you can use to interact with your local Git repository.

Prepare your development environment

In this section, you prepare a development environment to build the Azure IoT Device SDK for C. The sample code provisions the device during the device's boot sequence.

  1. In a web browser, go to the Release page of the Azure IoT C SDK.

  2. Copy the tag name for the latest release of the Azure IoT C SDK, for example: lts_03_2024.

  3. Open a Windows command prompt and run the following commands to clone the latest release of the Azure IoT Device SDK for C GitHub repository. Replace <release-tag> with the tag you copied in the previous step.

    git clone -b <release-tag> https://github.com/Azure/azure-iot-sdk-c.git
    cd azure-iot-sdk-c
    git submodule update --init
    

    This operation could take several minutes to complete.

  4. When the operation is complete, run the following commands from the azure-iot-sdk-c directory:

    mkdir cmake
    cd cmake
    
  5. The code sample uses a symmetric key to provide attestation. Run the following command to build a version of the SDK specific to your development client platform that includes the device provisioning client:

    cmake -Dhsm_type_symm_key:BOOL=ON -Duse_prov_client:BOOL=ON  ..
    

    Tip

    If cmake does not find your C++ compiler, you may get build errors while running the above command. If that happens, try running the command in the Visual Studio command prompt.

  6. When the build completes successfully, the last few output lines will look similar to the following output:

    $ cmake -Dhsm_type_symm_key:BOOL=ON -Duse_prov_client:BOOL=ON  ..
    -- Building for: Visual Studio 16 2019
    -- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.22621.
    -- The C compiler identification is MSVC 19.29.30146.0
    -- The CXX compiler identification is MSVC 19.29.30146.0
    
    ...
    
    -- Configuring done
    -- Generating done
    -- Build files have been written to: C:/azure-iot-sdk-c/cmake
    
  1. Open a command prompt or Git Bash terminal.

  2. Clone the Azure IoT SDK for C# GitHub repository using the following command:

    git clone https://github.com/Azure/azure-iot-sdk-csharp.git
    
  1. Open a command prompt or Git Bash terminal.

  2. Clone the Azure IoT SDK for Node.js GitHub repository using the following command:

    git clone https://github.com/Azure/azure-iot-sdk-node.git --recursive
    
  1. Open a command prompt or Git Bash terminal.

  2. Clone the Azure IoT Device SDK for Python GitHub repository using the following command:

    git clone -b v2 https://github.com/Azure/azure-iot-sdk-python.git --recursive
    

    Note

    The samples used in this tutorial are in the v2 branch of the azure-iot-sdk-python repository. V3 of the Python SDK is available to use in beta. For information about updating V2 code samples to use a V3 release of the Python SDK, see Azure IoT Device SDK for Python migration guide.

  1. Open a command prompt or Git Bash terminal.

  2. Clone the Azure IoT SDK for Java GitHub repository using the following command:

    git clone https://github.com/Azure/azure-iot-sdk-java.git --recursive
    
  3. Go to the root azure-iot-sdk-java directory and build the project to download all needed packages. This step can take several minutes to complete.

    cd azure-iot-sdk-java
    mvn install -DskipTests=true
    

Create a symmetric key enrollment group

  1. Sign in to the Azure portal and navigate to your Device Provisioning Service instance.

  2. Select Manage enrollments from the Settings section of the navigation menu.

  3. Select Add enrollment group.

  4. 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 if you want to use randomly generated keys. Uncheck this box if you want to provide your own keys.
    Group name Provide a name for the group of devices. 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 ('-').
    Provisioning status Check the Enable this enrollment box if you want this enrollment group to be available to provision devices. Uncheck this box if you want the group to be disabled. You can change this setting later.
    Reprovision policy Choose a reprovision policy that reflects how you want DPS to handle devices that request reprovisioning. For more information, see Reprovision policies

    Screenshot that shows adding an enrollment group for symmetric key attestation.

  5. Select Next: IoT hubs.

  6. On the IoT hubs tab of the Add enrollment group page, provide the following information to determine which IoT hubs the enrollment group can provision devices to:

    Field Description
    Target IoT hubs Select one or more of your linked IoT hubs, or add a new link to an IoT hub. To learn more about linking IoT hubs to your DPS instance, see How to link and manage IoT hubs.
    Allocation policy If you selected more than one linked IoT hub, select how you want to assign devices to the different hubs. To learn more about allocation policies, see How to use allocation policies.

    If you selected only one linked IoT hub, we recommend using the Evenly weighted distribution policy.

    Screenshot that shows connecting IoT hubs to the new enrollment group.

  7. Select Next: Device settings

  8. On the Device settings tab of the Add enrollment group page, provide the following information to define how newly provisioned devices will be configured:

    Field Description
    IoT Edge Check the Enable IoT Edge on provisioned devices if all the devices provisioned through this group will run Azure IoT Edge. Uncheck this box if this group is for non-IoT Edge-enabled devices only. Either all devices in a group will be IoT Edge-enabled or none can be.
    Device tags Use this text box to provide any tags that you want to apply to the device twins of provisioned devices.
    Desired properties Use this text box to provide any desired properties that you want to apply to the device twins of provisioned devices.

    For more information, see Understand and use device twins in IoT Hub.

  9. Select Next: Review + create.

  10. On the Review + create tab, verify all of your values then select Create.

When you create the enrollment group, DPS generates a primary key and secondary key, then adds them to the enrollment entry. Your symmetric key enrollment group appears under the Group name column in the Enrollment Groups tab.

Open the enrollment and copy the value of the Primary Key. This key is your group key.

Choose a unique registration ID for the device

A unique registration ID must be defined to identify each device. You can use the MAC address, serial number, or any unique information from the device.

In this example, we use a combination of a MAC address and serial number forming the following string for a registration ID.

sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6

Create unique registration IDs for each device. The registration ID is a case-insensitive string (up to 128 characters long) of alphanumeric characters plus the following special characters: - . _ :. The last character must be alphanumeric or dash (-).

Derive a device key

To generate device keys, use the enrollment group primary key to compute an HMAC-SHA256 hash of the registration ID for each device. The result is then converted into Base 64 format for each device.

Warning

Your device code for each device should only include the derived device key for that device. Do not include your group primary key in your device code. A compromised group key has the potential to compromise the security of all devices being authenticated with it.

The IoT extension for the Azure CLI provides the az iot dps enrollment-group compute-device-key command for generating derived device keys. This command can be used from both Windows-based and Linux systems.

Replace the value of the --key parameter with the Primary Key from your enrollment group.

Replace the value of the --registration-id parameter with your registration ID.

az iot dps enrollment-group compute-device-key --key <group_primary_key> --registration-id <device_registration_id>

Example result:

"Jsm0lyGpjaVYVP2g3FnmnmG9dI/9qU24wNoykUmermc="

Each device uses its derived device key and unique registration ID to perform symmetric key attestation with the enrollment group during provisioning.

Prepare and run the device provisioning code

In this section, you update the device sample code to send the device's boot sequence to your Device Provisioning Service instance. This boot sequence causes the device to be recognized, authenticated, and assigned to an IoT hub linked to the Device Provisioning Service instance.

The sample provisioning code accomplishes the following tasks, in order:

  1. Authenticates your device with your Device Provisioning resource using the following three parameters:

    • The ID Scope of your Device Provisioning Service
    • The registration ID for your device.
    • The derived device key for your device.
  2. Assigns the device to the IoT hub already linked to your Device Provisioning Service instance.

To update and run the provisioning sample with your device information:

  1. In the main menu of your Device Provisioning Service, select Overview.

  2. Copy the ID Scope value.

    Screenshot that shows copying the ID scope from the DPS overview pane.

  3. In Visual Studio, open the azure_iot_sdks.sln solution file that was generated by running CMake. The solution file should be in the following location:

    
    \azure-iot-sdk-c\cmake\azure_iot_sdks.sln
    
    

    Tip

    If the file was not generated in your cmake directory, make sure you used a recent version of the CMake build system.

  4. In Visual Studio's Solution Explorer window, go to the Provision_Samples folder. Expand the sample project named prov_dev_client_sample. Expand Source Files, and open prov_dev_client_sample.c.

  5. Find the id_scope constant, and replace the value with the ID Scope value that you copied from the Azure portal.

    static const char* id_scope = "0ne00002193";
    
  6. Find the definition for the main() function in the same file. Make sure the hsm_type variable is set to SECURE_DEVICE_TYPE_SYMMETRIC_KEY as shown below:

    SECURE_DEVICE_TYPE hsm_type;
    //hsm_type = SECURE_DEVICE_TYPE_TPM;
    //hsm_type = SECURE_DEVICE_TYPE_X509;
    hsm_type = SECURE_DEVICE_TYPE_SYMMETRIC_KEY;
    
  7. Find the call to prov_dev_set_symmetric_key_info() in prov_dev_client_sample.c that 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 call and replace the placeholder values (including the angle brackets) with the registration ID you chose in Choose a unique registration ID for the device and the derived device key that you generated in Derive a device key.

    // Set the symmetric key if using they auth type
    prov_dev_set_symmetric_key_info("sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6", "Jsm0lyGpjaVYVP2g3FnmnmG9dI/9qU24wNoykUmermc=");
    

    Caution

    Be aware that this step leaves the derived device key included as part of the image for each device, which isn't a recommended security best practice. This is one reason why security and ease-of-use are often tradeoffs. You must fully review the security of your devices based on your own requirements.

  8. Save the file.

  9. Right-click the prov_dev_client_sample project and select Set as Startup Project.

  10. On the Visual Studio menu, select Debug > Start without debugging to run the solution. In the rebuild the project prompt, select Yes to rebuild the project before running.

    The following output is an example of the device successfully connecting to the provisioning Service instance to be assigned to an IoT hub:

    Provisioning API Version: 1.9.1
    
    Registering Device
    
    Provisioning Status: PROV_DEVICE_REG_STATUS_CONNECTED
    Provisioning Status: PROV_DEVICE_REG_STATUS_ASSIGNING
    
    Registration Information received from service: contoso-hub-2.azure-devices.net, deviceId: sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6
    Press enter key to exit:
    

The sample provisioning code accomplishes the following tasks:

  1. Authenticates your device with your Device Provisioning resource using the following three parameters:

    • The ID Scope of your Device Provisioning Service
    • The registration ID for your device.
    • The derived device key for your device.
  2. Assigns the device to the IoT hub already linked to your Device Provisioning Service instance.

  3. Sends a test telemetry message to the IoT hub.

To update and run the provisioning sample with your device information:

  1. In the main menu of your Device Provisioning Service, select Overview.

  2. Copy the ID Scope value.

    Screenshot that shows copying the ID scope from the DPS overview pane.

  3. Open a command prompt and go to the SymmetricKeySample in the cloned SDK repository:

    cd .\azure-iot-sdk-csharp\provisioning\device\samples\how to guides\SymmetricKeySample
    
  4. In the SymmetricKeySample folder, open Parameters.cs in a text editor. This file shows the parameters referenced by the sample. Only the first three required parameters are used in this article when running the sample. Review the code in this file. No changes are needed.

    Parameter Required Description
    --i or --IdScope True The ID Scope of the DPS instance
    --r or --RegistrationId True The registration ID for the 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 ('-').
    --p or --PrimaryKey True The primary key of an individual enrollment or the derived device key of a group enrollment.
    --g or --GlobalDeviceEndpoint False The global endpoint for devices to connect to. Defaults to global.azure-devices-provisioning.net
    --t or --TransportType False The transport to use to communicate with the device provisioning instance. Defaults to Mqtt. Possible values include Mqtt, Mqtt_WebSocket_Only, Mqtt_Tcp_Only, Amqp, Amqp_WebSocket_Only, Amqp_Tcp_only, and Http1.
  5. In the SymmetricKeySample folder, open ProvisioningDeviceClientSample.cs in a text editor. This file shows how the SecurityProviderSymmetricKey class is used along with the ProvisioningDeviceClient class to provision your simulated symmetric key device. Review the code in this file. No changes are needed.

  6. Build and run the sample code using the following command:

    • Replace <id-scope> with the ID Scope that you copied from the Azure portal.
    • Replace <registration-id> with the registration ID that you chose in Choose a unique registration ID for the device.
    • Replace <primarykey> with the derived device key that you generated.
    dotnet run --i <id-scope> --r <registration-id> --p <primarykey>
    
  7. You should see something similar to the following output. A "TestMessage" string is sent to the hub as a test message.

    D:\azure-iot-sdk-csharp\provisioning\device\samples\how to guides\SymmetricKeySample>dotnet run --i 0ne00000A0A --r sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6 --p sbDDeEzRuEuGKag+kQKV+T1QGakRtHpsERLP0yPjwR93TrpEgEh/Y07CXstfha6dhIPWvdD1nRxK5T0KGKA+nQ==
    
    Initializing the device provisioning client...
    Initialized for registration Id sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6.
    Registering with the device provisioning service...
    Registration status: Assigned.
    Device sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6 registered to contoso-hub-2.azure-devices.net.
    Creating symmetric key authentication for IoT Hub...
    Testing the provisioned device with IoT Hub...
    Sending a telemetry message...
    Finished.
    

The sample provisioning code accomplishes the following tasks, in order:

  1. Authenticates your device with your Device Provisioning resource using the following four parameters:

    • PROVISIONING_HOST
    • PROVISIONING_IDSCOPE
    • PROVISIONING_REGISTRATION_ID
    • PROVISIONING_SYMMETRIC_KEY
  2. Assigns the device to the IoT hub already linked to your Device Provisioning Service instance.

  3. Sends a test telemetry message to the IoT hub.

To update and run the provisioning sample with your device information:

  1. In the main menu of your Device Provisioning Service, select Overview.

  2. Copy the ID Scope value.

    Screenshot that shows copying the ID scope from the DPS overview pane.

  3. Open a command prompt for executing Node.js commands, and go to the following directory:

    cd azure-iot-sdk-node\provisioning\device\samples
    
  4. In the provisioning/device/samples folder, open register_symkey.js and review the code.

    The sample defaults to MQTT as the transport protocol. If you want to use a different protocol, comment out the following line and uncomment the line for the appropriate protocol.

    var ProvisioningTransport = require('azure-iot-provisioning-device-mqtt').Mqtt;
    

    Notice, also, that the sample code sets a custom payload:

    provisioningClient.setProvisioningPayload({a: 'b'});
    

    You may comment out this code, as it's not needed with for this tutorial. A custom payload can be used when you use a custom allocation webhook to assign your device to an IoT Hub. For more information, see Tutorial: Use custom allocation policies.

    The provisioningClient.register() method attempts the registration of your device.

  5. In the command prompt, run the following commands to set environment variables used by the sample:

    • The first command sets the PROVISIONING_HOST environment variable to the Global device endpoint. This endpoint is the same for all DPS instances.
    • Replace <id-scope> with the ID Scope that you copied from the Azure portal.
    • Replace <registration-id> with the registration ID that you chose in Choose a unique registration ID for the device.
    • Replace <defived-device-key> with the derived device key that you generated in Derive a device key.
    set PROVISIONING_HOST=global.azure-devices-provisioning.net
    
    set PROVISIONING_IDSCOPE=<id-scope>
    
    set PROVISIONING_REGISTRATION_ID=<registration-id>
    
    set PROVISIONING_SYMMETRIC_KEY=<derived-device-key>
    
  6. Build and run the sample code using the following commands:

     npm install
    
    node register_symkey.js
    
  7. You should now see something similar to the following output. A "Hello World" string is sent to the hub as a test message.

    registration succeeded
    assigned hub=contoso-hub-2.azure-devices.net
    deviceId=sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6
    payload=undefined
    Client connected
    send status: MessageEnqueued
    

The sample provisioning code accomplishes the following tasks, in order:

  1. Authenticates your device with your Device Provisioning resource using the following four parameters:

    • PROVISIONING_HOST
    • PROVISIONING_IDSCOPE
    • PROVISIONING_REGISTRATION_ID
    • PROVISIONING_SYMMETRIC_KEY
  2. Assigns the device to the IoT hub already linked to your Device Provisioning Service instance.

  3. Sends a test telemetry message to the IoT hub.

To update and run the provisioning sample with your device information:

  1. In the main menu of your Device Provisioning Service, select Overview.

  2. Copy the ID Scope value.

    Screenshot that shows copying the ID scope from the DPS overview pane.

  3. Open a command prompt and go to the directory where the sample file, provision_symmetric_key.py, is located.

    cd azure-iot-sdk-python\samples\async-hub-scenarios
    
  4. In the command prompt, run the following commands to set environment variables used by the sample:

    • The first command sets the PROVISIONING_HOST environment variable to the Global device endpoint. This endpoint is the same for all DPS instances.
    • Replace <id-scope> with the ID Scope that you copied from the Azure portal.
    • Replace <registration-id> with the registration ID that you chose in Choose a unique registration ID for the device.
    • Replace <defived-device-key> with the derived device key that you generated in Derive a device key.
    set PROVISIONING_HOST=global.azure-devices-provisioning.net
    
    set PROVISIONING_IDSCOPE=<id-scope>
    
    set PROVISIONING_REGISTRATION_ID=<registration-id>
    
    set PROVISIONING_SYMMETRIC_KEY=<derived-device-key>
    
  5. Install the azure-iot-device library by running the following command.

    pip install azure-iot-device
    
  6. Run the Python sample code in provision_symmetric_key.py.

    python provision_symmetric_key.py
    
  7. You should now see something similar to the following output. Some example wind speed telemetry messages are also sent to the hub as a test.

    D:\azure-iot-sdk-python\samples\async-hub-scenarios>python provision_symmetric_key.py
    The complete registration result is
    sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6
    contoso-hub-2.azure-devices.net
    initialAssignment
    null
    Will send telemetry from the provisioned device
    sending message #1
    sending message #2
    sending message #3
    sending message #4
    sending message #5
    sending message #6
    sending message #7
    sending message #8
    sending message #9
    sending message #10
    done sending message #1
    done sending message #2
    done sending message #3
    done sending message #4
    done sending message #5
    done sending message #6
    done sending message #7
    done sending message #8
    done sending message #9
    done sending message #10
    

The sample provisioning code accomplishes the following tasks, in order:

  1. Authenticates your device with your Device Provisioning resource using the following four parameters:

    • GLOBAL_ENDPOINT
    • SCOPE_ID
    • REGISTRATION_ID
    • SYMMETRIC_KEY
  2. Assigns the device to the IoT hub already linked to your Device Provisioning Service instance.

  3. Sends a test telemetry message to the IoT hub.

To update and run the provisioning sample with your device information:

  1. In the main menu of your Device Provisioning Service, select Overview.

  2. Copy the ID Scope value.

    Screenshot that shows copying the ID scope from the DPS overview pane.

  3. Open the Java device sample code for editing. The full path to the device sample code is:

    azure-iot-sdk-java/provisioning/provisioning-samples/provisioning-symmetrickey-individual-sample/src/main/java/samples/com/microsoft/azure/sdk/iot/ProvisioningSymmetricKeyIndividualEnrollmentSample.java

  4. Set the value of the following variables for your DPS and device enrollment:

    • Replace [Your scope ID here] with the ID Scope that you copied from the Azure portal.
    • Replace [Your Provisioning Service Global Endpoint here] with the Global device endpoint: global.azure-devices-provisioning.net. This endpoint is the same for all DPS instances.
    • Replace [Enter your Symmetric Key here] with the derived device key that you generated in Derive a device key.
    • Replace [Enter your Registration ID here] with the registration ID that you chose in Choose a unique registration ID for the device.
    private static final String SCOPE_ID = "[Your scope ID here]";
    private static final String GLOBAL_ENDPOINT = "[Your Provisioning Service Global Endpoint here]";
    private static final String SYMMETRIC_KEY = "[Enter your Symmetric Key here]";
    private static final String REGISTRATION_ID = "[Enter your Registration ID here]";
    

    Caution

    Be aware that this step leaves the derived device key included as part of the image for each device, which isn't a recommended security best practice. This is one reason why security and ease-of-use are often tradeoffs. You must fully review the security of your devices based on your own requirements.

  5. Open a command prompt for building. Go to the provisioning sample project folder of the Java SDK repository.

    cd azure-iot-sdk-java\provisioning\provisioning-device-client-samples\provisioning-symmetrickey-individual-sample
    
  6. Build the sample.

    mvn clean install
    
  7. Go to the target folder and execute the created .jar file. In the java command, replace the {version} placeholder with the version in the .jar filename on your machine.

    cd target
    java -jar ./provisioning-symmetrickey-individual-sample-{version}-with-deps.jar
    
  8. You should now see something similar to the following output.

    Starting...
    Beginning setup.
    WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.
    2022-10-07 18:14:48,388 DEBUG (main) [com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClient] - Initialized a ProvisioningDeviceClient instance using SDK version 2.0.2
    2022-10-07 18:14:48,390 DEBUG (main) [com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClient] - Starting provisioning thread...
    Waiting for Provisioning Service to register
    2022-10-07 18:14:48,392 INFO (global.azure-devices-provisioning.net-002edcf5-CxnPendingConnectionId-azure-iot-sdk-ProvisioningTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.ProvisioningTask] - Opening the connection to device provisioning service...
    2022-10-07 18:14:48,518 INFO (global.azure-devices-provisioning.net-002edcf5-Cxn002edcf5-azure-iot-sdk-ProvisioningTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.ProvisioningTask] - Connection to device provisioning service opened successfully, sending initial device registration message
    2022-10-07 18:14:48,521 INFO (global.azure-devices-provisioning.net-002edcf5-Cxn002edcf5-azure-iot-sdk-RegisterTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.RegisterTask] - Authenticating with device provisioning service using symmetric key
    2022-10-07 18:14:49,252 INFO (global.azure-devices-provisioning.net-002edcf5-Cxn002edcf5-azure-iot-sdk-ProvisioningTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.ProvisioningTask] - Waiting for device provisioning service to provision this device...
    2022-10-07 18:14:49,253 INFO (global.azure-devices-provisioning.net-002edcf5-Cxn002edcf5-azure-iot-sdk-ProvisioningTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.ProvisioningTask] - Current provisioning status: ASSIGNING
    2022-10-07 18:14:52,459 INFO (global.azure-devices-provisioning.net-002edcf5-Cxn002edcf5-azure-iot-sdk-ProvisioningTask) [com.microsoft.azure.sdk.iot.provisioning.device.internal.task.ProvisioningTask] - Device provisioning service assigned the device successfully
    IotHUb Uri : contoso-hub-2.azure-devices.net
    Device ID : sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6
    2022-10-07 18:14:58,424 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
    2022-10-07 18:14:58,436 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
    2022-10-07 18:14:58,440 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Initialized a DeviceClient instance using SDK version 2.1.1
    2022-10-07 18:14:58,450 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - Opening MQTT connection...
    2022-10-07 18:14:58,471 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT CONNECT packet...
    2022-10-07 18:14:59,314 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT CONNECT packet was acknowledged
    2022-10-07 18:14:59,315 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT SUBSCRIBE packet for topic devices/sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6/messages/devicebound/#
    2022-10-07 18:14:59,378 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT SUBSCRIBE packet for topic devices/sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6/messages/devicebound/# was acknowledged
    2022-10-07 18:14:59,379 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - MQTT connection opened successfully
    2022-10-07 18:14:59,381 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - The connection to the IoT Hub has been established
    2022-10-07 18:14:59,383 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Updating transport status to new status CONNECTED with reason CONNECTION_OK
    2022-10-07 18:14:59,389 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceIO] - Starting worker threads
    2022-10-07 18:14:59,392 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Invoking connection status callbacks with new status details
    2022-10-07 18:14:59,395 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Client connection opened successfully
    2022-10-07 18:14:59,404 INFO (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Device client opened successfully
    Sending message from device to IoT Hub...
    2022-10-07 18:14:59,408 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Message was queued to be sent later ( Message details: Correlation Id [32cf12c4-4db1-4562-9d8c-267c0506636f] Message Id [2e1717be-cfcf-41a7-b1c0-59edeb8ea865] )
    Press any key to exit...
    2022-10-07 18:14:59,409 DEBUG (contoso-hub-2.azure-devices.net-sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6-c32c76d0-Cxn0e70bbf7-8476-441d-8626-c17250585ee6-azure-iot-sdk-IotHubSendTask) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Sending message ( Message details: Correlation Id [32cf12c4-4db1-4562-9d8c-267c0506636f] Message Id [2e1717be-cfcf-41a7-b1c0-59edeb8ea865] )
    2022-10-07 18:14:59,777 DEBUG (MQTT Call: sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - IotHub message was acknowledged. Checking if there is record of sending this message ( Message details: Correlation Id [32cf12c4-4db1-4562-9d8c-267c0506636f] Message Id [2e1717be-cfcf-41a7-b1c0-59edeb8ea865] )
    2022-10-07 18:14:59,779 DEBUG (contoso-hub-2.azure-devices.net-sn-007-888-abc-mac-a1-b2-c3-d4-e5-f6-c32c76d0-Cxn0e70bbf7-8476-441d-8626-c17250585ee6-azure-iot-sdk-IotHubSendTask) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Invoking the callback function for sent message, IoT Hub responded to message ( Message details: Correlation Id [32cf12c4-4db1-4562-9d8c-267c0506636f] Message Id [2e1717be-cfcf-41a7-b1c0-59edeb8ea865] ) with status OK
    Message received! Response status: OK
    

Confirm your device provisioning registration

In this tutorial, you used the Static configuration allocation policy to assign devices that register through the enrollment group to the same IoT hub. However, for allocations where a device might be provisioned to one of several IoT hubs, you can examine the enrollment group's registration records to see which IoT hub the device was provisioned to:

  1. In the Azure portal, go to your DPS instance.

  2. In the Settings menu, select Manage enrollments.

  3. Select Enrollment groups.

  4. Select the enrollment group you created for this tutorial.

  5. On the Enrollment Group Details page, select Registration status.

  6. Find the device ID for your device Device Id column and note down the IoT hub in the Assigned IoT hub column.

    You can select the device record to see more details like the initial twin assigned to the device.

To verify the device on your IoT hub:

  1. In the Azure portal, go to the IoT hub that your device was assigned to.

  2. In the Device management menu, select Devices.

  3. If your device was provisioned successfully, its device ID should appear in the list, with Status set as enabled. If you don't see your device, select Refresh.

    Device is registered with the IoT hub

Note

If you changed the initial device twin state from the default value in the enrollment group, a device can pull the desired twin state from the hub and act accordingly. For more information, see Understand and use device twins in IoT Hub.

Provision more devices

To provision more devices through the enrollment group, follow the steps in the preceding sections to:

  1. Choose a unique registration ID for the device.

  2. Derive a device key. As you did previously, use the primary key for the enrollment group as the group key.

  3. Run the device provisioning code. Replace the necessary artifacts with your new derived device key and registration ID.

Clean up resources

If you plan to continue working on and exploring the device client sample, don't clean up the resources created in this tutorial. If you don't plan to continue, use the following steps to delete all resources created in this tutorial.

Delete your enrollment group

Deleting an enrollment group doesn't delete the registration records associated with it. These orphaned records count against the registrations quota for the DPS instance. For this reason, it's a best practice to delete all registration records associated with an enrollment group before you delete the enrollment group itself.

  1. In the Azure portal, go to your DPS instance.

  2. In the Settings menu, select Manage enrollments.

  3. Select the Enrollment groups tab.

  4. Select the name of the enrollment group you used for this tutorial to open its details page.

  5. On the Enrollment details page, select Registration status. Then select the check box next to the Device Id column header to select all of the registration records for the enrollment group. Select Delete at the top of the page to delete the registration records.

  6. Go back to the Manage enrollments page.

  7. Select the check box next to the name of the enrollment group you used for this tutorial.

  8. At the top of the page, select Delete.

Delete device registrations from IoT Hub

  1. In the Azure portal, go to the IoT hub that your device was assigned to.

  2. Select Devices from the Device management section of the navigation menu.

  3. Select the check box next to the device ID of the devices you registered in this tutorial.

  4. At the top of the page, select Delete.

Next steps

In this tutorial, you provisioned multiple devices to a single IoT hub using an enrollment group. Next, learn how to provision IoT devices across multiple hubs.