Mosquitto MQTT Broker SSL Configuration using openssl

 In this tutorial, I will test how to encrypt the communication between mosquitto MQTT Broker and the client and use a Python example.

We will use openssl for certificate and key generation.


In the certificate creation task I referred to the mosquitto-tls man page.


OpenSSL Process


The values I entered in the certificate and key generation process are modified and used appropriately.


Generate a certificate authority certificate and key.

There is one thing to note. In Common Name, be sure to enter the host name where MQTT Broker is running. In my case the hostname is rocky.


[root@rocky ssl]# openssl req -new -x509 -days 73000 -extensions v3_ca -keyout ca.key -out ca.crt


Enter PEM pass phrase:bluebaypem
Country Name (2 letter code) [XX]:kr
State or Province Name (full name) []:Seoul
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:BluebayNetworks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:rocky
Email Address []:spypiggy@mymail.com

[root@rocky ssl]# ls -al
total 16
drwxr-xr-x. 2 root root   52 Apr  2 18:21 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key



Generate a server key without password.


[root@rocky ssl]# openssl genrsa -aes256 -out server.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.......+++++
.................+++++
e is 65537 (0x010001)
Enter pass phrase for server.key:bluebayserver
Verifying - Enter pass phrase for server.key:bluebayserver
[root@rocky ssl]# ls -al
total 16
drwxr-xr-x. 2 root root   52 Apr  2 18:21 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key
-rw-------. 1 root root 1766 Apr  2 18:21 server.key



Generate a certificate signing request to send to the CA


[root@rocky ssl]# openssl req -out server.csr -key server.key -new
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:kr
State or Province Name (full name) []:Seoul
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:BluebayNetworks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:rocky
Email Address []:spypiggy@mymail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:Hellobluebay
An optional company name []:



Send the CSR to the CA, or sign it with your CA key


[root@rocky ssl]# openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 73000
Signature ok
subject=C = kr, ST = Seoul, L = Default City, O = BluebayNetworks.co.kr, CN = spypiggy, emailAddress = spypiggy@email.com
Getting CA Private Key
Enter pass phrase for ca.key:bluebaypem
[root@rocky ssl]# ls -al
total 28
drwxr-xr-x. 2 root root  102 Apr  2 18:24 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key
-rw-r--r--. 1 root root   41 Apr  2 18:24 ca.srl
-rw-r--r--. 1 root root 1294 Apr  2 18:24 server.crt
-rw-r--r--. 1 root root 1078 Apr  2 18:23 server.csr
-rw-------. 1 root root 1675 Apr  2 18:22 server.key



You do not have to create a certificate and key for the client. TLS communication is possible with only the server certificate and key. However, let's try to make it according to the contents introduced on the homepage.


Generate a client key without password(Optional)



[root@rocky ssl]# openssl genrsa -out client.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.........................+++++
...........+++++
e is 65537 (0x010001)
[root@rocky ssl]# ls -al
total 32
drwxr-xr-x. 2 root root  120 Apr  2 19:32 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key
-rw-r--r--. 1 root root   41 Apr  2 19:23 ca.srl
-rw-------. 1 root root 1675 Apr  2 19:32 client.key
-rw-r--r--. 1 root root 1294 Apr  2 19:23 server.crt
-rw-r--r--. 1 root root 1082 Apr  2 19:22 server.csr
-rw-------. 1 root root 1679 Apr  2 19:21 server.key



Generate a certificate signing request to send to the CA(Optional)


[root@rocky ssl]# openssl req -out client.csr -key client.key -new
Enter pass phrase for client.key:bluebayclient
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:kr
State or Province Name (full name) []:Seoul
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:BluebayNetworks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:spypiggy
Email Address []:spypiggy@mymail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:blueclient
An optional company name []:blueclient
[root@rocky ssl]# ls -al
total 36
drwxr-xr-x. 2 root root  138 Apr  2 19:34 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key
-rw-r--r--. 1 root root   41 Apr  2 19:23 ca.srl
-rw-r--r--. 1 root root 1078 Apr  2 19:34 client.csr
-rw-------. 1 root root 1675 Apr  2 19:32 client.key
-rw-r--r--. 1 root root 1294 Apr  2 19:23 server.crt
-rw-r--r--. 1 root root 1082 Apr  2 19:22 server.csr
-rw-------. 1 root root 1679 Apr  2 19:21 server.key



Send the CSR to the CA, or sign it with your CA key(Optional)


