TLS in Python for MQTT
Use TLS in Python for MQTT
Use TLS in Python for MQTT
If you are familiar with the Python Paho MQTT library, implementing TLS is simple.
Ensure you have properly enabled TLS and created and configured TLS certificates. See Secure MQTT with certificates.
You must create a separate server certificate for each computer that runs a FairCom server. Each FairCom server must be configured to use the appropriate server certificate for the computer on which it runs
Each user must have a unique client certificate. A client certificate allows a client program to identify itself to a FairCom server. Each program that wants to use a certificate must be configured to send the certificate to the server.
Note
Do not use a client certificate in a client program to connect to a FairCom server that is not configured with a certificate.
Ensure you meet the prerequisites before this procedure.
Configure the
MQTTS
listener in theservices.json
file to use your CA certificate, server certificate, and private key.Ensure the
"enabled"
property is set totrue
.Update the
"tls"
object:Update the
"certificateFilename"
property value to the certificate you obtained for this FairCom server.Add a
"privateKeyFilename"
property and set it to the private key for this FairCom server.Add a
"certificateAuthoritiesFilename"
property and set it to the path and filename containing CA certificate.Note
This is the certificate from the CA that signed the server certificate.
Save any changes.
Restart the server for the changes to take effect.
MQTTS
listener{ "serviceName": "mqtts8883", "description": "Port 8883 using TLS-secured MQTTS protocol for the MQTT broker on all TCP/IP addresses bound to this server", "port": 8883, "protocol": "mqtts", "enabled": true, "tls": { "certificateAuthoritiesFilename": "C:/Certificates/ca.crt", "certificateFilename": "C:/Certificates/server.crt", "privateKeyFilename": "C:/Certificates/server.key" } },
MQTTWSS
listener{ "serviceName": "mqttwss9002", "description": "Port 9002 using TLS-secured WebSocket protocol for the MQTT broker on all TCP/IP addresses bound to this server", "port": 9002, "protocol": "mqttwss", "enabled": true, "tls": { "certificateAuthoritiesFilename": "C:/Certificates/ca.crt", "certificateFilename": "C:/Certificates/server.crt", "privateKeyFilename": "C:/Certificates/server.key" } }
Ensure you meet the prerequisites before this procedure.
Update the
"port"
property value to the TLS port used by your broker.Call
tls_set()
on yourpaho.mqtt.client
class object with the following parameters (see Example program):ca_certs
certfile
keyfile
Ensure you meet the prerequisites before this procedure.
Create a
callback
function that will print any messages received using the following code:def message_callback( message_client, userdata, message ): print( message.payload.decode( 'utf8' ) )
Define a client using the following code:
Note
To use a secure WebSocket, this call only needs the additional parameter of
transport = 'websockets'
.mqtts_client = mqtt.Client( client_id = "MQTTS Client ID" )
Enable TLS by calling
tls_set()
on the newly created client using the following code:mqtts_client.tls_set( ca_certs = "/Certificates/ca.crt", certfile = "/Certificates/client.crt", keyfile = "/Certificates/client.key" )
Assign the message callback to the client using the following code:
Note
There are many callbacks in the Paho library, including
on_connect
,on_connect_fail
,on_disconnect
,on_message
,on_publish
,on_subscribe
,on_unsubscribe
,on_log
,on_socket_open
,on_socket_close
,on_socket_register_write
,on_socket_unregister_write
.mqtts_client.on_message = message_callback
Call
loop_start()
on the client to begin processing MQTT events using the following code:mqtts_client.loop_start()
Connect the client and server using the following code:
Note
The port is set to
8883
. This must match the port configured inservices.json
. The broker address must also match the address in its certificate.mqtts_client.connect( "MyServer.local", port = 8883 )
Wait a few seconds or use the
on_connect
callback as a guide to when the connection has been made.Note
The connection will appear instantaneously, but work is happening in the background.
Subscribe to a topic of your choice using the following code:
mqtts_client.subscribe( "test/MqttsTopic" )
Publish to your chosen topic using the following code:
mqtts_client.publish( "test/MqttsTopic", "Simple MQTTS message" )
Implement a simple non-blocking delay using the following code:
Note
Do this step because even though the message will arrive in a few milliseconds, your code could finish before the message arrives.
count = 0while count < 5: time.sleep( 1 ) count += 1
Observe the message:
Note
Receiving the message means your client was able to subscribe and publish to your broker using TLS for encryption and authentication.
Simple MQTTS message
Close the connection using the following code:
mqtts_client.unsubscribe( "test/MqttsTopic" ) mqtts_client.disconnect() mqtts_client.loop_stop()
import time import paho.mqtt.client as mqtt # If this fails, do "pip install paho-mqtt" import ssl use_client_certificate = True # Change to False to log in to MQTT broker using a client username/password. ca_certificate_file = "ca.crt" # File that holds the CA certificate which signed the server certificate used by the broker and the client certificate used by this script. # These two are for logging into the broker with a client certificate. client_certificate_file = "user1Client.pem" # If this also contains the client's private key, set 'client_key_file' to None. client_key_file = None # If 'client_certificate_file' does not contain the private key, specify the private key file here. Otherwise, use None. client_key_file_password = None # password to use if client's private key is encrypted. Otherwise, use None. If the key is encrypted and this is None, you will be asked for the password at runtime. # These two are for logging into the broker with a username/password, instead of a client certificate. client_username = "user1" client_password = "pass1" # Make some callback functions which set global status variables. connected=subscribed=published=False def on_connect( connect_client, userdata, flags, connect_reason_code, connect_properties = None ): # 'I connected to the MQTT broker' callback global connected print( "Connected!" ) connected = True def on_disconnect( disconnect_client, userdata, rc ): # 'I lost my connection to the MQTT broker' callback global connected print( f"client disconnected with reason code {rc}" ) connected = False def on_subscribe( sub_client, userdata, mid, granted_qos ): # 'I subscribed' callback global subscribed print( f"subscribed with qos={granted_qos}\n" ) subscribed = True def on_unsubscribe( sub_client, userdata, mid ): # 'I unsubscribed' callback global subscribed print( "unsubscribed\n" ) subscribed = False def on_message( message_client, userdata, message ): # 'message arrived' callback print( "message received: ", str( message.payload.decode( "utf-8" ) ) ) def on_publish( pub_client, userdata, mid ): # 'I published message' callback global published print( f"data published mid={mid}\n" ) published = True if __name__ == "__main__": mqtts_client = mqtt.Client( client_id = "MQTTS Client ID" ) topic_name = "My Test Topic" if use_client_certificate: # Connect to the MQTT broker using a username/password mqtts_client.tls_set( ca_certs = ca_certificate_file, certfile = client_certificate_file, keyfile = client_key_file, keyfile_password=client_key_file_password, tls_version=ssl.PROTOCOL_TLSv1_2) mqtts_client.tls_insecure_set(False) else: # Connect to the MQTT broker using a username/password mqtts_client.tls_set( ca_certs = ca_certificate_file, tls_version=ssl.PROTOCOL_TLSv1_2) mqtts_client.tls_insecure_set(False) mqtts_client.username_pw_set(client_username, client_password) # specify the username and password # Hook up the callback functions mqtts_client.on_connect = on_connect mqtts_client.on_disconnect = on_disconnect mqtts_client.on_publish = on_publish mqtts_client.on_subscribe = on_subscribe mqtts_client.on_unsubscribe = on_unsubscribe mqtts_client.on_message = on_message # Connect to the MQTT broker and start Paho's event loop print("Connecting to the MQTT broker...") mqtts_client.connect( "localhost", port = 8883 ) mqtts_client.loop_start() while not connected: # Wait until the connection completes time.sleep( 0.5 ) print("Subscribing to topic...") mqtts_client.subscribe( topic_name ) while not subscribed: # Wait until the subscription completes time.sleep( 0.5 ) print("Publishing message to topic...") mqtts_client.publish( topic_name, "Simple MQTT test message" ) while not published: # Wait until the publish completes time.sleep( 0.1 ) for i in range(5): # Wait 5 seconds for the message to arrive time.sleep( 1 ) print("Unsubscribing from the topic...") mqtts_client.unsubscribe( topic_name ) while subscribed: # Wait until the un-subscription completes time.sleep( 0.5 ) print("Disconnecting from the MQTT broker...") mqtts_client.disconnect() while connected: # Wait until the disconnect completes time.sleep( 0.5 ) mqtts_client.loop_stop() print("Done!")
import time import paho.mqtt.client as mqtt def message_callback( message_client, userdata, message ): print( message.payload.decode( 'utf8' ) ) if __name__ == "__main__": mqtts_client = mqtt.Client( client_id = "MQTTS Client ID", transport = 'websockets' ) mqtts_client.tls_set( ca_certs = "/Certificates/ca.crt", certfile = "/Certificates/client.crt", keyfile = "/Certificates/client.key" ) mqtts_client.on_message = message_callback mqtts_client.loop_start() mqtts_client.connect( "MyServer.local", port = 9002 ) time.sleep( 2 ) mqtts_client.subscribe( "test/MqttWssTopic" ) mqtts_client.publish( "test/MqttWssTopic", "Simple MQTT WSS message" ) count = 0 while count < 5: time.sleep( 1 ) count += 1 mqtts_client.unsubscribe( "test/MqttWssTopic" ) mqtts_client.disconnect() mqtts_client.loop_stop()