AWS IoT Integration
The Amazon Web Services Internet-of-Things (AWS IoT) service enables bi-directional communication between Internet-connected things, such as sensors, embedded devices, or appliances, and other services on the AWS cloud, such as cloud servers, databases, analytics and more. This document provides an overview how to use AWS IoT component with balena to deploy IoT devices on the AWS IoT platform.
Configuring AWS IoT
Sign up for an AWS account or log into your account at the AWS Console. Once logged in, navigate to the AWS IoT console from AWS services dashboard.
For more details about the following steps, please check the AWS Documentation, and in particular the AWS IoT Documentation. Most tasks are available both in the web interface and through the AWS Command Line Interface (CLI).
Create a thing
Physical devices that are sending and/or receiving data are called "things" on AWS IoT. They can connect to the platform using certificates, and have to have rules defined to give the device ability to communicate with AWS services. Optionally they are grouped with a thing type to make configuration of similar devices easier.
From the AWS IoT Core page, go to Manage -> Things. Then on the page, go ahead and register a thing, then on the next page select Create a single thing.
For this example project, we will create a thing called balena_project
. All you need to do is to insert the name and click Next.
Each device
or thing
, must have its own certificates that will be used to authenticate with AWS IoT, so let’s use the One-click certificate creation option.
In order to authenticate with the service, you will first need to download the following files:
- The thing's certificate
- The thing's public key file
- The thing's private key file
- You also need to download a root CA for AWS IoT. You can find the root CA files for AWS IoT here. We used the RSA 2048 bit key.
After downloading the files, click on Activate
.
Create a policy
Now it’s time to create some policies to allow our devices to communicate with the platform. Go back to the IoT Core, open Secure -> Policies and click on Create a policy.
For this project create a policy called balena_control_policy
, and add the statement as shown below:
Action | iot:* |
---|---|
Resource ARN | * |
Effect | Allow |
Go to Secure -> Certificates. Select the recently created certificate and attach both the thing and policy to it.
The policy previously created enables all devices (things) to connect to our AWS IoT broker, but for security reasons, when you add the thing to the certificate, it guarantees that only those with matching security keys will be able to connect to the server.
The last step in configuring the AWS IoT is to get the endpoint URL to connect to the service. Simply go to AWS IoT and click on Settings. There you will find the endpoint. Save it as we will need it later on.
At this point everything is ready on the AWS side, so let’s go ahead and configure our device to communicate with it using balenaCloud.
Flashing the Raspberry Pi and deploying code
Using Python: MQTT Client example
Set up the balenaCloud application
If you don’t have one already, sign up for a balenaCloud account.
You can deploy this project to a new balenaCloud application in one click using the button below:
The application will be named balena-aws-iot-mqtt-example
by default but you can change it to anything you like. Select a device type that matches your device (in this example we will create a project to run on a Raspberry Pi 3).
Then click Create and Deploy
. This will create an application with all of the code already deployed.
With the application created, click on Add device and select the latest recommended balenaOS version, choose the network connection you desire, setup its credentials and download the balenaOS to your computer.
Flash your device
Use balenaEtcher to flash your Raspberry Pi with the downloaded OS image from the previous section. Insert the SD card into your computer, select the balenaOS image file, select the SD Card and click Flash!
After flashing is done, insert the SD card into your device and turn it on. After a few seconds, it should connect to the internet and show up on the balenaCloud dashboard.
Converting the certificates to base64
When configuring your device to communicate with AWS IoT, each device must contain its own certificates. The issue with the certificate files is that you can’t and shouldn’t add them to the project directory as it would create a security issue for the whole project. Instead, we will deploy all the devices with the same source-code and configure individual certificates from the balenaCloud dashboard, making use of environment variables.
The method we will apply is to convert the cert files we previously downloaded into base64 strings and paste them into our device’s variables.
You can generate the base64 encoded files from the terminal with: openssl base64 -in <in file> -out <out file>
For this project, you will need to convert the root CA root-CA.crt
, the thing certificate xxx.cert.pem
and the private key xxx.private.key
. Then you will paste the content of the files into our balenaDash environment variables as described in the next session.
Add Environment Variables
To add the environment variables for the device, on the device dashboard page, go to D(x) Device Variables and add the following variables with the values from the conversion in the previous step.
ENV VAR | Value |
---|---|
AWS_ENDPOINT | Your AWS IoT Custom endpoint |
AWS_PRIVATE_CERT | Base64 string of xxx.private.key |
AWS_ROOT_CERT | Base64 string of AmazonRootCA1.pem |
AWS_THING_CERT | Base64 string of xxx.cert.pem |
You should now have something similar to:
Using Node.js
The previous part of the documentation describes how to create a sample project with Python. In case you want to create a Node.js application, the AWS Javascript SDK package is capable of both working with the AWS IoT resources and the data communication on the IoT Data Plane. Thus it can be used to implement both the provisioning and the device side of the application. However for security reasons it isn't encouraged to use the AWS Javascript SDK on devices in the field, it is better instead to just use the AWS IoT device SDK doesn't have resource management capabilities. Therefore for this example, we have split the code into two parts. balena-aws-lambda
is responsible the resource provisioning and balena-aws-device
only handles data communication.
For a complete Node.js example, please see the pair of balena-aws-lambda and balena-aws-device repositories!
Here are a few notes using the AWS IoT device SDK with balena devices. Using Dockerfile templates, start from the balena default Node.js images, for example:
FROM balenalib/%%BALENA_MACHINE_NAME%%-node:latest
Add the aws-iot-device-sdk
dependency in your package.json
in your application's folder:
npm install --save aws-iot-device-sdk
Later in your Dockerfile.template
you can then configure the node modules installation as:
COPY package.json ./
RUN JOBS=MAX npm i --unsafe-perm --production && npm cache clean
Then in your application you can access the environmental variables through process.env.VARIABLE
, and send messages through the SDK. A simple example is shown below (where new-lines in the relevant environment variables were escaped base64 encoded strings):
var awsIot = require('aws-iot-device-sdk');
var Chance = require('chance'); // used to randomize bool values
var chance = new Chance();
var device = awsIot.device({
privateKey: new Buffer(process.env.AWS_PRIVATE_KEY, 'base64'),
clientCert: new Buffer(process.env.AWS_CERT, 'base64'),
caCert: new Buffer(process.env.AWS_ROOT_CA, 'base64'),
clientId: process.env.BALENA_DEVICE_UUID,
region: process.env.AWS_REGION
});
device.on('connect', function() {
console.log('connect');
device.subscribe('sensor');
// publish data
setInterval(function () {
var reading = chance.floating({min: 0, max: 200});
device.publish('sensor', JSON.stringify({ reading: reading }));
}, process.env.INTERVAL || 3000);
});
device.on('message', function(topic, payload) {
console.log('message', topic, payload.toString());
});
General
You can create base64 encoded strings from key files to be use with environment variables for example in Python as:
import base64
filename = "KEYFILE"
with open(filename, "rb") as key_file:
key = key_file.read()
encoded_key = base64.b64encode(key)
print(encoded_key.decode("ascii") )
or in Linux as:
cat KEYFILE | base64 -w 0
where you need to replace KEYFILE
with the relevant filename (such as xxxxxxxxxx-certificate.pem.crt
or xxxxxxxxxx-private.pem.key
).
Further information
Shortcuts:
- AWS IoT console
- AWS IoT Documentation
- AWS IoT API Reference
- AWS SDK reference, list of SDKs in all supported languages
- AWS IoT MQTT Client, useful for debugging AWS IoT communication
Sample Apps
A few sample apps to get started:
- balena-aws-lambda and balena-aws-device
- balenaCloud AWS IoT MQTT Broker Example with full blog post for example: