Authenticating downstream devices with x.509 certificates

One of the most common scenarios in the industry is to provide one common interface/gateway for the devices to connect and send data to the cloud.
Some of the reasons for this might be:
– Devices do not have access to public network  all the time
– Protocol translations need to be done before data reaches cloud
– Identity translation needs to be done before data reaches cloud
– Data filtering and processing need to be done before data reaches cloud
– Security, updating, management etc.
Microsoft offers Azure IoT Edge as a powerful tool with huge potential as a solution for these scenarios.
This blog post will focus on a case where IoT Edge acts as a gateway which simply passes communications between the devices and IoT Hub.
This case in the official documentation is called ‘Transparent gateway’.
Picture 1.
For the testing purpose, end-to-end components are:
– Downstream device – generates messages
– IoT Edge as a gateway – passes communication between downstream device and IoT Hub
– Azure IoT Hub as a message broker and device management service
– Azure Function that consumes messages from IoT Hub for testing purposes

 Setting up IoT Edge

Below are the documentation steps required to take before writing any code:
1. Setup Azure IoT Edge on Linux Ubuntu 18.04 VM
2. In Azure Portal, create IoT Hub and add new Edge device with Symmetric key as AuthenticationType
   a) Copy the connection string
3. In Azure Portal, create two new devices one with “Sas” authentication type and the other one with CertificateAuthority authentication type
Picture 2
    a) Copy the “Sas” device connection string
4. Create certificates and use the deviceIds from steps 2. and 3. when creating the device and edge certificate
   a) Add Root certificate to IoT Hub  and follow the steps for the certificate verification
5. Make sure to store following certificates on the Linux VM on which IoT Edge is running:
– azure-iot-test-only.root.ca.cert.pem – Root Certificate
– new-edge-device.key.pem – Edge device private certificate
– new-edge-device-full-chain.cert.pem – Edge full chain certificate
6. Edit config.yaml file located in folder /etc/iotedge. Since this file is write protected, it is necessary to change the permissions.
sudo chmod +o+rw config.yaml
In order to edit the file it is possible to use the following command:
sudo nano config.yaml
7. Provisioning section in config.yaml should be:
provisioning:
   source: "manual"
   device_connection_string: "your_edge_device_connection_string_from_step_2a"
 8. Certificates section in config.yaml should look like:
certificates:
   device_ca_cert: "/path/to/cert/folder/new-edge-device-full-chain.cert.pem"
   device_ca_pk: "/path/to/cert/folder/new-edge-device.key.pem"
   trusted_ca_certs: "/path/to/cert/folder/azure-iot-test-only.root.ca.cert.pem"
9.  In Azure Portal routes should be set as:
{
  "routes": {
    "route": "FROM /* INTO $upstream"
  }
}
Picture 3
 
Follow the steps in Azure portal and finish the module deployment to the Edge device. After this step routes should be updated.
10. In order to double check if everything works fine, IoT Edge runtime can be restarted
sudo systemctl restart iotedge
and the following command should return status ‘Active’:
sudo systemctl status iotedge
Picture 4
Side note: It is required to make sure that the downstream device(host machine in this case) can ping the IoT Edge host. In case that ping is rejected, potentially it is required to check DNS settings.
At this point, IoT Edge is in place and works as a transparent gateway.

 Setting up the downstream device

As presented in Picture 1 in order to establish secure communication between the downstream device and Edge device it is necessary to install Root Certificate on the downstream device. This can be resolved in the code or simply by importing the certificate in the Certificate store. Downstream devices with “Sas” authentication type should contain similar code:
            var rootCertificatePath = Environment.GetEnvironmentVariable("CA_CERTIFICATE_PATH");
            // Add Root Certificate
            InstallCACert(certificatePath: rootCertificatePath);
            var deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString);
            if (deviceClient == null)
            {
                Console.WriteLine("Failed to create DeviceClient!");
            }
            else
            {
                SendEvents(deviceClient, MESSAGE_COUNT).Wait();
            }
CA_CERTIFICATE_PATH – path on the file system to root certificate
ConnectionString – Connection string retrieved from IoT Hub(step 3a) and attached ‘;GatewayHostName=hostname_from_config.yaml’. Without GatewayHostName messages would be sent directly to IoT Hub after initial authentication.
Running this code results in:
Picture 5. Downstream Device, Azure IoT Edge and Azure function outputs. Messages are passed through the Azure IoT Edge to IoT Hub and then consumed by Azure Function
 
With downstream devices with CA Authentication Type things are slightly different.
1. First, in Azure Portal and IoT Hub there must be a relation (parent-child) set between the edge device and downstream devices.
Side note: At the moment of writing this post documentation does not state if this is always required, even for “Sas” devices. For “Sas” devices it works without setting this, but for “CA” authentication type this is a must.
Picture 6.
This sets in the device twin of downstream device attribute called deviceScope which matches with the same attribute from the device twin of the edge device.
Picture 7.
 
 Side note:  At the moment of writing this post, there is no any kind of public API and SDK that would enable setting this attribute from the code. This is also a limitation for Device Provisioning Service, which is not able to provision downstream devices at the moment.
2. Root certificate but also Device Certificate need to be installed in the local certificate store. Also, gateway hostname needs to be specified:
            // Add Root Certificate
            InstallCACert(certificatePath: rootCertificatePath);
            // Add Leaf Device Certificate
            InstallCACert(certificatePath: leafCertificatePath,
                      certificatePassword: leafCertificatePassword);
            var certificate = new X509Certificate2(leafCertificatePath, leafCertificatePassword);
            var deviceAuthentication = new DeviceAuthenticationWithX509Certificate(deviceId, certificate);
            var deviceClient = DeviceClient.Create(hostname: iotHubHostName,
                                            gatewayHostname: gatewayHostName,
                                       authenticationMethod: deviceAuthentication,
                                              transportType: TransportType.Mqtt);
            if (deviceClient == null)
            {
                Console.WriteLine("Failed to create DeviceClient!");
            }
            else
            {
               SendEvents(deviceClient, MESSAGE_COUNT).Wait();
            }
Side note: x.509 authentication has been added by default as of IoT Edge v1.06. In version 1.05 this was not enabled by default and environment variable had to be added for Edge hub module:
Picture 8.
Picture 9.
 
The code is available on GitHub.

 

Conclusion

Azure IoT Edge evolved with features and capabilities. One of the features definitely is authentication of downstream devices with x.509 certificate, considering the fact that many IoT solutions that are using Azure IoT Edge, also have devices that are using certificates for authentication. It would be nice to have Device Provisioning Service as a next step to support the ‘zero-touch’ provisioning of downstream devices. That way we can have ‘zero-touch’ installations with downstream devices and IoT Edge gateways in the field. I believe that Microsoft is heading towards the ‘zero-touch’ provisioning concept. An expectation is that all pieces of information regarding relations between devices are synced with IoT Hub after initial authentication so that potential changes in the code are avoided during the installation in the field. Looking forward to new releases!

References

1. IoT Edge as a gateway: https://docs.microsoft.com/en-us/azure/iot-edge/iot-edge-as-gateway
2. Create a transparent gateway: https://docs.microsoft.com/en-us/azure/iot-edge/how-to-create-transparent-gateway
3. Connect downstream device: https://docs.microsoft.com/en-us/azure/iot-edge/how-to-connect-downstream-device
4. Setup x.509 security in IoT Hub: https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/iot-hub/iot-hub-security-x509-get-started.md
5. Connect a downstream device to an Azure IoT Edge Gateway: https://docs.microsoft.com/en-us/azure/iot-edge/how-to-connect-downstream-device

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: