4. MQTT over TLS实战配置
说实话,很多团队在 MQTT 上栽跟头,不是因为协议本身多难,而是 TLS 证书配置这一步就卡住了。我见过不少项目,上线前才想起来「哎呀,通信还是明文的」,然后急急忙忙去配证书,结果各种踩坑。
这一章,咱们就彻底搞定它。我会带你从零开始,生成自签名 CA、签发服务端证书、配置 Mosquitto Broker,最后让客户端也能连上来。整个过程我会用我自己的习惯来走,你跟着做就行。
核心目标:让 Broker 和客户端之间的所有通信都经过 TLS 加密,杜绝中间人攻击和明文窃听。
4.1 整体流程:先看一张图
动手之前,我建议你先看看这张流程图。它把整个证书体系的脉络画清楚了。我自己做项目时,习惯先在脑子里过一遍这个流程,不然容易乱。
4.2 准备工作:你需要什么?
嗯,这里要注意。别一上来就敲命令,先把工具备齐。我习惯用 OpenSSL,它基本是 Linux 系统的标配。如果你用的是 Windows,建议装个 WSL 或者 Git Bash,里面也带了 OpenSSL。
| 工具/文件 | 说明 | 备注 |
|---|---|---|
| OpenSSL | 证书生成工具 | 版本 ≥ 1.1.1 |
| Mosquitto | MQTT Broker | 版本 ≥ 2.0 |
| mosquitto_pub/sub | 客户端测试工具 | 随 Mosquitto 安装 |
| CA 证书文件 | ca.crt | 自签名根证书 |
| 服务端证书文件 | server.crt | 由 CA 签发 |
| 服务端私钥文件 | server.key | 必须保密 |
我的习惯:我会在 /etc/mosquitto/certs/ 下统一存放所有证书文件,方便管理。生产环境千万别把私钥放在可公开访问的目录里。
4.3 第一步:生成 CA 根证书(自签名)
CA 根证书是整个信任链的基石。说白了,它就是「我是我」的证明——自己给自己签名。我刚开始学的时候觉得这有点奇怪,但这就是 PKI 体系的玩法。
先生成 CA 私钥,我一般用 RSA 2048 位,够用也快。
# 生成 CA 私钥
openssl genrsa -out ca.key 2048
# 生成 CA 自签名证书,有效期 10 年
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyIoT/CN=MyCA"
这里 -subj 参数里的 CN(Common Name)我填的是 MyCA,你可以改成你自己的标识。但注意,CA 的 CN 不需要跟域名匹配,它只是个标识。
我曾经踩过的坑:有次我图省事,把 CA 证书的有效期设成了 1 年。结果一年后所有设备都连不上 Broker,排查了半天才发现是证书过期了。生产环境建议 CA 有效期设 5-10 年,服务端证书设 1-2 年,定期轮换。
4.4 第二步:生成服务端证书并签发
服务端证书是给 Broker 用的。这里有个关键点:CN 必须填 Broker 的域名或 IP。你想想看,客户端连过来的时候,要验证证书里的 CN 是不是跟它连接的地址一致,否则会报错。
# 生成服务端私钥
openssl genrsa -out server.key 2048
# 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyIoT/CN=broker.example.com"
# 使用 CA 签发服务端证书,有效期 1 年
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 365 -sha256
如果你是在内网测试,CN 可以填 IP 地址,比如 CN=192.168.1.100。但生产环境强烈建议用域名。
重要:生成完证书后,记得检查一下证书内容,确保 CN 正确:
openssl x509 -in server.crt -text -noout | grep Subject:
4.5 第三步:配置 Mosquitto Broker
证书准备好了,接下来就是让 Mosquitto 用上它们。我习惯在配置文件里单独开一个 TLS 监听端口,默认的 1883 可以留着给内网调试用,但生产环境建议关掉明文端口。
编辑 Mosquitto 配置文件(通常是 /etc/mosquitto/mosquitto.conf),加入以下内容:
# TLS 监听端口
listener 8883
# 证书文件路径
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
# 要求客户端必须使用 TLS(但不要求客户端证书)
tls_version tlsv1.2
require_certificate false
这里 require_certificate false 表示只做单向认证——客户端验证 Broker 的身份,但 Broker 不验证客户端。如果你需要双向认证,后面章节会讲。
我的习惯:配置完后,先不要急着启动服务。我会用 mosquitto -c /etc/mosquitto/mosquitto.conf -d 在前台运行一次,看看有没有报错。确认没问题了再以 daemon 方式启动。
4.6 第四步:客户端连接配置
Broker 配好了,客户端怎么连?这里分两种情况:用命令行工具测试,或者用代码连。
4.6.1 命令行测试
用 mosquitto_pub 和 mosquitto_sub 测试最直接。记得带上 CA 证书:
# 订阅端
mosquitto_sub -h broker.example.com -p 8883 --cafile ca.crt -t "test/topic" -d
# 发布端
mosquitto_pub -h broker.example.com -p 8883 --cafile ca.crt -t "test/topic" -m "Hello TLS" -d
-d 参数会打印调试信息,你可以看到 TLS 握手的过程。如果看到 Client connected 就说明成功了。
4.6.2 Python 代码示例
如果你用 Python 写客户端,paho-mqtt 库支持 TLS 配置。下面是我常用的写法:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
client = mqtt.Client()
client.tls_set(ca_certs="ca.crt")
client.on_connect = on_connect
client.connect("broker.example.com", 8883, 60)
client.loop_forever()
注意 tls_set() 的第一个参数就是 CA 证书路径。如果你的 Broker 用了客户端证书认证,还需要传 certfile 和 keyfile。
我曾经踩过的坑:有次我写 Python 客户端,忘了调用 tls_set(),结果连接一直超时。查了半天才发现客户端默认走的是明文 1883 端口,而 Broker 的 8883 端口只接受 TLS 连接。记住:端口和 TLS 配置必须匹配。
4.7 验证与排障
配置完了,怎么确认 TLS 真的生效了?我一般用两个方法:
- 抓包验证:用 Wireshark 抓 8883 端口的包,如果看到
Client Hello和Server Hello以及证书交换,说明 TLS 握手成功了。 - 错误日志:查看 Mosquitto 的日志,如果出现
OpenSSL Error或者certificate verify failed,说明证书有问题。
常见错误及解决方法:
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 连接被拒绝 | 端口未监听或防火墙拦截 | 检查 netstat -tlnp | grep 8883 |
| 证书验证失败 | CN 不匹配或 CA 证书不对 | 检查 CN 是否与连接地址一致 |
| TLS 版本不兼容 | 客户端或服务端 TLS 版本太低 | 统一使用 TLSv1.2 或更高 |
| 私钥文件权限问题 | Mosquitto 用户无法读取 key 文件 | chmod 600 server.key |
我的习惯:我会在客户端用 openssl s_client -connect broker.example.com:8883 -CAfile ca.crt 来测试 TLS 连接是否正常。这个命令会显示完整的握手过程,非常有用。
4.8 小结
到这里,你已经完成了 MQTT over TLS 的完整配置。从生成 CA 证书,到签发服务端证书,再到配置 Broker 和客户端,每一步我都把我在项目中踩过的坑告诉你了。
说实话,TLS 配置本身不复杂,但细节决定成败。证书路径、文件权限、CN 匹配、端口对应——任何一个环节出问题,都会导致连接失败。你按着上面的步骤走,应该不会有大问题。
嗯,这一章的内容就到这儿。证书配好了,通信安全就有了最基本的保障。后面咱们再聊更高级的认证方式。