AWS IoT-Part 1

Siddharth Malani
7 min readMay 27, 2020

When I started looking at AWS IoT I just drowned into classic AWS documentation hell. The diagram-less documentation is hard to follow and that is one of the reasons I am writing this article. While the technology design is sound and once you understand works quite well, it is hard to grasp it when you start afresh.

Very Important :-

  1. AWS IoT endpoint is a MQTT broker.
  2. The authentication mechanism between Thing or Device and IoT endpoint uses mutual certificate based auth. There are other options such as Cognito etc but we will discuss those later.
  3. The control i.e. who can publish and subscribe to what topics is defined by IoT policies attached to certificates which are attached to device/s.

We will get to some details in a minute but I want you to first understand the most important thing why we are doing all this. i.e. to send a message from the device to AWS and vice versa.

Message Flow

So once you configure the IoT core you will get an AWS endpoint which is essentially a MQTT broker. How you use this broker is entirely down to how you set things up via policies etc which we will discuss in some detail.

Important thing to remember is that devices can publish and subscribe to whatever topics they want to based on what you authorise them to do.

Ideally you would keep the devices isolated from each other to prevent crosstalk. So the example above I have separated devices and direction of comms using the patterns

dev2iot/<device id>

iot2dev/<device id>

So let’s get to some details about the IoT components and concepts. In the UI you will find some very confusing groupings and hierarchies.

  1. Thing Type — This is a type of thing. So for example maybe you want to monitor a single channel temperature sensor. So this will be a Temperature Sensor Type.
  2. Thing — This is an instance of Thing Type. So each of your temperature sensors will have a record as a “thing”
  3. Thing Group — This allows additional level of grouping. For example you may want to group all sensors by say year when it was manufactured.
  4. Dynamic Thing Group — This one is interesting because you can define a query and on that basis devices will get added or removed from a group. For example, you may want to upgrade a version of firmware of a device or a config and see that the numbers in a dynamic group change to monitor progress of updates.
  5. Billing Group — Let’s say you have multiple clients using the same thing type you could group them using this construct for billing purposes.
  6. Certificate — Each device should be attached to its own certificate. Although AWS do allow same cert across devices, you should use one certificate per device
  7. Certificate Policies — These policies are attached to the certificate. This was an interesting association. A certificate policy can be attached to multiple certificates.
  8. Thing Shadow — In most IoT applications you would want to know the current state of the Thing and its inputs or outputs. Thing Shadow is like a record which represents the current most up-to-date state information of the Thing.

Just to summarise the relationship between different object types here is a quick visual.

Relationship between Thing, ThingType, ThingGroup, Certificates and Policies

In words…

  • Thing can be of Thing Type.
  • Thing can belong to zero or more Thing Groups.
  • Certificate can be attached to zero or more Things. Ideally attach unique certificate for each device.
  • Policy can be attached to zero or more Certificates.

Steps to add your first device :-

First create a device-policy

Add the following policy json document and create a policy. Remember to replace correct region and account ids in the json below.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Publish"
],
"Resource": [
"arn:aws:iot:eu-west-2:123456789012:topic/dev2iot/${iot:Connection.Thing.ThingName}"
]
},
{
"Effect": "Allow",
"Action": [
"iot:Receive"
],
"Resource": [
"arn:aws:iot:eu-west-2:123456789012:topic/iot2dev/${iot:Connection.Thing.ThingName}"
]
},
{
"Effect": "Allow",
"Action": [
"iot:Subscribe"
],
"Resource": [
"arn:aws:iot:eu-west-2:123456789012:topicfilter/iot2dev/${iot:Connection.Thing.ThingName}"
]
},
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": [
"arn:aws:iot:eu-west-2:123456789012:client/${iot:Connection.Thing.ThingName}"
]
}
]
}

Note: The default policy that you get when you use the wizard is not useful. There are some nuances which are not documented and all the nice looking example policies that should be used to comply with best practices do not work unless you get some things right which we will come to later.

