如何解决Python应用通过TLS连接RabbitMQ(MQTT插件)的证书验证失败问题
问题:Python连接RabbitMQ MQTT插件的TLS证书验证失败?
我使用带有MQTT插件的RabbitMQ,配置如下:
loopback_users.guest = false listeners.tcp = none listeners.ssl.default = 5671 password_hashing_module = rabbit_password_hashing_sha512 # General ssl_options.cacertfile = /etc/rabbitmq/cert/ca_certificate.pem ssl_options.certfile = /etc/rabbitmq/cert/server_certificate.pem ssl_options.keyfile = /etc/rabbitmq/cert/server_key.pem ssl_options.verify = verify_peer ssl_options.fail_if_no_peer_cert = true # Web management.ssl.port = 15672 management.ssl.cacertfile = /etc/rabbitmq/cert/ca_certificate.pem management.ssl.certfile = /etc/rabbitmq/cert/server_certificate.pem management.ssl.keyfile = /etc/rabbitmq/cert/server_key.pem management.load_definitions = /etc/rabbitmq/definitions.json # Mqtt plugin mqtt.allow_anonymous = false mqtt.listeners.ssl.default = 8883 mqtt.listeners.tcp.default = 1883
证书无误,Web端安全连接正常。我尝试用Python应用通过TLS连接RabbitMQ,代码如下:
PATH_CERT = '/<path>/server_certificate.pem' client = paho.Client() client.on_connect = on_connect client.on_publish = on_publish client.on_message = on_message client.username_pw_set(MQTT_USER, MQTT_PASSWORD) client.tls_set(ca_certs = PATH_CERT, tls_version=ssl.PROTOCOL_TLSv1_2) client.tls_insecure_set(False) client.connect('my.domain.pl', 8883, 60) client.loop_forever()
但出现错误:
File "/usr/lib/python3.8/ssl.py", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)
用户名、密码及域名均正确,请问如何解决该证书问题?Python中传入的证书是否正确?
解决方案
你当前代码里传入的证书是错误的。tls_set的ca_certs参数需要传入的是CA根证书(ca_certificate.pem),而非服务器证书(server_certificate.pem)。
原因说明
TLS握手时,客户端需要通过CA根证书验证服务器证书的合法性:服务器证书由CA签发,客户端只有持有对应的CA根证书,才能确认服务器证书是可信的。你现在传递的是服务器证书,无法完成签发者(issuer)的验证流程,因此触发证书验证失败的错误。
修复步骤
- 将
PATH_CERT替换为CA根证书的本地路径,确保该文件与RabbitMQ配置中使用的/etc/rabbitmq/cert/ca_certificate.pem是同一个文件,且未损坏。 - 修改后的核心代码片段:
# 替换为CA根证书的路径 PATH_CA_CERT = '/<path>/ca_certificate.pem' client = paho.Client() # 回调函数、用户名密码配置保持不变 client.tls_set(ca_certs = PATH_CA_CERT, tls_version=ssl.PROTOCOL_TLSv1_2) client.tls_insecure_set(False) client.connect('my.domain.pl', 8883, 60) client.loop_forever()
额外注意事项
- 确认服务器证书的CN(通用名称)或SAN(主题备用名称)包含你连接使用的域名
my.domain.pl,否则即使CA证书正确,仍可能出现验证失败。 - 不要随意开启
client.tls_insecure_set(True),这会跳过证书验证环节,带来安全风险。
内容的提问来源于stack exchange,提问作者Ploxer2
相关产品推荐
相关产品推荐

