If you want to retrieve desired properties or report any change to a Device Twin and you have a Edge device auto-provisioned with TPM, you will need to properly instantiate a DeviceClient: this blog post is for you!
To date (12 february 2019) there is not a documented way to create, in a IoT Edge module, a DeviceClient to access twin properties.
If you have a Edge device DPS enrolled with TPM attestation, these are the steps to securely access your TPM and properly create a DeviceClient:
- Create a group and a user on host OS. Then give permissions to access the TPM
- Modify the Dockerfile to run Edge Module as the newly created user
- Implement the module code to instantiate a DeviceClient using TPM
- Specify proper DeviceMapping in createOptions section of your deployment.json
- only for ARM32 based device with a C# Edge Module: Rebuild TSS.NET and properly reference it in your custom Microsoft.Azure.Devices.Provisioning.Security.Tpm.csproj
1. Create a group and a user on host OS. Then give permissions to access the TPM
If you followed this doc in order to give IoT Edge access to the TPM, you may have given TPM access to the iotedge group.
Unfortunately this group could have a different gid across all your installations, making it very hard to manage the match between the “host user” and “container user”.
That’s why, I suggest you to:
- manually create a group (tpmusers in the example)
- add the iotedge user to the newly created group (the -a flag is crucial to keep the existing groups linked to iotedge user)
- create a user with a fixed uid and add it to the previously created group
The next step, in order to give tpmusers the access to the TPM, is to modify the group in the previously created tpmaccess.rules file
2. Modify the Dockerfile to run Edge Module as the newly created user
Everything is ready, host OS side, for your module to run command and access the tpm as tpmuser1 user.
We need now to create a user inside the container, matching uid and gid of the ones created in the previous step:
3. Implement the module code to instantiate a DeviceClient using TPM
If you are developing a Node.js module, your code will contain something like this:
Else if you are developing a C# module, your code will probably look like this:
4. Specify proper DeviceMapping in createOptions section of your deployment.json
The IoT Hub Client SDK will try to access /dev/tpm0 in order to instantiate a DeviceClient.
You need to bind your TPM device inside the container and, in order to achieve this goal, you can modify the createOptions of your IoT Edge Module like this:
5. only for ARM32 based device with a C# Edge Module: Rebuild TSS.NET and properly reference it in your custom Microsoft.Azure.Devices.Provisioning.Security.Tpm.csproj
Microsoft.Azure.Devices.Provisioning.Security.Tpm is the NuGet package responsible of accessing the TPM.
To date, this is relying on Microsoft.TSS NuGet package (v.2.0.1).
Microsoft.TSS has, in it, only binaries compiled for linux-x64. For this reason, when doing “dotnet publish -c Release -o out -r linux-arm” in Dockerfile.arm32v7, it is possible that .NET Standard binary is picked up for your ARM32.
If that happens, when trying to access the TPM, you will receive a “System.DllNotFoundException” complaining about missing ‘bcrypt.dll’. (.NET Standard library was compiled with different defines: see here the TSS_USE_BCRYPT and its usage in the code)
Some Microsoft colleagues were alerted of this issue, to fix it as soon as possible.
In the meanwhile, in order to make it work:
- Locally clone TSS.MSR and azure-iot-sdk-csharp
- in /TSS.NET/TSS.Net/TSS.Net.csproj change this:
- Reference the TSS.Net.csproj in Microsoft.Azure.Devices.Provisioning.Security.Tpm
- Manually reference Microsoft.Azure.Devices.Provisioning.Security.Tpm.csproj in your project (remember to remove the NuGet package reference)
- Your Dockerfile has to “dotnet publish -c Release -o out -r linux-arm“
- Optional: if you do not want to rebuild dependencies every time, you can setup a private NuGet Feed in Azure DevOps where to store the packages and then reference your own Microsoft.Azure.Devices.Provisioning.Security.Tpm in edge module .csproj. Furthermore when doing this, remember to copy NuGet.Config before doing a dotnet restore in Dockerfile