Add a Thing using a wizard.

Click the Onboard on the main AWS IoT view.

Click Onboard a Device to Create Device with wiz

Click Get Started

Click Get Started

Select Node to go through steps in this blog. You can choose either platform.

Choose device OS and language of choice. I chose linux and node.

Set the name as 1001.

Set device ID as 1001

AWS generates SDK for you. Download the SDK.

Download the connection kit

Follow steps below. The first time you run start.sh it will install sdk and download the example node script to run. We will edit it in following steps.

You can skip running start.sh for now

Now your device is completely registered.

Device registration is completed

Next go to Manage tab on main AWS IoT view. You should see device 1001 in the list. Click 1001.

Now you can see the device 1001 in the list

Click on Security tab under thing view.

Click on certificate

Once you click the certificate above you will see the attached policy. We need to detach this policy and attach the one we created i.e. device-policy.

Click on Policies

Detach 1001 default policy added by AWS.

Detach the default policy that it creates

Attach the policy we created.

Attach the device-policy we created earlier
Attach the policy

Now you can see device-policy properly attached to our thing 1001. Now we are ready to send messages and receive messages from AWS IoT.

Thats it- now you are almost set to send and receive messages from IoT Core

Run the sdk sample client

Unzip the connection kit you downloaded earlier.

chmod +x start.sh

./start.sh

Once it installs you can kill the process.

Change the code in node_modules/aws-iot-device-sdk/examples/device-example.js

if (args.testMode === 1) {
device.subscribe('iot2dev/1001');
} else {
device.subscribe('iot2dev/1001');
}
if ((Math.max(args.delay, minimumDelay)) !== args.delay) {
console.log('substituting ' + minimumDelay + 'ms delay for ' + args.delay + 'ms...');
}
timeout = setInterval(function() {
count++;
if (args.testMode === 1) {
device.publish('dev2iot/1001', JSON.stringify({
mode1Process: count
}));
} else {
device.publish('dev2iot/1001', JSON.stringify({
mode2Process: count
}));
}
}, Math.max(args.delay, minimumDelay)); // clip to minimum

Modify last line in start.sh to match client-id to thing name.

node node_modules/aws-iot-device-sdk/examples/device-example.js — host-name=xxxxxxxxxxxx-ats.iot.eu-west-2.amazonaws.com — private-key=1001.private.key — client-certificate=1001.cert.pem — ca-certificate=root-CA.crt — client-id=1001

./start.sh

Finally to test if this has all worked …

Enable IoT Logging

Once you enable and follow steps to attach policy you can view logs in CloudWatch which is really helpful in debugging.

Test comms

Test tab in main screen you can subscribe to dev2iot/1001 to receive test messages from the sdk you just ran.

You can publish message into the iot2dev/1001 which will only be delivered to your device.

Message received on device

Best Practices:

  1. Use one cert per device.
  2. Make sure your device can only talk to its own topics so there is no cross talk.
  3. You could create a generic template that could be applied across certificates just like the one above which will evaluate which topic the device is allowed to interact with.

The nuance which I took a long time to figure out (thankfully from a guy who posted on stackoverflow) that the client ID needs to match the Thing Name in order for the iot variable in policy to work i.e. ${iot:Connection.Thing.ThingName}. Completely crazy as it may sound this hack does work. This is important as it means you don’t end up with 10k policy document for 10k devices and also if you wanted to add capability or restrict something you don’t have to modify 10k documents.

So when you download the pack for your device if you follow the wizard just edit your start.sh to match the Client ID to the Thing Name. In above steps we are using 1001. You will also need to change the script to publish to dev2iot/1001 and subscribe to iot2dev/1001

In the following blogs will go through other bits such as Rules, Device Shadows, Jobs, Cert revocation, Auto Registration, OTA etc.

--

--