HiveMQ Cluster with mutual TLS on a local machine

This guide will show the required steps and some common pitfalls when setting up a HiveMQ cluster and enforcing TLS for each step of communication.

Certificate and keystore generation as well as their use will be demonstrated.

Requirements

  • HiveMQ

  • JDK 11 or higher

  • openssl

  • MQTT CLI

Instructions

  1. We will create a keystore used by our HiveMQ nodes

keytool -genkey -keyalg RSA -alias hivemq -keystore hivemq.jks -storepass changeme -validity 360 -keysize 2048

keytool will ask for the necessary information to create our root certificate and private key.

These will be stored in hivemq.jks which we need to make available to all our cluster nodes.

The common name should match the hostname of the HiveMQ node. For testing purposes ‘localhost’ will suffice.

 

  1. From this keystore we need to export the server’s certificate (in this case called server.pem) and make it accessible to all clients that wish to connect

keytool -exportcert -alias hivemq -keystore hivemq.jks -rfc -file server.pem

 

 

2. Next we need to create a client certificate (mqtt-client-cert.pem), generate an x509, DER encoded certificate from it (mqtt-client.crt) and make them available to HiveMQ in form of a keystore (hivemq-trust-store.jks)

openssl req -x509 -newkey rsa:2048 -keyout mqtt-client-key.pem -out mqtt-client-cert.pem -days 360 openssl x509 -outform der -in mqtt-client-cert.pem -out mqtt-client-cert.crt keytool -import -file mqtt-client-cert.crt -alias client -keystore hivemq-trust-store.jks -storepass changeme

 

3. Now it is time to configure HiveMQ to require TLS

In our config.xml we adjust:

<path> in <keystore> must point to our earlier generated hivemq.jks

<path> in <truststore> will be our hivemq-trust-store.jks

<private-key-password> must be identical to the one we set during creation and

<client-authentication-mode> must be set to REQUIRED

When your are running multiple HiveMQ nodes on a single server remember that each instance requires a unique listening port

 

In order to ensure the use of TLS between cluster nodes we need to modify the <cluster> section of our configuration.

We must again adjust the paths of our server’s keystore and truststore (path to our generated server.jks)

and since we are running our cluster nodes on a single machine, each must bind to a different <bind-port>

In a production environment we would create a separate trust store for each node and modify the location accordingly.

 

4. We are now ready to launch our brokers (run.sh in the bin/ subdirectory)

To avoid further binding conflicts, modify jmxremote.port to a unique value in each node’s JAVA_OPTS variable within the corresponding run.sh

 

Validating our setup with MQTT CLI

 

  1. Subscription attempt without providing any certificates

As expected HiveMQ disconnects the client since no certificate was presented to the server.

 

 

2. .. while including our server.pem

We can see the TLS handshake was initiated but is aborted on the server side due to a missing client certificate

 

3. .. while supplying all required certificates

as we can see, the server accepts our subscription and we have demonstrated a successful connection attempt!