# iot-device-bridge This repository contains the components library and a running application in Rust for IoT MQTT messaging, Fleet Provisioning and Device Shadow. ## IoT Bridge Design ![IoT Bridge Design](IoT_Bridge.png) The graphics shows the basic design, where the currently implemented components are indicated with continuous lines. These components implement following functionality: - basic configuration operations (configuration attributes stored in config.yaml file) - basic message client operations: - connect to cloud IoT (AWS IoT Core or alternate system) - connect to device via MQTT (it can be extended to other messaging system like AMQP, DDS/ROS2) - listen to incoming events - subscribe to topic - publish to topic - fleet provisioning implementing AWS "Provisioning by Claim" workflow with CreateCertificateFromCsr - basic device adapter operations - mapping of device event topics to IoT topics - filtering device incoming events - standardize the message format to standard (cloudevents.io) with extensions - device shadows (AWS) - `device_shadow` - setting rules for events mapping - setting rules for events filtering - `iot_shadow` - certificate rotation request (by setting the parameter in the cloud shadow the IoT Bridge starts CSR based certificate renewal) - cryptographic information about method and ciphers for _payload encryption_ (tbi when applicable) - cryptographic information about method and ciphers for _payload anonymization_ (tbi when applicable) For details see the _IoT Bridge code documentation_ at artifacts download. ### IoT Bridge Tasks Interaction The IoT Bridge uses extensively the asynchronous multi-thread processing. The task interactions are summarized in the graphic below. **This is a `mermaid` drawing well visible in markdown of Gitlab and Github but not in some other environments, like `crates.io`.** _Remark: The `device_interface` and `iot_interface` are not explicit IoT Bridge tasks, but rather the corresponding connections to the corresponding messaging interfaces._ ```mermaid sequenceDiagram participant DI as device_interface participant DM as device_monitor_thread participant DR as device_receiver_thread participant DS as device_shadow_thread participant IS as iot_shadow_thread participant IT as iot_transmitter_thread participant IR as iot_receiver_thread participant IM as iot_monitor_thread participant II as iot_interface II-)IM: receive MQTT message IM-)IR: receive event IR->>IR: connector_aws::on_iot_event alt event for IoT Shadow IR-)IT: send response to IoT IR-)IS: send shadow value IS->>IS: trigger cert rotation else event for Device Shadow IR-)IT: send response to IoT IR-)DS: send shadow value DS->>DS: device_adapter::on_receive_device_shadow end DI-)DM: receive MQTT message DM-)DR: receive event DR->>DR: device_adapter::on_device_event DR-)IT: send device message to IoT IT-)II: send MQTT device message to IoT ``` ## Device Shadow Interaction Based on the Reference Architecture in [DEVICE SHADOWS - MQTT TOPICS](https://iotatlas.net/en/implementations/aws/device_state_replica/device_state_replica1/). This implementation differentiates between the Device State (an object as Rust `struct`) and the Local Shadow (a copy of Device State as `serde_json::Value` with additional info) The sequence diagram below covers the main "positive" cases (i.e., no rejection). _**Observation: UPDATE_DELTA is not send when the value of an attribute is set to `null`.**_ ```mermaid sequenceDiagram participant D as Device State participant I as IoT Bridge participant L as Shadow @ Device participant R as Shadow @ Cloud participant C as Cloud Application Note right of L: Shadow Subscription L-)R: SUBSCRIBE (UPDATE_ACCEPTED, UPDATE_REJECTED, UPDATE_DELTA) Note right of L: Fleet Provisioning I-)R: UPDATE[reported] (Initialize IoT Bridge / Connector State Shadow at Provisioning with Defaults) I-)R: UPDATE[desired & reported] (Initialize Device State Shadow at Provisioning with Defaults) R-)L: UPDATE_ACCEPTED (Device State) L->>D: Transform & Store Note right of L: IoT Bridge Start I-)R: UPDATE[reported] (Send IoT Bridge / Connector State) L-)R: GET (Get Device State Shadow at Start) R-)L: GET_ACCEPTED L->>D: Transform & Store Note right of L: Change by Cloud Application (filtering / mapping) C->>R: UPDATE[desired] (filter/map change) R-)L: UPDATE_DELTA (Device State Shadow) par Shadow@Device to Shadow@Cloud L-)R: UPDATE[reported] (Device State Shadow) and Shadow@Device to Device State L-)D: Transform & Store end Note right of L: Certificate Rotation by Cloud Application C->>R: UPDATE[desired] (cert rotation request) R-)L: UPDATE_DELTA (IoT Bridge / Connector State Shadow) par Shadow@Device to Shadow@Cloud L-)R: UPDATE[reported] (IoT Bridge / Connector State Shadow) and Shadow@Device to IoT Bridge / Connector L-)I: Initiate Certificate Rotation end I->>I: Execute Certificate Rotation ``` ## IoT Bridge Configuration The IoT Bridge configuration section `device` is specific for the device and will not be discussed here. The `iot` section configures the connectivity to the IoT infrastructure -- below focusing on the AWS solutions. All values below are placeholders only -- replace with your proprietary values. ### IoT Connectivity These elements can be left as defined if not specific requirements need to be considered. ```yaml shadow_name: iot_shadow client_registration_status: INITIAL ca_path: AmazonRootCA1.pem ``` The elements below are specific to the IoT connection of a group / a fleet of devices: ```yaml iot_topic_prefix: SPDIF/X320/16A8/ client_id: 16A8_99998 endpoint: ENDPOINTID-ats.iot.eu-central-1.amazonaws.com port: 8883 ``` ### Fleet Provisioning For the AWS Fleet Provisioning the listed below elements of the configuration should be prepared and stored correspondingly, e.g., in the `device-iot.config/certs` folder: ```yaml claim_cert_path: ClaimCertificate.pem claim_priv_key_path: ClaimPrivateKey.pem claim_pub_key_path: ClaimPubKey.pem ``` Additionally the Fleet Provisioning template is required and should be referenced (e.g., `provisioning_template_name: iot-16A8-prov-templ`) and the corresponding provisioning policies and device policies defined. See AWS documentation for details. The registration status `client_registration_status: INITIAL` triggers the Fleet Provisioning. After successful registration the state changes to `REGISTERED:thingname` The below listed client (device instance) specific elements will be generated during the Fleet Provisioning ```yaml client_cert_path: IotCertificate.pem client_priv_key_path: IotPrivateKey.pem client_pub_key_path: IotPubKey.pem ``` ### Data Payload Encryption In environments demanding high confidentiality a _data payload encryption_ may be required in addition to using secure channels (like mTLS). It is particularly interesting for end-to-end confidentiality between the source (device) and the receiver of the events. Functionality implementing the data payload encryption uses ECIES (Elliptic Curve Integrated Encryption Scheme) built upon AES-GCM-256 and HKDF-SHA256 and using the secp256k1 curve. The method is implemented in interoperable libraries in Golang, Python, Rust and Typescript ... i.e., these languages used also in the backend (e.g., the decryption lambda in Golang -- see `decryption-lambda-go` in the testing folder). This encryption framework is standardized as: ISO/IEC 18033-2:2006 and also described in the chapter 5.1 in the [Standards for Efficient Cryptography Group](https://www.secg.org/sec1-v2.pdf). The encryption can be "switched-on/-off" and the public keys should be distributed using the IotShadow, e.g.: ```json { "iot_registration_status": { "Registered": "98765" }, "data_encryption_config": { "method": "EciesSecp256k1", "public_key": [ 4,89,117,155,81,243,172,179, 90,195,137,53,151,179,94,29, 83,81,109,41,239,43,231,104, 14,189,163,2,229,86,3,148, 164,194,250,198,166,60,62,162, 124,188,178,137,87,61,52,245, 18,210,207,175,130,234,120,161, 45,205,156,7,34,37,164,106, 128 ] } } ``` _Remark: The secrets are obviously stored in secure facilities, like the AWS Secret Manager._