Improve this doc

AWS IoT Integration

balena aws iot

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.

create thing

create 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.

generate certs

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.

generate certs

In order to authenticate with the service, you will first need to download the following files:

  1. The thing's certificate
  2. The thing's public key file
  3. The thing's private key file
  4. 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.

download certs

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.

create policy

For this project create a policy called balena_control_policy, and add the statement as shown below:

Action iot:*
Resource ARN *
Effect Allow

create policy

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.

create policy

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:

Deploy to balena button

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).

add device

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.

add device

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.

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:

end vars

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() {
  // 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());


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 =
    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


Sample Apps

A few sample apps to get started: