物联网 MQTT 协议 Mosquitto 的 TLS 加密

前文提到过 物联网消息协议-mosquitto-服务器在-centos-7-上的部署, 然而等要部署到云端服务器时,需要采用 TLS 来实现传输层的加密时,碰到了好几个坑。分享如下。

一、使用 Certbot (Let’s Encrypt)证书的坑。

  • 根据官网某帖子的描述,其实都是错的。正确的配置是:

cafile /etc/mosquitto/ssl/certbot-ca.pem
certfile /etc/mosquitto/ssl/cert1.pem
keyfile /etc/mosquitto/ssl/privkey1.pem

其中 certfile 和 keyfile 是 Certbot 产生的证书文件,而 cafile 的文件需要由 Let’s Encrypt的DST_Root_CA_X3.pem 根证书合并 fullchain1.pem 产生:

cat DST_Root_CA_X3.pem fullchain1.pem >certbot-ca.pem

要把这个文件也拷贝到 Mosquitto 客户端,在客户端运行 mosquitto_sub 或者 mosquitto_pub 时需要指定 -cafile certbot-ca.pem

  • 碰到所有证书文件载入错误的消息,Unable to load server key file, 或者 Unable to load CA certificates 一般是文件权限问题,因为 Certbot 的证书目录默认是 root 只读。
    drwx------ 9 root root 4096 Aug 11 16:09 archive
    所以需要手工拷贝证书到 mosquitto 用户可读的目录。基于这一点以及 Let’s Encrypt 证书每三个月需要更新的残酷现实,为了不给设备端添加更新证书的额外流程,最终放弃使用 Let’s Encrypt 证书,采用自己发行证书的办法。另外一个错得离谱的地方是,采用某网站的说法,在 cafile 后面加了等号,都是类似的错误,其实还是文件没有读到,Mosquitto 把等号也作为文件名的一部分了。 看日志即可。

二、自行发证书的坑

  •   这个其实也不能算坑,只要有在Web 服务器发行过证书的经验,就应该知道证书最好不要加密码,否则每次重启服务都需要输入密码。而 Mosquitto 是不支持输入密码的。 下面把流程大概介绍一下:

产生 CA 私钥,这里可以添加一个密码,来保护私钥。

openssl genrsa -out ca-key.pem -des 2048

生成 CA 证书请求文件CSR
openssl req -new -key ca-key.pem -out ca-csr.pem

用 CSR 生成 CA 证书 ca-cert.pem
openssl x509 -req -in ca-csr.pem -signkey ca-key.pem -out ca-cert.pem

产生服务器证书私钥(不要加密码) server-key.pem
openssl genrsa -out server-key.pem 2048

生成服务器证书请求文件 CSR,命令行里 -config 的配置文件可以不要,主要是为了节省每次输入那些CN/OU/Common Name等信息。
openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem

生成服务器证书 server-cert.pem:

openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in server-csr.pem -out server-cert.pem -extensions v3_req -extfile openssl.cnf

这样,我们就得到如下的配置:

cafile /etc/mosquitto/ssl/ca-cert.pem
certfile /etc/mosquitto/ssl/server-cert.pem
keyfile /etc/mosquitto/ssl/server-key.pem

同样的,把 ca-cert.pem 拷贝到每个设备上。或者把 ca-cert.pem 放到 Web 服务器,在设备上用 wget/curl 下载。

三、和客户端(设备)相关的坑

  • 由于设备支持加密方式的问题,需要在服务器端配置特别的 ciphers,可以根据客户端 “openssl ciphers” 命令的输出,直接配置在 ciphers 后面。
  • tls_version 也是一个小坑,在我的环境里,我注释掉了 # tls_version tlsv1

经过以上配置后,在客户端(设备)上,我们就可以用如下的命令来 subscribe 消息了。

mosquitto_sub -v -u "username" -P "Password" -t 'topic' -h mqtt.yj777.cn -p 8883 --cafile ca-cert.pem

作者: 甬洁网络

--移动互联网&物联网技术提供商