[root@rocky ssl]# openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 73000
Signature ok
subject=C = kr, ST = Seoul, L = Default City, O = BluebayNetworks, CN = rocky, emailAddress = spypiggy@mymail.com
Getting CA Private Key
Enter pass phrase for ca.key:
[root@rocky ssl]# ls -al
total 40
drwxr-xr-x. 2 root root  156 Apr  2 19:38 .
dr-xr-x---. 3 root root 4096 Apr  2 17:37 ..
-rw-r--r--. 1 root root 1415 Apr  2 18:20 ca.crt
-rw-------. 1 root root 1854 Apr  2 18:19 ca.key
-rw-r--r--. 1 root root   41 Apr  2 19:38 ca.srl
-rw-r--r--. 1 root root 1294 Apr  2 19:38 client.crt
-rw-r--r--. 1 root root 1078 Apr  2 19:34 client.csr
-rw-------. 1 root root 1675 Apr  2 19:32 client.key
-rw-r--r--. 1 root root 1294 Apr  2 19:23 server.crt
-rw-r--r--. 1 root root 1082 Apr  2 19:22 server.csr
-rw-------. 1 root root 1679 Apr  2 19:21 server.key



Mosquitto Configuration


Now that you have created the necessary certificates and keys, set up to apply TSL to mosquitto. First, modify the mosquitto.conf file. For Rocky Linux, this file exists in /etc/mosquitto directory.

Add certificate and key file path

In my case, the certificate and key files I worked on above are stored in the /root/ssl directory.

cafile /root/ssl/ca.crt
certfile /root/ssl/server.crt
keyfile /root/ssl/server.key


Change service port

The service default port for MQTT is 1883. It is generally recommended to use a different value for TLS.

# =================================================================
# Extra listeners
# =================================================================

# Listen on a port/ip address combination. By using this variable
# multiple times, mosquitto can listen on more than one port. If
# this variable is used and neither bind_address nor port given,
# then the default listener will not be started.
# The port number to listen on must be given. Optionally, an ip
# address or host name may be supplied as a second argument. In
# this case, mosquitto will attempt to bind the listener to that
# address and so restrict access to the associated network and
# interface. By default, mosquitto will listen on all interfaces.
# Note that for a websockets listener it is not possible to bind to a host
# name.
# listener port-number [ip address/host name]
listener 8883



Restart Mosquitto Service


All settings are now complete. Restart the mosquitto MQTT broker.


[root@rocky ssl]# systemctl restart mosquitto
[root@rocky ssl]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8883            0.0.0.0:*               LISTEN      50156/mosquitto     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      927/sshd            
tcp        0      0 0.0.0.0:1883            0.0.0.0:*               LISTEN      50156/mosquitto     
tcp6       0      0 :::8883                 :::*                    LISTEN      50156/mosquitto     
tcp6       0      0 :::22                   :::*                    LISTEN      927/sshd            
tcp6       0      0 :::1883                 :::*                    LISTEN      50156/mosquitto 

You can see that the mosquitto MQTT broker is using port 8883.


MQTT Client Confirguration


All the MQTT client only needs  a ca certificate. You can test with a program installed along with the mosquitto service as follows.






MQTT Python Client


As in the example above, the certificate in the Python program only needs ca.crt.

import paho.mqtt.client as paho
import time
import ssl

broker = 'rocky'
port = 8883
connected = False

def on_connect(client, userdata, flags, rc):
    global connected
    connected = True
    print("Client connected")


def on_log(client, userdata, level, buf):
    print("buf:", buf)

def on_disconnect(client, userdata, rc):
    print("client disconnected")


client = paho.Client ()
client.on_log = on_log
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.tls_set(r"/root/ssl/ca.crt")

client.connect(broker, port)

while not connected:
    time.sleep(1)
    print("Waiting")
    client.loop()

time.sleep(1)
print("Publishing")
client.publish("test", "I'm python client")
time.sleep(1)
client.loop()
time.sleep(1)
client.disconnect()


Now let's run this python program and see if it is receiving from mosquitto_sub.



You can see that "I'm python client" sent from Python is transmitted normally.


Wrapping up

I created a certificate and key using openssl and applied TLS in MQTT Broker. When using MQTT Broker in the internal network, TLS does not necessarily need to be applied. However, when MQTT Broker and client communicate via the Internet, it is often necessary to consider applying TLS to MQTT Broker.


I referenced a lot of information from the following site.



댓글

이 블로그의 인기 게시물

MQTT - C/C++ Client

RabbitMQ - C++ Client #1 : Installing C/C++ Libraries

C/C++ - Everything about time, date