.. _lib_aws_iot: AWS IoT ####### .. contents:: :local: :depth: 2 The Amazon Web Services Internet-of-Things (AWS IoT) library enables applications to connect to, and exchange messages with the `AWS IoT Core`_ service. The library supports the following technologies: * TLS secured MQTT transmission protocol * Firmware-Over-The-Air (FOTA) .. _aws_setup_and_configuration: Setup and configuration *********************** To connect a device to AWS IOT Core, complete the following steps: 1. :ref:`aws_setup_and_permissions` #. :ref:`generating_and_provisioning_certificates` #. :ref:`creating_a_policy` #. :ref:`creating_a_thing` #. :ref:`Configuring the library ` .. rst-class:: numbered-step .. _aws_setup_and_permissions: Setting up AWS and configuring permissions ========================================== The initial AWS account setup required for using AWS IoT Core is described in `Set up your AWS account`_. For development purposes, the AWS managed policies ``AWSIoTConfigAccess`` and ``AWSIoTDataAccess`` provide sufficient permissions to manage AWS IoT. If you want to use AWS FOTA, the ``AmazonS3FullAccess`` policy can be used to obtain access to AWS S3. .. note:: These policies provide a large number of permissions to the user. Though this can be acceptable for development purposes, you should operate on a least-privilege principle whenever possible. To complete the steps described in this document, make sure that the following prerequisites are met: * Install `AWS Command Line Interface`_ on your system and login as a user with appropriate permissions. * To use the ``nrfcredstore`` tool, the dependencies in the :file:`nrf/scripts/requirements-extra.txt` file must be installed. .. rst-class:: numbered-step .. _generating_and_provisioning_certificates: Generating and provisioning certificates ======================================== *Things* in AWS IoT are typically authenticated using device certificates. There are multiple ways to generate and register these certificates: * The device key pair and certificate are generated by AWS and downloaded onto the device. * The device generates the key pair and a Certificate Signing Request (CSR). This request is uploaded to AWS to obtain a device certificate and is used to generate a self-signed device certificate. .. tabs:: .. tab:: nRF91: Keys generated on device .. note:: Generating a key pair on device requires an nRF91 Series device. If you are using an nRF9160 DK, modem version v1.3.x or later is required. .. important:: Program the :ref:`at_client_sample` sample to your device before following this guide. Complete the following steps to generate a key pair and CSR on the modem, which is then used to obtain a device certificate signed by AWS: 1. Obtain a list of installed keys using the following command: .. code-block:: console nrfcredstore list where ```` is the serial port of your device. #. Select a security tag that is not yet in use. This security tag must match the value set in the :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option. #. Generate a key pair and obtain a CSR using the following command: .. code-block:: console nrfcredstore generate device_cert.csr.der |serial_port_sec_tag| #. Convert the CSR from DER format to PEM format using the following command: .. code-block:: console openssl req -inform DER -in device_cert.csr.der -outform PEM -out device_cert.csr.pem #. Obtain a signed certificate using the following command: .. code-block:: console aws iot create-certificate-from-csr --certificate-signing-request file://device_cert.csr.pem --certificate-pem-outfile device_cert.pem --set-as-active --no-cli-pager --query certificateArn #. Take note of the certificate ARN, as it will be required later. #. Provision the certificate using the following command: .. code-block:: console nrfcredstore write CLIENT_CERT device_cert.pem |serial_port_sec_tag| #. Download the `Amazon Root CA 1`_ PEM file. #. Provision the certificate using the following command: .. code-block:: console nrfcredstore write ROOT_CA_CERT AmazonRootCA1.pem |serial_port_sec_tag| .. tab:: nRF91: Keys generated by AWS .. warning:: This option is not recommended for production scenarios, since the private key leaves the device. .. important:: Program the :ref:`at_client_sample` sample to your device before following this guide. To obtain a key pair and certificate generated by AWS, and to provision them to the modem, complete the following steps: 1. Generate the key pair and certificate using the following command: .. code-block:: console aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile device_cert.pem --public-key-outfile pub_key.pem --private-key-outfile priv_key.pem --no-cli-pager --query certificateArn #. Take note of the certificate ARN, as it will be required later. #. Obtain a list of installed keys using the following command: .. code-block:: console nrfcredstore list where ```` corresponds to the serial port of your device. #. Select a security tag that is not yet in use. This security tag must match the value set in :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option. #. Provision the client certificate using the following command: .. code-block:: console nrfcredstore write CLIENT_CERT device_cert.pem |serial_port_sec_tag| #. Provision the client key using the following command: .. code-block:: console nrfcredstore write CLIENT_KEY priv_key.pem |serial_port_sec_tag| #. Download the `Amazon Root CA 1`_ PEM file. #. Provision the certificate using the following command: .. code-block:: console nrfcredstore write ROOT_CA_CERT AmazonRootCA1.pem |serial_port_sec_tag| .. tab:: nRF70: Keys generated by AWS To obtain a key pair and certificate generated by AWS, complete the following steps: 1. Generate the key pair and certificate using the following command: .. code-block:: console aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile client-cert.pem --public-key-outfile public-key.pem --private-key-outfile private-key.pem --no-cli-pager --query certificateArn #. Take note of the certificate ARN, as it will be required later. #. Download the `Amazon Root CA 1`_ PEM file as :file:`ca-cert.pem`. #. Place the PEM files into the folder path specified by the :kconfig:option:`CONFIG_MQTT_HELPER_CERTIFICATES_FOLDER` option, default is :file:`/certs/`. Ensure that the :kconfig:option:`CONFIG_MQTT_HELPER_PROVISION_CERTIFICATES` option is set. #. If the files are placed correctly, the :ref:`lib_mqtt_helper` library finds the certificates and provisions them to the Mbed TLS stack when connecting to AWS IoT. .. rst-class:: numbered-step .. _creating_a_policy: Creating a policy ================= AWS IoT Core policies determine which permissions a *Thing* has and are required to connect to the AWS IoT data plane. To create a policy, complete these steps: 1. Create a file :file:`policy.json` with the following content: .. code-block:: javascript { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:*", "Resource": "*" } ] } .. note:: This policy example is only intended for development environments. Make sure to update this to a more restrictive policy before you go into production. For more information, refer to the example policies listed in `AWS IoT Core policy examples`_ and `Security best practices in AWS IoT Core`_. #. Create the policy using the following command: .. code-block:: console aws iot create-policy --policy-name my-policy --policy-document file://policy.json #. Attach the policy to the previously registered certificate using the following command: .. code-block:: console aws iot attach-policy --target --policy-name my-policy where ```` is the ARN of the previously generated device certificate. .. rst-class:: numbered-step .. _creating_a_thing: Creating a Thing ================ Create a *Thing* in AWS IoT core by completing the following steps: 1. Create a *Thing* using the following command: .. code-block:: console aws iot create-thing --thing-name where ```` is the desired name for the *Thing*, for example, ``my-thing``. #. Attach the certificate to the *Thing* using the following command: .. code-block:: console aws iot attach-thing-principal --principal --thing-name where ```` is the ARN of the previously generated device certificate and ```` is the previously chosen name of the *Thing*. .. rst-class:: numbered-step .. _configuring_the_library: Configuring the library ======================= Complete the following steps to set the required library options: 1. Obtain the AWS IoT broker endpoint using the following command: .. code-block:: console aws iot describe-endpoint --endpoint-type iot:Data-ATS #. Set the :kconfig:option:`CONFIG_AWS_IOT_BROKER_HOST_NAME` Kconfig option to the obtained endpoint value. For information on how to set this value at runtime, refer to :ref:`lib_set_aws_hostname`. #. Set the :kconfig:option:`CONFIG_AWS_IOT_CLIENT_ID_STATIC` Kconfig option to the name of the *Thing* created earlier. For information on how to set this value at runtime, refer to :ref:`lib_set_client_id`. #. Set the :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` to the security tag for which the key and certificate were provisioned earlier. Optional library options ------------------------ To subscribe to the various `AWS IoT Device Shadow Topics`_ , set the following options: * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_GET_ACCEPTED_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_GET_REJECTED_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_UPDATE_ACCEPTED_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_UPDATE_REJECTED_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_UPDATE_DELTA_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_DELETE_ACCEPTED_SUBSCRIBE` * :kconfig:option:`CONFIG_AWS_IOT_TOPIC_DELETE_REJECTED_SUBSCRIBE` Other options: * :kconfig:option:`CONFIG_AWS_IOT_BROKER_HOST_NAME` * :kconfig:option:`CONFIG_AWS_IOT_CLIENT_ID_STATIC` * :kconfig:option:`CONFIG_AWS_IOT_CLIENT_ID_MAX_LEN` * :kconfig:option:`CONFIG_AWS_IOT_CONNECT_TIMEOUT_SECONDS` * :kconfig:option:`CONFIG_AWS_IOT_AUTO_DEVICE_SHADOW_REQUEST` MQTT helper library specific options: * :kconfig:option:`CONFIG_MQTT_HELPER_SEND_TIMEOUT` * :kconfig:option:`CONFIG_MQTT_HELPER_SEND_TIMEOUT_SEC` * :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` * :kconfig:option:`CONFIG_MQTT_HELPER_SECONDARY_SEC_TAG` * :kconfig:option:`CONFIG_MQTT_HELPER_PORT` * :kconfig:option:`CONFIG_MQTT_HELPER_RX_TX_BUFFER_SIZE` * :kconfig:option:`CONFIG_MQTT_HELPER_PAYLOAD_BUFFER_LEN` * :kconfig:option:`CONFIG_MQTT_HELPER_STACK_SIZE` * :kconfig:option:`CONFIG_MQTT_HELPER_NATIVE_TLS` * :kconfig:option:`CONFIG_MQTT_HELPER_LAST_WILL` * :kconfig:option:`CONFIG_MQTT_HELPER_LAST_WILL_TOPIC` * :kconfig:option:`CONFIG_MQTT_HELPER_LAST_WILL_MESSAGE` .. note:: If you are using a longer client ID that is either set by the option :kconfig:option:`CONFIG_AWS_IOT_CLIENT_ID_STATIC` or passed in during connect, it might be required to increase the value of the option :kconfig:option:`CONFIG_AWS_IOT_CLIENT_ID_MAX_LEN` to reserve enough space for the client ID string. .. _aws_iot_usage: Usage ***** The :ref:`aws_iot` sample showcases the use of this library and can be used to verify a connection to AWS IoT. To configure and run the sample, complete the steps described in :ref:`aws_iot_sample_server_setup` and :ref:`aws_iot_sample_building_and_running`. Initializing the library ======================== The library is initialized by calling the :c:func:`aws_iot_init` function. If this API call fails, the application must not make any other API calls to the library. Connecting to the AWS IoT MQTT broker ===================================== After the initialization, the :c:func:`aws_iot_connect` function must be called to connect to the AWS IoT broker. If this API call fails, the application must retry the connection by calling :c:func:`aws_iot_connect` again. .. note:: The connection attempt can fail due to several reasons related to the network. Due to this its recommended to implement a routine that tries to reconnect the device upon a disconnect. During an attempt to connect to the AWS IoT broker, the library tries to establish a connection using a TLS handshake, which usually spans a few seconds. When the library has established a connection and subscribed to all the configured and passed-in topics, it will propagate the :c:enumerator:`AWS_IOT_EVT_CONNECTED` event to signify that the library is connected and ready to be used. Subscribing to non-AWS specific topics ====================================== To subscribe to non-AWS specific topics, pass a list containing the topics using the :c:func:`aws_iot_application_topics_set` function before calling the :c:func:`aws_iot_connect` function. The following code example shows how to subscribe to non-AWS specific topics: .. code-block:: c #define CUSTOM_TOPIC_1 "my-custom-topic/example" #define CUSTOM_TOPIC_2 "my-custom-topic/example2" static const struct mqtt_topic topic_list[] = { { .topic.utf8 = MY_CUSTOM_TOPIC_1, .topic.size = strlen(MY_CUSTOM_TOPIC_1), .qos = MQTT_QOS_1_AT_LEAST_ONCE, }, { .topic.utf8 = MY_CUSTOM_TOPIC_2, .topic.size = strlen(MY_CUSTOM_TOPIC_2), .qos = MQTT_QOS_1_AT_LEAST_ONCE, } }; err = aws_iot_application_topics_set(topic_list, ARRAY_SIZE(topic_list)); if (err) { LOG_ERR("aws_iot_application_topics_set, error: %d", err); FATAL_ERROR(); return err; } Publishing to non-AWS specific topics ===================================== To publish to a non-AWS specific topic, complete the following steps: * Populate a :c:struct:`aws_iot_topic_data` with the custom topics that you want to publish to. It is not necessary to set the topic type when populating the :c:struct:`aws_iot_topic_data` structure. This type is reserved for AWS IoT shadow topics. * Pass in the entry that corresponds to the topic that the payload is to be published to in the message structure :c:struct:`aws_iot_data`. This structure is then passed into the :c:func:`aws_iot_send` function. The following code example shows how to publish to non-AWS specific topics: .. code-block:: c #define MY_CUSTOM_TOPIC_1 "my-custom-topic/example" #define MY_CUSTOM_TOPIC_1_IDX 0 static struct aws_iot_topic_data pub_topics[1] = { [MY_CUSTOM_TOPIC_1_IDX].str = MY_CUSTOM_TOPIC_1, [MY_CUSTOM_TOPIC_1_IDX].len = strlen(MY_CUSTOM_TOPIC_1), }; struct aws_iot_data msg = { /* Pointer to payload */ .ptr = buf, /* Length of payload */ .len = len, /* Message ID , if not set it will be provided by the AWS IoT library */ .message_id = id, /* Quality of Service level */ .qos = MQTT_QOS_0_AT_MOST_ONCE, /* "my-custom-topic/example" */ .topic = pub_topics[MY_CUSTOM_TOPIC_1_IDX] }; err = aws_iot_send(&msg); if (err) { LOG_ERR("aws_iot_send, error: %d", err); return err; } .. _lib_set_client_id: Setting client ID at run-time ============================= The library supports passing in the client ID at runtime. To use this feature, set the ``client_id`` entry in the :c:struct:`aws_iot_config` structure that is passed in the :c:func:`aws_iot_connect` function when connecting. The ``client_id`` entry must be a null-terminated string. .. _lib_set_aws_hostname: Setting the AWS host name at runtime ==================================== The library supports passing in the endpoint URL at runtime. To use this feature, set the ``host_name`` entry in the :c:struct:`aws_iot_config` structure that is passed in the :c:func:`aws_iot_connect` function when connecting. The ``client_id`` entry must be a null-terminated string. .. _aws_iot_testing_and_debugging: Testing and debugging ===================== For general information about testing and debugging, see :ref:`testing`. Topic monitoring ---------------- To observe incoming messages, navigate to the `AWS IoT console`_ and click :guilabel:`MQTT test client`. Subscribe to the topic that you want to monitor, or use the wild card token **#** to monitor all topics. .. _aws_iot_troubleshooting: Troubleshooting =============== For issues related to the library and |NCS| in general, refer to :ref:`known_issues`. * If you are experiencing unexpected disconnects from AWS IoT, try decreasing the value of the :kconfig:option:`CONFIG_MQTT_KEEPALIVE` option or publishing data more frequently. AWS IoT specifies a maximum allowed keepalive of 1200 seconds (20 minutes), however in certain LTE networks, the Network Address Translation (NAT) timeout can be considerably lower. As a recommendation to prevent the likelihood of unexpected disconnects, set the option :kconfig:option:`CONFIG_MQTT_KEEPALIVE` to the highest value of the network NAT and maximum allowed MQTT keepalive. * If publishing larger payloads fails, you might need to increase the value of the :kconfig:option:`CONFIG_MQTT_HELPER_RX_TX_BUFFER_SIZE` option. * For nRF91 Series devices, the size of incoming messages cannot exceed approximately 2 kB. This is due to a limitation of the modem's internal TLS buffers. Messages that exceed this limitation will be dropped. AWS FOTA ======== The library supports FOTA using the :ref:`lib_aws_fota` library. This library can be enabled by setting the :kconfig:option:`CONFIG_AWS_FOTA` Kconfig option. To create a FOTA job, refer to the :ref:`lib_aws_fota` documentation. API documentation ***************** | Header file: :file:`include/net/aws_iot.h` | Source files: :file:`subsys/net/lib/aws_iot/src/` .. doxygengroup:: aws_iot :project: nrf :members: