The Internet of Things on AWS – Official Blog

Route messages across multiple accounts with AWS IoT Core and Amazon SQS

Introduction

In this blog, we explain how to route AWS IoT Core messages from one or more ingestion accounts to Amazon Simple Queue Service (Amazon SQS) in a data account. It is a common pattern to have IoT telemetry ingested into one account and then require it to be shipped to another account for further processing. For example, when an organization hosts devices in multiple accounts and the data being ingested is classified as both sensitive and operational. Sensitive data needs to be kept in the original collection account but operational data needs to be relayed to another account monitored by an operations team.

You will learn how to configure AWS IoT rules for cross-account access to route MQTT topic data sets into Amazon SQS. Rules for AWS IoT give your devices the ability to interact with AWS services. You can use rules to support tasks such as augmenting or filtering data from a device, writing data to database, publishing messages to Amazon SQS and more.  For a complete list of tasks you can perform, please refer to the Rules for AWS IoT section of the AWS IoT Core Developer Guide.

Solution Overview

In this solution, you will first create an Amazon SQS queue in the data account and grant permissions to the ingestion account to publish to it . Next, you will create AWS IoT rules and send messages to them to test.

  1. Create an Amazon SQS queue called iot-data in the data account and allow publishing to this queue from the ingestion account.
  2. In the ingestion account:
    a. Create an Identity and Access Management (IAM) role with a policy that allows publishing to Amazon SQS in the data account.
    b. Create an IAM role with a policy that allows a republish action for errors encountered when publishing to the SQS queue.
  3. Create an IoT rule in the ingestion account to evaluate messages from a topic called data/private and send them to the data account SQS queue. The rule will have an error action that republishes messages to the error/rules topic for troubleshooting.
  4. Publish messages to the MQTT topic data/private and verify the messages are visible in the data account SQS queue.

Solution Diagram

Solution architecture diagram

Solution Instructions

Prerequisites

  1. Two AWS accounts
  2. Administrator privileges in both accounts
  3. AWS Command Line Interface (AWS CLI)

Create an SQS queue in the data account

  1. Create a file named queue_attributes.json with the following content.
    { "MessageRetentionPeriod": "259200" }
  2. With the AWS CLI configured for the data account and using the create-queue.json file, create an SQS queue called iot-data.
    aws sqs create-queue \
         --queue-name iot-data \   
         --attributes file://queue_attributes.json
  3. Record the QueueURL from the output as that will be needed in the next section.
  4. To grant permissions for the Amazon SQS queue resource to be accessed by the ingestion account, run the add-permission command. Be sure to update the account numbers accordingly.
    aws sqs add-permission \
         --queue-url https://sqs.<data account region>.amazonaws.com/<data account ID>/iot-data \
         --label IoTSendMessage \
         --aws-account-ids <ingestion account ID> \
         --actions SendMessage

Create the AWS Identity and Access Management (IAM) role and policy for cross-account publishing to SQS

In order to publish to the SQS queue from the data account, you first need to allow that action.

  1. Create a file named iot_policy.json with the following content:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Service": "iot.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }
  2. With the AWS CLI configured for the ingestion account, run the following command to create a role called iot-cross-sqs-allow and attach the trust policy to allow it to interact with IoT.
    aws iam create-role \ 
         --role-name iot-cross-sqs-allow \ 
         --assume-role-policy-document file://iot_policy.json
  3. Review the output and ensure it is correct:
    {
        "Role": {
            "Path": "/",
            "RoleName": "iot-cross-sqs-allow",
            "RoleId": "XXXXXXXXXXXXXXXXXXXXX",
            "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/iot-cross-sqs-allow",
            "CreateDate": "2022-09-07T05:05:58+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "iot.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            }
        }
    }
  4. Create a file called allow_send_cross_sqs.json with the following content. For the resource ARN, be sure to update with the region and account ID of the data account.
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "sqs:SendMessage",
                "Resource": "arn:aws:sqs:<data account region>:<data account ID>:iot-data"
            }
        ]
    }
  5. Add this custom inline policy to the role you created in the previous step by using the following command:
    aws iam put-role-policy \
         --role-name iot-cross-sqs-allow \
         --policy-name new-iot-cross-sqs-policy \
         --policy-document file://allow_send_cross_sqs.json

Create the AWS IAM role and policy to allow republishing of errors

When republishing messages with an AWS IoT rule, permissions need to be properly set to allow this action.

  1. With the AWS CLI configured for the ingestion account and using the same file created earlier, create a new role called iot-republish:
    aws iam create-role \
         --role-name iot-republish \
         --assume-role-policy-document file://iot_policy.json
    
  2. Review the output and ensure it is correct:
    {
        "Role": {
            "Path": "/",
            "RoleName": "iot-republish",
            "RoleId": "XXXXXXXXXXXXXXXXXXXXX",
            "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/iot-republish",
            "CreateDate": "2022-09-07T05:24:36+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "iot.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            }
        }
    }
  3. Next create a file called allow_republish.json with the following content. Please note that this policy restricts publishing to topic names starting with errors. Be sure to update with the region and account ID of the ingestion account.
    {
        "Version": "2012-10-17",
        "Statement": {
            "Effect": "Allow",
            "Action": "iot:Publish",
            "Resource": "arn:aws:iot:<ingestion account region>:<ingestion account ID>:errors/*"
        }
    }
    
  4. Add the policy just created as an inline policy to the iot-republish role:
    aws iam put-role-policy \
         --role-name iot-republish \
         --policy-name iot-republish \
         --policy-document file://allow_republish.json
    

Create an IoT rule in the ingestion account to evaluate messages and republish errors

Next, we will create the IoT rule that will route messages to the SQS queue in the and also republish any messages that encounter an error to a topic named error/rules.

  1. Create a file named ingestion_rule.json with the following content. Be sure to update the queueURL and roleArn values with those received in previous steps.
    {
    "sql": "SELECT * FROM 'data/private'" ,
    "description": "Cross-account publishing of messages to SQS.",
    "ruleDisabled": false,
    "awsIotSqlVersion": "2016-03-23",
    "actions": [{
        "sqs": {
            "roleArn": "<iot-cross-sqs-allow role ARN>",
            "queueUrl": "https://sqs.<data account region>.amazonaws.com/<data account ID>/iot-data",
            "useBase64": true
        }
    }], 
    "errorAction": {
        "republish": {
          "roleArn": "<iot-republish role ARN>",
          "topic": "error/rules",
          "qos": 0
        }
      }
    }
  2. With the AWS CLI configured for the ingestion account, create an IoT rule for the publishing of message to SQS in the data account:
    aws iot create-topic-rule \
         --rule-name "cross_account_sqs_publish" \
         --topic-rule-payload file://ingestion_rule.json

Publish messages and verify they are visible in the data account SQS queue

To test the solution, you can publish a message to AWS IoT Core and see if it arrives successfully in the data account SQS queue.

  1. From the ingestion account, use the AWS IoT MQTT client to subscribe to the data/private and error/rules topics.
  2. Continuing with the AWS MQTT IoT client, publish a message to the data/private topic with a sample payload:
    {
        "message": "Hello, world",
        "clientType": "MQTT client"
    }
    
  3. Retrieve messages from the SQS queue and review the output by configuring the AWS CLI for the data account and running the following command.
    aws sqs receive-message \
        --queue-url https://sqs.<data account region>.amazonaws.com/<data account ID>/iot-data
    

    The Body parameter of the output may be Base64 encoded. If so, you will need to decode it to see the contents of the published message

  4. If messages are not being received in the SQS queue, check the error/rules topic subscription for error messages related to delivery from the AWS MQTT IoT client in the ingestion account.

Cleaning Up

It is good practice to clean up any resources you no longer want to use. Cleaning up AWS resources prevents your account from incurring any further charges.

  1. Delete the SQS queue:
    aws sqs delete queue \
       --queue-url https://sqs.<data account region>.amazonaws.com/<data account ID>/iot-data
  2. Delete the iot-cross-sqs-all IAM role:
    aws iam delete-role-policy \
         --role-name iot-cross-sqs-all \
         --policy-name iot-cross-sqs-all
    
    aws iam delete-role --role-name iot-cross-sqs-all
    
  3. Delete the iot-republish role:
    aws iam delete-role-policy \
         --role-name iot-republish \
         --policy-name iot-republish
    
    aws iam delete-role --role-name iot-republish
    
  4. Delete the cross_account_sqs_publish topic rule:
    aws iot delete-topic-rule \
         --rule-name cross_account_sqs_publish

Conclusion

In this blog we  explained how to route AWS IoT messages from an ingestion account to Amazon SQS in a data account. We have shown you one pattern that allows for segmentation of a sensitive device and operational data within separate accounts. For further examples on how to perform cross-account message routing with other AWS services, please check out the related documentation in the AWS Developer Guide.

Authors

Steve Krems is a Specialist Solution Architect for IoT at Amazon Web Services (AWS). Prior to this role, Steve spent 18 years in the semiconductor industry in Information Technology management roles with a focus on cloud migration and modernization.
Kai-Matthias Dickman is a Specialist Solution Architect for IoT at Amazon Web Services (AWS).   He enjoys working with developers and decision makers at large enterprises to drive the adoption of AWS IoT services.  Kai has in-depth knowledge of IoT and cloud and works in this role with global customers ranging from start-up to enterprises to enable them to build IoT solutions with the AWS Eco system.