Unable to use TLS encryption with Letsencrypt certificate
Lefuneste83 opened this issue · 10 comments
What were you doing?
- ...Create an account on Homeassistant to allow MQTT connection
- ...Declare the account in the Octoprint MQTT plugin. Login is OK on MQTT Broker
- ...Enable TLS (change port, enable TLS flag, add local path to fullchain.pem) in the Octoprint MQTT plugin. Login is KO on, MQTT Broker
What did you expect to happen?
Proper Login with TLS enabled
What happened instead?
No login
Version of OctoPrint
1.4.0
Version of the MQTT plugin
0.8.7
Used MQTT broker and its version
Mosquitto broker 5.1
Link to octoprint.log
No error in the logs
Link to contents of Javascript console in the browser
Screenshot(s)/video(s) showing the problem
+1 on this.
I'm using mosquitto-1.6.10-1.el7.x86_64 on CentOS 7 (Digital Ocean VPS) with an SSL cert signed by Letsencrypt. It works fine with the MQTT plugin using TLS on port 8883. My broker doesn't require a login though. Here's the contents of my /etc/mosquitto/mosquitto.conf file:
listener 1883 localhost
listener 8883
certfile /etc/letsencrypt/live/<MY_FQDN>/cert.pem
cafile /etc/letsencrypt/live/<MY_FQDN>/chain.pem
keyfile /etc/letsencrypt/live/<MY_FQDN>/privkey.pemlistener 8083
protocol websockets
certfile /etc/letsencrypt/live/<MY_FQDN>/cert.pem
cafile /etc/letsencrypt/live/<MY_FQDN>/chain.pem
keyfile /etc/letsencrypt/live/<MY_FQDN>/privkey.pem
and I can see the progress of my print being sent to the broker by using the subscribe command while logged into the broker:
$ mosquitto_sub -h localhost -t octoPrint2/progress/printing
{"progress": 90, "_timestamp": 1605761283, "location": "local", "path": "CE3PRO_F_Ornament_2_loop_v1.gcode"}
{"progress": 91, "_timestamp": 1605761322, "location": "local", "path": "CE3PRO_F_Ornament_2_loop_v1.gcode"}
{"progress": 92, "_timestamp": 1605761409, "location": "local", "path": "CE3PRO_F_Ornament_2_loop_v1.gcode"}
{"progress": 93, "_timestamp": 1605761495, "location": "local", "path": "CE3PRO_F_Ornament_2_loop_v1.gcode"}
I edited the HTML and Javascript files from my light tower project to pull data from the feed over websockets and it can display info on the web page as well. https://github.com/xenophod/MQTT-Light-Tower
I'm thinking it's a Homeassistant configuration that might be causing the issue, and not the MQTT plugin.
I have just moved my mosquitto server over to TLS, using a Let's Encrypt certificate. I also had some trouble getting the plugin to connect initially. I don't really understand the code here :
OctoPrint-MQTT/octoprint_mqtt/__init__.py
Lines 305 to 311 in 08edf0d
The comment on line 309 says we have to specify ca_certs. From the docs I think this was true for earlier Python versions? The default now seems to be to use the system certificate stores.
I hacked this to work on my install by changing these lines to
tls_active = False
if broker_tls:
tls_args = dict((key, value) for key, value in broker_tls.items() if value)
import ssl
self._mqtt.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2)
tls_active = True
This then connects to my server with no problems - I'm not using client certificates though.
Obviously one would want to actually handle the provided settings instead of overriding them in a real implementation. :-)
I agree with @lexitus interpreation that starting from Python 2.7, providing a cert is no longer required by the paho-mqtt package and since Octoprint relies on Python > 2.7, we should be able to adapt this without breaking anything.
I was trying to get @lexitus solution to work but it turns out that things are a little more complicated: If you just hit "Broker requires TLS" and leave everything else untouched, @lexitus solution will not work either. In this case the dict broker_tls
will be empty and thus the tls_set
code will just be bypassed since if broker_tls
yields false. Also in @lexitus solution the tls_args['cert_reqs'] = ssl.CERT_REQUIRED
part is not required since this is the default value according to the docs (see link in his/her post). My hack looks like this now:
tls_active = False
if broker_tls:
tls_args = dict((key, value) for key, value in broker_tls.items() if value)
#ca_certs = tls_args.pop("ca_certs", None)
#if ca_certs: # cacerts must not be None for tls_set to work
self._mqtt.tls_set(**tls_args)
tls_active = True
which leaves all the other settings untouched. For this to work, you need to make sure that broker_tls
is populated, e.g. by providing a cipher like ECDHE
.
For a permanent fix, I would suggest adding the status of the "The broker requires TLS" checkbox to the self._settings
. The code would then change to something like this:
tls_active = self._settings.get_boolean(["broker", "tls"])['tlsActive']
if tls_active:
tls_args = dict((key, value) for key, value in broker_tls.items() if value)
tls_args.pop("tlsActive")
self._mqtt.tls_set(**tls_args)
However, I wasn't able to figure out how the self._settings
attribute gets populated. Looked through all the code but could not find the link where the web form values are being fed into the Python code. Maybe someone with more plugin development experience can point me in the right direction and I'd be happy to open a pull request.
Turns out there is an awesome OctoPrint plugin development tutorial explaining what I needed to know ;-) Was able to figure it out at the cost of a minor GUI imperfection, see the linked pull request.
Any update regarding this issue/PR? I believe I'm running into the same issue. I have a broker configured with LetsEncrypt certificates, and use it with many other clients, however can't find a way to make the MQTT plug-in in OctoPrint connect to it.
Checking the logs, I see this:
2021-12-02 01:04:09,855 - octoprint.plugin - ERROR - Error while calling plugin mqtt
Traceback (most recent call last):
File "/home/pi/oprint/lib/python3.7/site-packages/octoprint/plugin/__init__.py", line 271, in call_plugin
result = getattr(plugin, method)(*args, **kwargs)
File "/home/pi/oprint/lib/python3.7/site-packages/octoprint/util/__init__.py", line 1737, in wrapper
return f(*args, **kwargs)
File "/home/pi/oprint/lib/python3.7/site-packages/octoprint_mqtt/__init__.py", line 83, in on_startup
self.mqtt_connect()
File "/home/pi/oprint/lib/python3.7/site-packages/octoprint_mqtt/__init__.py", line 310, in mqtt_connect
self._mqtt.tls_set(ca_certs, **tls_args)
File "/home/pi/oprint/lib/python3.7/site-packages/paho/mqtt/client.py", line 804, in tls_set
context.load_verify_locations(ca_certs)
@edgauthier If you want, you can try my fix. You can download the zip from the forked repo and install via zip (Settings --> Plugin manager --> More --> Upload file). Uninstall the official plugin first. Let me know how it works for you (you should be able to comment in the pull request)
Thanks! This version fixed the issue for me.
Now that I have confirmation this PR works I'll handle bumping the version and merging later tonight. Thanks @edgauthier
PR has been merged and version 0.8.11 has been released.