How to Connect to AWS IoT Core using MQTT & ALPN

This example shows how to connect to AWS IoT Core using MQTT on the secure HTTPS port 443. Many firewalls and home routers limit inbound and outbound traffic to a small range of TCP ports. This is done as a security measure to limit the attack surface for possible cyber attacks. Standard ports for things like HTTPS traffic (port 443) are usually left open but others that are used for less common protocols, such as MQTT (port 8883) may be intentionally blocked.

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.

This example is designed for the YouTube video tutorial How to Get Started with AWS IoT Core Quick Connect. You must follow the instructions in this video "as is", except for running the Python code. Instead of running the Python code, you will be running the Lua code we have prepared.

We have prepared two AWS IoT Core MQTT examples. One can be downloaded from GitHub and the other is integrated in our Lua tutorials. The example on GitHub requires some configuration and the example that is integrated in our Lua tutorials is configuration-less. The Lua tutorials version just needs the zip file you get when following the AWS video tutorial. You can also safely run the AWS IoT Core MQTT example using our online tutorial server.

Options:

The GitHub code example has a smaller code base since it does not need the supporting code for the configuration-less example.

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 Authentication 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 authentication. The client authenticates the broker and the broker authenticates the client. See the tutorial Certificate Management for Embedded Systems if you are new to PKI (Public Key Infrastructure).

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


Posted in Tutorials