Mosquitto MQTT:Paho Python设置ca_certs为目录触发IsADirectoryError
问题描述
我有一条可正常运行的mosquitto_sub命令:
# this works fine! mosquitto_sub --capath /etc/ssl/certs/ -u user -P xyz -h hostname.com -p 8883 -t '#'
我编写了对应的Paho Python代码,预期实现相同功能:
import ssl import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) client.subscribe("#") def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) client = mqtt.Client() client.username_pw_set("user", "xyz ") client.tls_set("/etc/ssl/certs/", tls_version=ssl.PROTOCOL_TLSv1_2) # <- line 16 client.on_connect = on_connect client.on_message = on_message client.connect("hostname.com", 8883) client.loop_forever()
但代码运行时抛出异常:
Traceback (most recent call last): File "/workspaces/mqtt.py", line 16, in <module> client.tls_set("/etc/ssl/certs/", tls_version=ssl.PROTOCOL_TLSv1_2) File "/home/vscode/.local/lib/python3.9/site-packages/paho/mqtt/client.py", line 804, in tls_set context.load_verify_locations(ca_certs) IsADirectoryError: [Errno 21] Is a directory
我对此感到困惑,因为Paho MQTT文档说明该参数是“Certificate Authority证书文件的字符串路径”,为何会出现报错?
解决方法
问题核心是mosquitto_sub和Paho Python的参数逻辑差异:
mosquitto_sub的--capath接受证书目录,会自动加载目录内所有CA证书- Paho Python的
tls_set第一个参数ca_certs要求的是单个CA证书文件的路径,传入目录自然触发目录错误
有两种修复方式:
方式一:指定具体CA证书文件
找到系统中合并的CA证书文件(比如多数Linux系统的/etc/ssl/certs/ca-certificates.crt),修改tls_set调用:
client.tls_set("/etc/ssl/certs/ca-certificates.crt", tls_version=ssl.PROTOCOL_TLSv1_2)
方式二:通过SSL上下文加载证书目录
手动创建SSL上下文并指定证书目录,再传给Paho的tls_set_context方法:
import ssl import paho.mqtt.client as mqtt # 回调函数保持不变 def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) client.subscribe("#") def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) client = mqtt.Client() client.username_pw_set("user", "xyz") # 创建SSL上下文并加载证书目录 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.load_verify_locations(capath="/etc/ssl/certs/") client.tls_set_context(context) client.on_connect = on_connect client.on_message = on_message client.connect("hostname.com", 8883) client.loop_forever()
另外注意你代码中username_pw_set的密码末尾多了一个空格("xyz "),建议去掉避免认证失败。
内容的提问来源于stack exchange,提问作者tturbo
相关产品推荐
相关产品推荐

