Self-signed certificates for MQTT server

 Posted by:   Posted on:   Updated on:  2021-04-12T08:26:21Z

Generate SSL certificates for your own, self-hosted MQTT broker to be able to connect securely over the Internet

During the last series of posts, I set up an Orange Pi single board computer running Armbian and I installed Mosquitto on it. My intention is to have a self-hosted MQTT broker for IoT applications. I already have it running with the configuration from previous post and it can be used for local connections in my home LAN and WiFi. Since this is a closed network, behind a firewall running on the Internet gateway I got from my ISP, there is no need for MQTT over SSL. But I need more: I want to be able to connect to MQTT server from remote devices (my Android phone, for example).

To do this, I need to configure a secured listener in Mosquitto and open its port for internet access. Since most ISPs offer dynamic IPs to residential clients, I also need a dynamic DNS service provider to have a domain name which always points to my IP. If you can get a static IP, then you don't need this.

Self-signed certificates for MQTT server

Static IP or domain

The first step is to check if your IP is static. If you do not know, check your IP then restart the network hardware you got from your ISP in order to have Internet access (modem, gateway, ONT). If they provide service directly over Ethernet cable, restart your router. Check your IP again. If it is the same, you will have access to MQTT server at this IP.

Some ISPs offer static IPs as an additional service for a monthly fee. If you really want static IP, check with your ISP. Otherwise, if you are like me, with a dynamic IP, a dynamic DNS service is required. Dynamic DNS (Dynamic Domain Name System) allows you to assign a fixed host and domain name to a dynamic Internet IP address. It is useful when you are hosting your own website, FTP server, or another server behind the router. Fortunately for me, my ISP (RCS & RDS S.A. in Romania) offers dynamic DNS to all of its internet subscribers, at no extra costs. I can configure it in the customer account on their website and I get a subdomain: any-available-name.go.ro. Check with your ISP whether they have a similar service.

Otherwise, you need to use a 3rd party dynamic DNS provider (DynDNS, No-IP). The good thing is that most modems/ONTs with integrated router have this option for dynamic DNS. If your ISP allows you to use your own router, TP-Link also offers a dynamic DNS service. To begin with, you need to sign up with a Dynamic DNS service provider - one that is supported by the device you're using to access the Internet.

Configure Dynamic DNS in router interface

Configure Dynamic DNS in router interface

Although my ISP offers dynamic DNS from the customer account, the firmware on their ONT has the option to use a 3rd party dynamic DNS provider. I can't be of too much help here, since user interface is different on each device. However, all routers will require the domain name and your username/password from the Dynamic DNS account. The not so nice part of these free providers is that the domain name usually expires in 30 days, unless you log in each month and renew it (with a click). They even send you an email when your domain is ready to expire. To overcome this, you have to pay for better service.

Port forwarding

We are not done yet with the Internet access device. If it integrates a router (and most do), it has a NAT (network address translation) feature which allows port forwarding. In order to set it up, your Orange Pi board must have a known and fixed local IP and you must also know the port you want to open. By default, the MQTT port for secured connections is 8883. And the IP of Orange Pi has been set in the first post (to 192.168.1.4). I didn't quite explain it then, but when you set the IP of Orange Pi, make sure it is outside of the range of allowable DHCP leases, yet in the same subnet. If needed, you must modify DHCP server settings in the same Internet access device (LAN settings). For example, if its IP is 192.168.1.1 and DHCP is set to assign IPs from 192.168.1.2 to 192.168.1.254 (as most are), you can change start IP to 192.168.1.3 and make 192.168.1.2 available for Orange Pi. In my home network, I have other devices with fixed IPs (Orange Pi is one of them at 192.168.1.4), so I set DHCP server to assign addresses from 192.168.1.10 to 192.168.1.254, therefore having 192.168.1.2 to 192.168.1.9 free for devices with fixed IPs.

Here we go again to user interfaces. A port forwarding rule has a source host and a destination host. The destination host IP is Orange Pi IP and port is 8883. For the source, IP should be left blank and port can be whatever you want. I set it to the same 8883, because this is the port on which MQTT server will be accessible from the outside world. Some devices expect port intervals instead of a single port. Just set start and end port to the same 8883 and it should be fine. Protocol should be set to TCP.

Configure port forwarding in router interface

Configure port forwarding in router interface

TP-Link has this option in NAT Forwarding section and it is called Virtual Servers. Setting it up is very straightforward.

Getting SSL certificates

This is the highest level of security which you can use to send data over the internet in a safe way. It is not as easy to implement, though. You must get some certificates or generate them yourself. Because I chose to run a self-hosted server, I will also generate my own certificates. It can be done on all platforms, with OpenSSL. So why not do it on Armbian? The following commands are available in Linux and even Windows, if you install OpenSSL and run the commands with the correct path to openssl executable.

