How to Connect to AWS IoT Core using MQTT & ALPN

This example demonstrates how to connect to AWS IoT Core using MQTT over a secure HTTPS connection on port 443. Many firewalls and home routers restrict inbound and outbound traffic to a small range of TCP ports as a security measure, and while standard ports like HTTPS (port 443) are typically left open, others that are used for less common protocols like MQTT (port 8883) may be blocked. By using TLS ALPN, this example shows you how to connect the MQTT client to AWS IoT Core using the HTTPS port 443, allowing you to bypass any potential barriers and establish a secure connection. This is an important consideration for anyone looking to implement MQTT in their IoT projects, and our ready-to-run examples make it easy to get started with this powerful communication setup.

This tutorial also shows you how to set up mutual TLS authentication. Mutual Transport Layer Security (mTLS) is a secure communication protocol that establishes an encrypted connection between two parties using X.509 digital certificates to authenticate each other. This ensures that the parties on either end of a network connection can be confident in the other party's identity, as both must possess the correct private key to establish the connection successfully. This tutorial serves as a solid foundation for both the mTLS Lua example and the mTLS C example included in the SharkSSL IDE, and will help you get started with implementing secure communication in your own IoT projects.


Our example code is designed for the following Amazon video tutorial:

You must follow the instructions in the above video "as is", except for running the Python code. Instead of running the Python code, you will run the Lua or C code we prepared.

  • Lua code:
    We have created two AWS IoT Core MQTT examples for Lua - one can be downloaded from GitHub and the other is integrated into our Lua tutorials. The GitHub example requires some configuration, while the version in our Lua tutorials is ready to use out of the box - all you need is the zip file produced by following the above video. The configuration-less example is also available on our online tutorial server, so you can try it out without setting anything up on your own computer.
  • C/C++ code:
    Additionally, we have included a C code version of the AWS IoT Core MQTT example in the SharkSSL IDE, providing an option for those looking to get started with AWS IoT Core using C/C++ and not Lua. However, note that Lua greatly simplifies designing an MQTT client, and if you are considering using an MCU, check out the Lua-powered Xedge32 for ESP32, which can run this example.

Options:

The GitHub code example has a smaller code base since it does not need the supporting code for the no-code example. Note: we also provide an AWS MQTT tutorial for the ESP32 microcontroller.

How the AWS IoT Core Example Works

The following code snippet shows how to connect to AWS IoT Core using the port number 443 (the secure HTTPS port).

local mqtt = require"mqttc".connect(
   awsBroker, -- broker name
   onpub, -- Our MQTT callback function
   { -- The option (op) table
      shark = shark,
      id = "basicPubSub",
      port = 443,
      alpn = "x-amzn-mqtt-ca"
   })

We load the Lua MQTT client module "mqttc" by calling the require function. This function returns the MQTT module as a Lua table. Using this table, we call the MQTT connect() function that is part of this table. We pass in three arguments to the connect() function, the AWS IoT Core's MQTT broker name, a callback function, and a configuration table. The callback function will be called when the broker publishes messages we have subscribed to. In the configuration table, we set the MQTT client's ID, the connection port to 443, and the alpn extension to a specialized extension defined by AWS. See the Amazon AWS tutorial MQTT with TLS client authentication on port 443 for more information on how this works. We also set the 'shark' attribute in the configuration table. The Mako Server uses the Barracuda App Server library, which in turn is bundled with a TLS stack called SharkSSL. Since we are connecting using a secure connection, a SharkSSL object is required.

How to Create a Mutual Transport Layer Security (mTLS) SharkSSL Object

As we mentioned above, a SharkSSL object is required when using a secure connection. This object not only enables setting up a secure connection, but also makes sure we trust the broker and that the broker can authenticate our MQTT client using the SSL certificate created by the online AWS portal. This is known as Mutual TLS (mTLS) authentication. The client authenticates the broker and the broker authenticates the client.

