Jon Avezbaki
AvenueJ

How to use certificates with an MQTT Broker

This guide assumes you’re using Mosquitto as your broker of choice, but the principles outlined here can apply to any broker. Tweak the specifics as needed.

Credentials

Edit the contents of the mosquitto.conf file to:

password_file /mosquitto/passwd_file
listener <web-socket-port-here>
allow_anonymous false
protocol websockets

listener <mqtt-port-here>
allow_anonymous false
protocol mqtt

Run the following command to create the username and password:

$ mosquitto_passwd -c /mosquitto/passwd_file <your-username-here>

Encrypting The Connection

You can encrypt your MQTT connection with TLS/SSL. This is sometimes known as MQTTS. When encrypting your connection, there are a few key decisions you will need to make.

mutual TLS (mTLS) vs one-way TLS

TLS is ultimately just a handshake over the network. That handshake can happen in one of two ways. Either the requisite files (certificate and key) are on one machine (server), or both machines (server and client).

Note: When reading TLS discussions, posts, and tutorials online, people rarely distinguish which method they’re employing. This is fine. That info is easy to infer based on the presence of certain files in their setup. Only see server files? It’s one-way TLS. See both server and client files? Probably mTLS.

So which is the best for your use case? It depends. mTLS marries the server and client device together. You cannot have a new client device connect to the server without first getting the requisite TLS files on that client’s device.

One-way TLS, as the name implies, only requires that that the server carry requisite files. This is how HTTPS works on your browser. When you visit https://google.com, there are no certificates or keys on your machine that need to be validated.

MQTT vs WSS

Depending on what protocol you’re using to communicate with your broker, encryption will work a bit differently.

WSS (the secure version of ws, used for web socket communication) is used whenever you’re trying to communicate with an MQTT broker over a web app. Browsers have no way of working with MQTT messages, so transmitting those messages over a web socket is the next best thing.

The MQTT protocol is used in pretty much every other scenario.

Self-Signed Certificates vs Certificates From an Official CA

Certificates are typically administered by a certificate authority (CA). However, you can generate and sign your own certificate. Which one should you do? Getting a real certificate is almost always preferred. Your code will fight you less, and this is overall a more secure approach.

Self-signing is in some ways, much easier, and in others, much harder. Getting a self-signed cert is easier, since you don’t need to go through a CA. However, most code you work with will not recognize a self-signed cert as valid, so you will usually need to employ workarounds to handle this.

Self-Signed Certificates with WSS

Self-signing becomes extra tricky when working with wss on web apps though. Browsers will not recognize a self-signed cert as valid. The only way to get around that is by importing the cert to the browser’s trust store. This however, introduces an extra layer of coupling between the client device and the server.

Now, only the client devices that have had certificates imported into their browser can connect to the server. Maybe this isn’t an issue if you were already planning on using mTLS. But if you were planning on using one-way TLS, this coupling is a serious downside.

Additionally, if you are using wss, you need to consider whether your web app is being hosted on a publicly available domain name, or on a private network. It is easy to get a certificate from a trusted CA when you’re hosting on a publicly available website. If you’re hosting on a private network, things get more complicated.

Setting up Encryption with a Self-Signed Certificate

Create a directory /certs. Within that directory, create sub-directories: /broker, /ca. If you’re doing mTLS, create a client directory as well. Fill out the 3 sub-directories as follows:

/ca

  1. Run the following command:
$ openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
  1. You will be prompted for the following information. Fill in as necessary.
PEM Pass Phrase: <your-pem-pass-phrase here>

Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
  1. Verify that you now have both a ca.crt and ca.key in your /ca directory.

/broker

  1. Generate the broker’s private key
$ openssl genrsa -out broker.key 2048
  1. Create the signing request from the broker’s private key
$ openssl req -out broker.csr -key broker.key -new
  1. You will be prompted for the following information. Fill in as necessary.
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:localhost
Email Address []:

A challenge password []:
An optional company name []:

Note: The ‘challenge password’ and ‘PEM pass phrase’ are unrelated. The challenge password is completely obsolete, which is why we leave it empty.

  1. Pass the Certificate Signing Request (csr) file to our validation authority
$ openssl x509 -req -in broker.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out broker.crt -days 100
  1. Provide the pass phrase
Enter pass phrase for ../ca/ca.key: <your-pem-pass-phrase-here>
  1. Verify that you have the broker.crt, broker.csr, and broker.key files
  2. Remove the broker.csr file

/client

  1. Generate the client’s private key
$ openssl genrsa -out client.key 2048
  1. Create the signing request from the client’s private key
$ openssl req -out client.csr -key client.key -new
  1. You will be prompted for the following information. Fill in as necessary.
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:<IP-address-of-broker>

Email Address []:

A challenge password []:
An optional company name []:
  1. Pass the Certificate Signing Request (csr) file to our validation authority
$ openssl x509 -req -in client.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out client.crt -days 100
  1. Provide the pass phrase
Enter pass phrase for ../ca/ca.key: <your-pem-pass-phrase-here>
  1. Verify that you have the client.crt, client.csr, and client.key files
  2. Remove the client.csr file

Using Encryption

The following is a template of a mosquitto.conf file you can use that is set up for encryption. Combine this with the mosquitto.conf file from the ‘Credentials’ section if you plan on using a username and password.

listener <your-mqtt-port-here>
protocol mqtt
certfile /certs/broker/broker.crt
keyfile /certs/broker/broker.key
allow_anonymous true

listener <your-web-socket-port-here>
protocol websockets
certfile /certs/broker/broker.crt
keyfile /certs/broker/broker.key
allow_anonymous true

This handles things on the broker’s side. If you’re using mTLS, you’ll need to configure whatever you’re doing client side to use the client.crt and client.key.

Note: For any changes you make to the mosquitto.conf to take effect, the broker needs to be restarted.

Verifying Client To Broker Communication

Before trying to connect your client to the broker, it’s useful to check if you can use a bare bones MQTT client to connect first. I recommend using MQTT Explorer, which is what the following instructions are based on, but you can use anything.

Filling out everything for WSS is relatively straight forward. The only snag is that you cannot turn on ‘Validate certificate’ if you are using a self-signed certificate.

Regardless of whether you’re using wss or mqtt, if you’re using mTLS, you need to upload the client files. You can do this by hitting the ‘Advanced’ button.

Misc. Tips

  • If you’re working with a web app, you can use a client cert and key to host it on a HTTPS connection.
  • If you’re getting ‘Permission Denied’ errors on your broker, you may need to alter the permissions on the sub-directories and files you created for your certs and keys. You can do this via chmod. You still want these restrictions to be as rigorous as possible though.