The first prerequisite is to create a certificate authority (CA). For SSL connections to take place, the server (and client's) certificates must be signed by a trusted CA. The server and clients hold a private copy of the CA and check received certificates against the CA before trusting another device. I ran the following commands:

mkdir ~/certs
cd ~/certs
openssl genrsa -des3 -out ca.key 2048

A pass phrase is requested for the key. Enter a strong password and store it somewhere (in a text file) because it is needed everytime you generate certificates and you want to sign them with this CA. Next is the actual certificate:

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

Modify -days as you wish. 10 years is a long time for website certificates, but for IoT applications is just fine. Give it the pass phrase and it will go to the next step. Each certificate contains some information about the issuer. At this step, for the CA, you may enter whatever you want in the requested fields.

If you want those fields to reflect the reality, enter your address (country code, state/province and locality). For the organization name, I like to write the purpose of this certificate (i.e., "Home Automation IoT") and organization unit can be blank. Common name is your full name (not a domain here) and the last requested information is your email address.

The CA certificate is generated and you should copy it to the dedicated folder of Mosquitto.

sudo cp ca.crt /etc/mosquitto/ca_certificates/

CA is created only once. Remember that if you need to generate client certificates on another device, the CA certificate file (ca.crt) and pass phrase are needed.

Certificate generation

Now I will generate certificates. One for the server and as many as I need for (each of the) clients. Let's start with the server one:

openssl genrsa -out server.key 2048
openssl req -new -out server.csr -key server.key -addext subjectAltName=IP:server_local_ip,DNS:dynamic_dns_domain,DNS:hostname.local

Edit the command to suit your needs. You need to have a domain name if you want to access the MQTT server from the Internet. If that's not needed, remove DNS:dynamic_dns_domain, from the command. Chrome browser will throw a big security warning if the website domain from certificate does not match the actual URL. As far as I know, MQTT clients do not have this problem. And it is perfectly safe to override any security warnings regarding certificate authenticity. Remember those are certificates generated by you and are safe as long as they are not published on the Internet.

This command will continue with the same prompts for country, address, common name and email address. Note that here, every piece of information is about the server, so common name is server domain (the dynamic DNS domain). If you don't have one just enter any domain or name there. Sometimes additional information is requested. I was prompted to enter a "challenge password" - this is a different password, not the CA pass phrase. The next command creates the certificate:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650

As you probably expected, it asks for CA pass phrase to sign the certificate. Let's copy certificate and key in the configuration folder:

sudo cp server.crt /etc/mosquitto/certs/
sudo cp server.key /etc/mosquitto/certs/

With this, the section "Certificate generation" ends. I want you to know you have to repeat the steps inside this section for each certificate you want to generate.

What about clients?

Clients which connect to Mosquitto server can prove their identity in two ways. With certificate or with username/password. The first option is not always available (not all MQTT client software can be configured with certificate). It is more secure for clients to prove their identity with a certificate but it is a bit too much and not needed. When you connect to a secured website from the browser, only the website proves its identity to the browser by sending its certificate. The browser has a database of trusted certificate authorities and if the website's certificate is signed by one of those authorities, the website is trusted by browser.

The connection is encrypted even if the client doesn't offer a certificate. Therefore I will not configure Mosquitto to require certificates from clients. The username/passwords used to log in are from the password file created in the previous post. But I want to show you both methods.

When certificate is required

There is no need to generate certificate with subjectAltName. The common name is not a domain, but a client name/description.

openssl genrsa -out client.key 2048
openssl req -new -out client.csr -key client.key
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650

Each client connected to MQTT server has a name. It is usually the name from passwords file. When you require clients to prove their identity with a certificate, the common name set in certificate subject or the entire subject can replace client name. That's why, when you create client certificates, set the common name to a string that represents the client (i.e., Relay, TempSensor). Client names are good to know if you set access control rules. There is also the option to require certificate and username/password at the same time.

Secured listener example 1
  • Client certificate is required.
  • Client is trusted because it owns a certificate signed by the same CA as server's certificate.
  • Client name is set from CN field of certificate subject.
# Certificate listener
listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate true
use_identity_as_username true
Secured listener example 2
  • Client certificate is required.
  • Client is trusted because it owns a certificate signed by the same CA as server's certificate.
  • Client name is set from certificate subject (in the form of CN=device_name,OU=,O=Home Automation IoT,L=Home,ST=X,C=RO).
# Certificate listener
listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate true
use_subject_as_username true
Secured listener example 3
  • Client certificate is required.
  • Client authenticates with username/password.
# Certificate listener
listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate true
use_identity_as_username false

Without client certificates

When client certificate is not requested, the SSL/TLS component of the client will verify the server but there is no requirement for the client to provide anything for the server: authentication is limited to the MQTT built in username/password.

This is the configuration I have in use. Below is the complete mosquitto.conf file. It can be edited with nano as I showed in the previous post.

# Global
per_listener_settings true

# Default listener
port 1883

# PSK listener
listener 8882
psk_hint "mqttbroker"
use_identity_as_username true

# Certificate listener
listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false

# Security
allow_anonymous false
password_file /etc/mosquitto/passwd/pass.txt
psk_file /etc/mosquitto/passwd/psk.txt

Commands for editing configuration file and restarting the server are the following. After you paste contents, press Ctrl+O, then Enter and Ctrl+X to save and exit nano editor.

sudo nano /etc/mosquitto/conf.d/mosquitto.conf
sudo systemctl restart mosquitto

Overview

Your own, self-hosted MQTT server should be running by now, if you followed this series of posts. Feel free to test the connection from various devices, with various clients. When you add local clients (sensors, relays), use the local IP to connect to server. If you use a MQTT client app on your phone (i.e., MQTT Dash), use the domain name to connect to server from any network.

And one last important note. Unless you have back-up battery which handles unexpected power drops, a full back-up of the SD card is always good to have.

References

  1. HaiBac Ngo. How-To Create Self-signed SSL Certificates For IoT Application. Available from https://bacnh.com/how-create-self-signed-certificates/ (accessed on March 4th, 2021).
  2. One Transistor. Configure Mosquitto™ broker with TLS certificate (2019). Available from https://www.onetransistor.eu/2019/05/mosquitto-mqtt-tls-certificate.html (accessed on March 4th, 2021).

No comments :

Post a Comment

Please read the comments policy before publishing your comment.