Setting up the HiveMQ PKI

Setting up a PKI infrastructure for the MQTT broker HiveMQ

It’s required if you want to connect securely using MQTT over TLS (MQTTS) or Secure Web Socket (WSS).

We recommend reading our blog post, about secure communication, first.

Requirements

  • OpenSSL / LibreSSL
  • Java JRE / OpenJDK JRE

Structure

HiveMQ requires two Java Key Stores

Keystore

This keystore stores HiveMQ certificate and private key.

You should handle this store as confidential, since anybody with access to it, could generate valid client certificates, and therefore read and send messages in your MQTT infrastructure.

Truststore

This keystore stores all certificates of Clients.

It’s used by HiveMQ to verify their connection to the broker.

It does not contain any private keys, and might therefore be shared publicly.

PEM certificates & keys

Most MQTT clients cannot use Java Key Stores, but PEM encoded certificates/keys.

A PEM encoded certificate will begin with:

-----BEGIN CERTIFICATE-----

A private key will begin with:

-----BEGIN PRIVATE KEY-----

Treat every private key as confidential.

Setting up a new PKI

Creating a Key store

The command below will create the keystore.

Please change the storepass changeme to a more secure password.

By default this generates a key, valid for ~10 Years (3600), this can be controlled with the validity parameter (in days).

keytool -genkey -keyalg RSA -alias hivemq -keystore hivemq.jks -storepass changeme -validity 3600 -keysize 4096 -dname "CN=united-manufacturing-hub-hivemqce-local-service" -ext "SAN=IP:127.0.0.1"

The command will run for a couple seconds and then exit without any message printed into your Terminal.

Inside your current working directory, there will be a new file called hivemq.jks.

If you want to explore, whats inside .jks files, we recommend using Keystore Explorer (FOSS).

Creating client certificates

  1. Create a new folder, called pki inside your current working directory.

  2. The command below creates a new self-signed client certificate.

    Replace $servicename with the name of whatever you want to connect to HiveMQ (example: mqtt_kafka_bridge).

    The $servicename should not contain any whitespaces.

    openssl req -new -x509 -newkey rsa:4096 -keyout "pki/$servicename-key.pem" -out "pki/$servicename-cert.pem" -nodes -days 3600 -subj "/CN=$servicename"
    

    After a few seconds you will see two new files inside the PKI folder.

    • $servicename-key.pem is the private key for the service
      • This key should be handled as confidential
    • $servicename-cert.pem is the certificate for the service
      • The certificate can be shared publicly
  3. JKS cannot import PEM files directly, therefore we need to convert it, before importing it into the truststore.

    Again, replace $servicename with the same name as above.

    openssl x509 -outform der -in "pki/$servicename-cert.pem" -out "pki/$servicename.crt"
    

    This generates a new file, $servicename.crt inside your PKI folder, which can also be shared publicly.

  4. In the last step, we import the .crt file into the truststore.

    If you haven’t created any truststore yet, it will automatically create it for you.

    Again, replace $servicename with the same name as above.

    $hivepass is the password of your truststore, you should replace it with a more secure password.

     keytool -import -file "pki/$servicename.crt" -alias "$servicename" -keystore hivemq-trust-store.jks -storepass $hivepass
    
  5. If you want to create another service, repeat these steps

Importing the PKI into the UMH Stack

If you take a look at our values.yaml file, you will see a lot of certificates under the _000_commonConfig -> infrastructure -> mqtt -> tls key.

These are Base64 encoded.

To encode your keystore & truststore you can use the following command:

openssl base64 -A -in .\hivemq.jks or openssl base64 -A -in .\hivemq-trust-store.jks

The same needs to done for the cert and key of every microservice.

You can alternatively use the below PowerShell script, to convert every PEM file automatically.

Get-ChildItem -Path .\ -Filter *.pem -Recurse -File -Name| ForEach-Object {
    $FileContent = Get-Content $_ -Raw
    $fileContentInBytes = [System.Text.Encoding]::UTF8.GetBytes($FileContent)
    $fileContentEncoded = [System.Convert]::ToBase64String($fileContentInBytes)
    $fileContentEncoded | Set-content ($_ + ".b64")
    Write-Host $_ + ".b64" + "File Encoded Successfully!"
}

Make sure to update the truststore inside the values.yaml each time, you add a new microservice.

Deep dive

If you like to know more, about HiveMQ’s TLS configuration, visit there documentation here.

Last modified February 17, 2023: update (#208) (ea731fc)