MQTT is a widely used network protocol in IoT for sending messages between devices and a server. To keep the connection secure, MQTTS is normally used. This consumes more data and drains the battery. By using a TLS connector, we can have the device use MQTT, which Onomondo transforms into MQTTS.
For this example, I use the mqtt module for Node.js, but you should be able to replace it with any other implementation for your language. I also use test.mosquitto.org as the test MQTT server.
An example with MQTTS
This is a basic example of how to use MQTTS to connect to:
const fs = require('fs')
const mqtt = require('mqtt')
const ca = fs.readFileSync('./mosquitto.org.crt').toString()
const client = mqtt.connect('mqtts://test.mosquitto.org:8883', { ca })
client.on('message', (topic, payload) =>
console.log(`[messaged received] topic=${topic} payload=${payload.toString()}`)
)
client.on('connect', () => {
console.log('[connected]')
client.subscribe('helpomondo/testing', () =>
client.publish('helpomondo/testing', 'Hello from device')
)
})
Note that you need to have the mosquitto.org.crt on your device.
I used the Traffic Monitor to capture the packets going to/from the device. When I ran this example, it used 3.6 KB. Most of it is used to establish a secure connection.
Let’s see how we can do it better with a TLS connector.
Setting up the TLS connector
Now we need to create a new connector in the Onomondo app. For this example, we need to set the host to test.mosquitto.org, port to 8883, and put the contents of mosquitto.org.crt into the connector setup. We also add two passthrough rules to pass all UDP and ICMP packets directly to the internet.
With this setup, all TCP traffic going out from your device (no matter which IP/host it’s supposed to reach) will go to test.mosquitto.org:8883, and Onomondo creates a TLS connection to that endpoint.
Your setup should look similar to this:
Now find your SIM on the SIMs page, and edit it. Set the connector to the one we've just created.
Example with MQTT
Let's go back to the code example and set it up to only use MQTT and not MQTTS.
const fs = require('fs')
const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://test.mosquitto.org:8883')
// Notice how we went from `mqtts://` to `mqtt://` and removed the `ca`
client.on('message', (topic, payload) =>
console.log(`[messaged received] topic=${topic} payload=${payload.toString()}`)
)
client.on('connect', () => {
console.log('[connected]')
client.subscribe('helpomondo/testing', () =>
client.publish('helpomondo/testing', 'Hello from device')
)
})
It’s very similar to before, except for a few key differences. The protocol is now MQTT instead of MQTTS, and we removed the CA certificate file.
I used the Traffic Monitor to capture packets going to/from the device. This example now uses 1.1 KB.
Benefits of using a TLS connector
Saves on data cost:
Less data is transferred.
In this example, we went from ~3.6 KB to ~1.1 KB. With IoT, we often send very small messages, so establishing a TLS connection can be quite expensive.
Saves on battery usage:
By not transferring as many packets, the radio module can save battery, saving up to 45% of battery usage.
No encryption on the device:
Saves battery usage by not having to handle encryption.
Fewer keys or certificates need to be updated on the device.
Is this still secure?
A little-known fact about telecom is that traffic is secure from your device until it reaches your provider. A SIM card mostly contains keys for one-end encryption, with the matching keys on the provider’s side. This means that traffic is always encrypted until it gets to your provider (i.e., Onomondo), but then it goes on the Internet. Since most providers just pass traffic out on the Internet, you need to encrypt it on the device. By using a TLS connector, Onomondo ensures that there is an encrypted connection between Onomondo and your endpoint.
In summary, cellular traffic is already encrypted between the device and provider. Adding a TLS connector ensures encryption between Onomondo and your endpoint.
A little extra bonus
Remember how I mentioned that all TCP traffic going out of the device went to test.mosquitto.org:8883? This actually means we no longer have to look up test.mosquitto.org on the device. So we can remove that hostname from our example and save that lookup for even more optimization:
...
const client = mqtt.connect('mqtt://1.2.3.4')
// Notice how we removed the hostname. There's only an ip address now.
...
How to debug with the MQTT Explorer
To help with testing, you can find it very helpful to use MQTT Explorer. You can subscribe to helpomondo/testing and see if the device behaves as expected.