Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New entry: Connect to an MQTT broker with TLS encryption #67

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Binary file added images/mqtt/tls-connect-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 116 additions & 0 deletions mqtt/tls-connect-to-broker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
layout: default
title: Connect to an MQTT broker with TLS encryption

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this title in the Node-RED cookbook, I would expect more information about how to configure the mqtt-broker node for secure connections (e.g. clarification of the meanings of the fields in the TLS configuration dialog, usage of self signed certificates including validation) and not necessarily information about configuring the MQTT broker.

Maybe instead: "Set up the Mosquitto MQTT broker to accept encrypted connections and connect to it from Node-RED"? Or add more information about the configuration options in Node-RED?

slug:
- label: mqtt
url: /#mqtt
- secure connect
---

### Problem

You want to have an encrypted connection to your Mosquitto MQTT broker.

### Solution

Create a valid set of certificates and keys for the broker to use.

Change the configuration of the broker to start a TLS encrypted port (`mqtts`) using the above.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "... to accept encrypted connections..." instead of "...to start a TLS encrypted port..."?


Alter the <code class="node">MQTT Config</code> node, changing the "Server" name to start with `mqtts://`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding mqtts:// to the server name is redundant when ticking the "Enable secure connection" checkbox... Maybe just "Configure the MQTT broker node to establish a secure connection."?


#### Example

**Valid Certificate Creation**

THe easiest approach for this is to use [Let's Encrypt](). This is beyond the scopy of this article but there are plenty of examples and tutorials available on the Internet. For this to work successfully, you also need to be able to use a registered domain name on your internal network because you cannot use Let's Encrypt with IP addresses or non-public domain names.
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved

Alternatively, you can create a self-signed set of certificates. Again, this is beyond the scope of the article. However, you may need to create a trusted root certificate and provide its public cert instead of the one that Debian provides that is listed in the configuration below.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only "configuration below" that includes a CA cert is the Mosquitto configuration, which does not need a CA cert at all. Instead, when using self-signed certificates, the CA cert needs to be configured in Node-RED, but this aspect is missing in the article.


**Mosquitto configuration**

This assumes that you are using Let's Encrypt or other certificates signed by a root CA already trusted by the Debian operating system.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether the CA is trusted by Debian is not relevant for the Mosquitto configuration.


Note the entries in `<...>` which need to be replaced with your own folders and files.

This goes into a file of any name of the form `*.config` in the folder `/etc/mosquitto/conf.d/`. So you have to edit it with root privalages (e.g. using `sudo`).
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved

{{ page.lcb }}% raw %}
~~~text
# Default Listener: 1883
port 1883
# Bind the default listener to localhost only if you want to force external connections to be TLS only
#bind_address localhost

# Secure listener
listener 8883
# TLS
## This is standard and should always be this when using Let's Encrypt
## If using a self-signed certificate, this needs to be your custom Root CA public certificate
cafile /etc/ssl/certs/DST_Root_CA_X3.pem
Comment on lines +48 to +50

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which cafile is configured here is only relevant for certificate based user authentication, it is not relevant for encrypted connections. The cafile entry can be left out completely. The only requirement is to have either a cafile-entry or a capath-entry in the listener configuration to enable SSL/TLS mode. This can be something like capath /var/empty.

## These are from your installation of LE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...or the self-signed certs

certfile /<path-to-LE-cert-files>/<fullchain>.cer
keyfile /<path-to-LE-cert-files>/<private-key-name>.key
## Forces use of modern version of TLS to avoid security issues
tls_version tlsv1.2

## Forces ALL CLIENTs to provide a valid certificate - change the node config to allow this from NR
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
#require_certificate true
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
~~~
{: .shell}
{{ page.lcb }}% endraw %}

After making these changes, you have to restart the mosquitto broker using the command:

~~~text
[~]$ sudo systemctl restart mosquitto
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
~~~
{: .shell}

**<code class="node">MQTT Config</code> node configuration**

![](/images/mqtt/tls-connect-1.png)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This image shows a configuration where the certificate is not validated.


Notes

* You need to use the IP name rather than IP address in the server name if using Let's Encrypt (otherwise the certificate isn't valid).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IP name -> domain name?
More specific: If using a Let's Encrypt certificate, one needs to use the domain name the certificate was issued for.

* You need to change the server name to a url, prefixed with `mqtts://`. This disables the port field, I change that first to `8883` to remind me what the correct port will be.
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
* You **do not** need to set the "Enable secure connection" flag. That lets you authenticate the Node-RED client connection to the broker (if you set the require_certificate to true for example).
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved

### Discussion

Mosquitto allows you to create multiple ports for connectivity. This lets you use websockets and TLS encrypted connections in addition to the default connection.

The folder `/etc/mosquitto/conf.d/` can contain any number of config files which will all be applied so that you can split your custom changes into separate files if you like.

Just remember that once you use a custom file to set ports, the default port (1883) is no longer active so you have to specify that as well. The standard port for MQTT over TLS (MQTTS) is 8883. You can, however, use other ports if they are not in use. Make sure you use a port number greater than 1024 otherwise everything that wants to use that port has to have root privalages.
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved

You can check which ports the broker has opened with the command:

~~~text
[~]$ sudo netstat -lptu | grep mosquitto
tcp 0 0 0.0.0.0:8883 0.0.0.0:* LISTEN 17697/mosquitto
tcp 0 0 0.0.0.0:1883 0.0.0.0:* LISTEN 17697/mosquitto
tcp6 0 0 [::]:8883 [::]:* LISTEN 17697/mosquitto
tcp6 0 0 [::]:1883 [::]:* LISTEN 17697/mosquitto
~~~
{: .shell}

You can test whether the server device is allowing connections on a port by using telnet from another device.

~~~text
[~]$ telnet <ip-name> 8883
~~~
{: .shell}

If the connection opens, then the target device is accepting connections on that port.

Note that the operating system automatically opens the required ports through the devices firewall.

If you want to monitor what the broker is doing, including seeing which clients connect to which ports, use the following command:

~~~text
[~]$ sudo tail /var/log/mosquitto/mosquitto.log -f
TotallyInformation marked this conversation as resolved.
Show resolved Hide resolved
~~~
{: .shell}