When using mTLS, both the client and server have a certificate, and both sides authenticate using their public/private key pair. The mTLS handshake works as follows:
  1. Client connects to server
  2. Server presents its TLS certificate
  3. Client verifies the server's certificate
  4. Client presents its TLS certificate
  5. Server verifies the client's certificate
  6. Server grants access
  7. Client and server exchange information over encrypted TLS connection

Check out the tutorial Certificate Management and Chain of Trust if you are new to certificate management and/or mTLS.

Before creating a SharkSSL object, we need to create a Truststore aka certificate store. The certificate store will enable the client to authenticate the broker's X.509 certificate; more specifically, the certificate store will enable the client to validate the broker's complete certificate chain.

local certstore = ba.create.certstore()
certstore:addcert(io,"AmazonRootCA1.pem")
local shark = ba.create.sharkssl(certstore)

In the above Lua code snippet, we create a certificate store and add the Amazon root certificate aka certificate authority (CA) certificate to the store. This will enable the client to authenticate the AWS MQTT broker. The last line above creates a SharkSSL object and binds this object to the certificate store.

We also need to make sure the client sends its client certificate to the MQTT broker. You get the client certificate and its associated private key by following the instructions in the AWS IoT Core Quick Connect video tutorial.

local sharkcert = ba.create.sharkcert(io, "Demo_Thing.cert.pem","Demo_Thing.private.key")
shark:addcert(sharkcert)

In the above code snippet, we create a SharkSSL binary (optimized) certificate by using the client's certificate and private key. We then add this certificate to the SharkSSL object. That is all it takes to complete the mutual authentication configuration. We can now use the SharkSSL object in the configuration table when we call the mqtt.connect() function (see the first code snippet above).

See the MQTT example's full source code for details.

Note: This example does not work if your Intranet requires Internet access via a proxy such as a SOCKS proxy. See the code snippet Example 4: Connecting via a SOCKS5 proxy included in the MQTT documentation if you are behind a HTTPS or SOCKS proxy.

Conclusion

Exploring AWS IoT Core reveals a platform that is both incredibly powerful and versatile, designed to accommodate a wide range of IoT applications. However, it also comes with its complexities, making the learning curve steep for those new to the ecosystem. One specific nuance to be aware of is how AWS IoT Core Quick Connect handles Access Control Lists (ACLs). AWS IoT Core Quick Connect automatically configures ACLs for two MQTT topics: "topic_1" and "topic_2". If you attempt to subscribe to or publish to topics outside of these predefined ones, the AWS broker will terminate the connection abruptly. This security feature is in place to ensure that only authorized operations are carried out, further reinforcing the robustness of the AWS IoT Core platform.


Facing a Technical Puzzle? We're With You Every Step:

Dive deep into our treasure trove of embedded web server and IoT tutorials designed for enthusiasts like you. Yet, if deadlines loom or challenges arise, remember our experts are on standby. With Real Time Logic, you have the freedom to learn and the assurance of expert support when you need it. Let's bring your project to fruition your way.



OPC-UA

OPC-UA Client & Server

An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.

Edge Controller

Edge Controller

Use our user programmable Edge-Controller as a tool to accelerate development of the next generation industrial edge products and to facilitate rapid IoT and IIoT development.

On-Premises IoT

On-Premises IoT Platform

Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.

Embedded Web Server

Barracuda Embedded Web Server

The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.

WebSocket Server

Microcontroller Friendly

The tiny Minnow Server enables modern web server user interfaces to be used as the graphical front end for tiny microcontrollers. Make sure to check out the reference design and the Minnow Server design guide.

WebDAV Server

Network File System

Why use FTP when you can use your device as a secure network drive.

HTTP Client

Secure HTTP Client Library

PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.

WebSocket Client

Microcontroller Friendly

The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.

SMTP Client

Secure Embedded SMTP Library

Send alarms and other notifications from any microcontroller powered product.

Crypto Library

RayCrypto C Library

The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.

Embedded PKI Service

Automatic SSL Certificate Management for Devices

Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.

Modbus

Modbus TCP client

The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.

Posted in Tutorials