In my last article, I showed how we could build an IoT app without the Internet. It's a good exercise when you want to get started or do Rapid Prototyping without having any dependency on the Internet. One question that is always asked by the people evaluating the proof of concepts, is regarding Security. How have you secured your solution ? Most of the customers’ concerns when they are contemplating to introduce IoT into their business or product line are related to security. Be it device security or network security, having it on scale is very important. I would not go into much detail into that as it's a long topic.
In this article, I will showcase how we could secure our IoT network by enabling security into the MQTT broker and build a secure channel between the client and broker communication. One can use this when building PoCs or demos for clients or self-learning.
Network Security using Transport Level Security(TLS)
Transport Level Security(TLS) is the most common method by which secure network communication happens. I would not go into detail how TLS works, but I would demonstrate how we could configure TLS in our Local IoT application I showed you in my previous article.
Here is what I will do.
- Create a Local Certificate authority
- Create certificates for MQTT broker and clients
- Use the Local certificate authority to sign certificates for the MQTT broker and its clients.
- Secure the MQTT broker on our Raspberry Pi IoT gateway using the certificates.
- Connect multiple clients to the broker and do a data exchange.
Before we deep dive into practicalities, I just want to touch base about certificate authority (CA).
A certificate authority (CA) is an entity that signs digital certificates. The broker need to let the clients know that the connection is secure, so in practical scenarios, they pay an internationally trusted CA (e.g., VeriSign, DigiCert) to sign a certificate for their domain where the broker is hosted.e.g AWS IoT using Verisign CA. In some cases it may make more sense to act as your own CA, rather than paying a CA like DigiCert or Verisign. Common practices include securing a local broker and for issuing certificates to clients to allow them to authenticate to it. Typically, the root CA does not sign server or client certificates directly. The root CA is only ever used to create one or more intermediate CAs, which are trusted by the root CA to sign certificates on their behalf.
Let us begin…!
Generate Certificate Authority, Signed Certificates & Keys
I have put some resources for this article in a GitHub repository. It consists of some shell script that would generate a local certificate authority and MQTT broker and client certificates signed by that authority. The script uses OpenSSL which is an open source cryptographic toolkit for TLS and SSL protocols.
The certificate generator has 3 scripts namely the root CA generator, the server certificate generator and the client certificate generator.
- The root CA generator generates a root CA and an intermediate CA. The CA deals with the cryptographic pairs of private keys and public certificates. Typically, the root CA does not sign server or client certificates directly. The root CA is only ever used to create one or more intermediate CAs, which are trusted by the root CA to sign certificates on its behalf. This is the best practice. It allows the root key to be kept offline and unused as much as possible, as any compromise of the root key would be disastrous in the real world. It's for that reason, the IoT platform e.g. AWS IoT or MS Azure IoT gives its users an intermediate CA to sign the certificates.
- The server certificate generator generates a private key and a certificate signed by the intermediate CA. Both will be used later when we secure the MQTT broker.
- The client certificate generator generates a private key and a certificate signed by the intermediate CA. It will be used by the MQTT clients to establish a secure connection with the broker.
Ideally from the perspective of the certificate authority, clients or brokers can instead create their own private key and a certificate signing request (CSR) without revealing their private key to the CA. The CSR is then passed on to the CA which will give back a signed certificate that is used by the broker or the clients in making the secured connection. In this script, the CA is deployed on the Raspberry Pi IoT gateway itself for simplicity and demonstration purposes. Feel free to try out putting the CA on another system and copy the certificates on the gateway and the clients later.
- On the Raspberry Pi IoT gateway we used in our last article, login via ssh and update the software on the Raspberry Pi gateway
sudo apt-get update; sudo apt-get -y upgrade
- Clone the git repository which has the scripts and example code.
- Use the script to generate the certificates for the broker and the clients.
- Take a note of the hostname of the Raspberry Pi IoT gateway using the
hostnamecommand. The hostname is passed as an argument during the server certificate generation
- Create the CA and intermediate CA using the command
- It should generate the CA certificate in the results folder
- Next, create the server certificate and the key using the command. Here
mqttserveris the hostname of the IoT gateway.
./genservercert -s mqttserver
- It should generate the server certificate and the key in the results folder
all-ca.crt mqttserver.crt mqttserver.key
- Now, to create the client certificate and key run the command. Here,
mqttclientis the network name of the client.You could even use the IP address as well.
IoT-Dev>./genclientcert -c mqttclient
- It should generate the client certificate and the key in the 'results' folder. We need to download these files on the laptop to be used by the client.You could scp or even use a USB stick to copy the files directly from the RaspberryPi via the USB port.
all-ca.crt mqttclient.crt mqttclient.key
Now that we have all the certificates and keys, we shall configure our MQTT broker and the client to use them to talk to each other securely.
Configuration of the MQTT Broker
To enable the security in the MQTT broker, we need to change the Mosquitto configuration to make the broker understand using a secured channel. Because the MQTT protocol was not designed with security in mind, the main reason to keep it light weighted, security is enabled on top of it using TLS. Of course, there is an authentication mechanism using username and passwords built into the Mosquitto broker, but I would not cover that.
The configuration file
/etc/mosquitto/mosquitto.conf needs to be edited with the changes to make it secure.
By default, the MQTT broker does not have any security enabled, and it listens to default port 1883 for unencrypted communication.
In the configuration file change to the secured default port for MQTT to
8883 and set the certificate authentication flag
Other changes include addition of the paths for the rootca
cafile file, the server certificate
certfile and the server key
Configuration of the MQTT Client
For a quick test, I would use MQTT.fx tool which was introduced in my last article. Copy the client certificates and the key which we generated earlier on your laptop.
- Create a new profile, e.g. SecureIoT Broker and add the parameters like IP address of the Broker, and set the port number to 8883. Leave the rest as defaults.
- Go to the SSL/TLS tab and enable the SSL/TLS checkbox and select Self signed certificates options. Select the appropriate files for CA File, Client certificate file and Client Key file from the files we downloaded earlier. Click OK to save the configuration.
- Select the new profile and click connect.
- If the connection was successful, the status will be green in the top right corner.
- Now, lets subscribe to a MQTT Topic e.g /IoT/Sensor01
- Go to the 'publish tab' and enter a message to the same topic /IoT/Sensor01 and publish.
- You should see your message in the 'subscribe tab'
This was how we could use MQTT.fx to test our secured MQTT broker configuration.
How do we do it in the Code ?
In the example-code folder, I have a sample python MQTT publisher and subscriber client that make use of the certificates and keys to connect to the MQTT Broker on the Raspberry Pi gateway.In the code, you need to modify the hostname of the broker and replace the certificates and the keys you generate using the steps above.To execute the code just run them in 2 separate terminal windows.
You now have an IoT App that talks to a secure IoT broker which you have deployed locally.
Note: If you want to start this activity again from scratch and want to clean all the certificates and keys you generated, you could do this using this command.
On a closing note, I know this article has been a little advance and some people might find it complex to follow. I would be happy to answer any questions and offer assistance in case anyone wants to try it out.
I strongly believe what Aristotle once said
“For the things we have to learn before we can do them, we learn by doing them.”
― Aristotle, The Nicomachean Ethics