如何手动配置Mosquitto的TLS?

MQTT

1 基础知识

1.1 前言

本章将配置Mosquitto的TLS加密通讯,本章内容包括服务器端与客户端的证书创建以及引用。

1.2 TLS

1.2.1 TLS的介绍

– TLS,即英文Transport Layer Security的缩写,中文翻译为传输层安全协议
– TLS,用于防止两个应用程序通过网络进行数据交换时被窃听和篡改
– TLS,协议采用主从式架构模型(即C/S架构)
– TLS,由两层组成,TLS记录协议(TLS Record)和TLS握手协议(TLS Handshake)
– TLS,优势在于能与应用层协议(如HTTP、FTP、Telnet)无缝耦合

1.2.2 TLS的工作原理

– 客户端请求支持TLS协议的服务器创建安全连接并返回客户端支持的密码组合(加密密码算法和加密哈希函数),即握手开始
– 服务和从客户端提供的列表中选出可用的加密和散列函数,并通知客户端
– 客户端确认服务器颁发的证书是有效的
– 客户端使用服务器的公钥加密随机生成秘钥并发给服务器端(该私钥只能由服务器自己的私钥解密)
– 双方利用随机数生成用于加密和解密的对称秘钥,至此TLS握手结束
注:握手完毕直到连接被关闭的通讯都是安全的通讯连接

2 最佳实践

2.1 配置环境

2.1.1 环境信息

Server,
hostname = mosquitto.cmdschool.org
ip addresses = 10.168.0.91
OS = CentOS 7.6 x86_64

Cient,
hostname = client.cmdschool.org
ip addresses = 10.168.0.8
OS = CentOS 7.6 x86_64

2.1.2 部署服务器端

In Server,
本章假设你已经完成Mosquitto的配置,本章使用的范例是1.5.8版本,
https://www.cmdschool.org/archives/6833
如果需要1.6.3版本请参阅如下文章,
https://www.cmdschool.org/archives/6559

2.1.3 开放服务端口

In Server,

firewall-cmd --permanent --add-port=8883/tcp
firewall-cmd --reload
firewall-cmd --list-all

2.2 创建服务器端证书

In Server,

2.2.1 创建证书临时存放目录

mkdir ~/myca

2.2.2 创建证书颁发机构证书和密码

cd ~/myca
openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt

命令行向导如下,

[...]
Enter PEM pass phrase: ******
Verifying - Enter PEM pass phrase: ******
[...]
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Guangdong
Locality Name (eg, city) [Default City]:Dongguan
Organization Name (eg, company) [Default Company Ltd]:cmdschool.org
Organizational Unit Name (eg, section) []:Certificate Authority
Common Name (eg, your name or your server's hostname) []:
Email Address []:

注:“[…]”表示省略,以上设置的密码用于保护自签名的过程(即后面步骤中以上密码验证不通过则不能进行自签名)

2.2.3 创建服务器秘钥

cd ~/myca
openssl genrsa -out mosquitto.cmdschool.org.key 2048

根据Mosquitto服务要求,我们使用不加密的签名创建服务器证书,如果你需要加密签名过程,请使用如下命令创建,

cd ~/myca
openssl genrsa -des3 -out mosquitto.cmdschool.org.key 2048

命令行向导如下,

[...]
Enter pass phrase for server.key: ******
Verifying - Enter pass phrase for server.key: ******

注:以上设置的秘密用于保护下面的签名步骤

2.2.4 创建用于向CA请求签名的CSR证书

cd ~/myca
openssl req -out mosquitto.cmdschool.org.csr -key mosquitto.cmdschool.org.key -new

创建证书的向导如下,

Enter pass phrase for server.key: ******
[...]
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Guangdong
Locality Name (eg, city) [Default City]:Dongguan
Organization Name (eg, company) [Default Company Ltd]:cmdschool.org
Organizational Unit Name (eg, section) []:MQTT
Common Name (eg, your name or your server's hostname) []:mosquitto.cmdschool.org
Email Address []:
[...]
A challenge password []:
An optional company name []:

注意:
– 秘密验证步骤通过之后才能继续创建用于向CA请求签名的CSR证书(或进行自签名的CSR文件)
– 如果使用不加密的签名创建服务器证书,此步骤将被自动跳过
– 当要求输入通用名(即Common Name,简称CN)时,请输入服务器(或代理)主机名或域名
– 证书通用名的值会与客户端访问的服务器域名进行校验,所以设置的值必须谨慎
– 如果是生产环境,请将CSR证书发给CA请求签名并且跳过后面的自签名步骤(即自签名步骤不用执行)

2.2.5 创建自签名证书(可选)

cd ~/myca
openssl x509 -req -in mosquitto.cmdschool.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out mosquitto.cmdschool.org.crt -days 365

命令行向导如下,

[...]
Enter pass phrase for ca.key:

注:
– 以上输入的是骤一创建的CA密码
– 以上使用自己服务器的CA秘钥进行自签名(签名仅用于测试,不建议用于生产环境)

2.3 配置服务器端证书

In Server,

2.3.1 部署证书到配置目录

cd ~/myca
mkdir -p /etc/mosquitto/ca_certificates/
mkdir -p /etc/mosquitto/certs/
cp ca.crt /etc/mosquitto/ca_certificates/
cp mosquitto.cmdschool.org.crt mosquitto.cmdschool.org.key /etc/mosquitto/certs/

证书部署完毕后,我建议你使用以下命令配置证书的安全权限,

chmod 600 /etc/mosquitto/certs/mosquitto.cmdschool.org.key
chown mosquitto:root /etc/mosquitto/certs/mosquitto.cmdschool.org.key

2.3.2 创建引用证书配置

vim /etc/mosquitto/conf.d/tls.conf

加入如下配置,

listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
keyfile /etc/mosquitto/certs/mosquitto.cmdschool.org.key
certfile /etc/mosquitto/certs/mosquitto.cmdschool.org.crt
tls_version tlsv1.2

由于客户端默认使用的是“tls_version”默认是“tlsv1.2”,所以服务端也声明相同的版本,
另外,如果要同时保留1883端口,请按如下配置书写,

port 1883

listener 8883
cafile /etc/mosquitto/ca_certificates/ca.crt
keyfile /etc/mosquitto/certs/mosquitto.cmdschool.org.key
certfile /etc/mosquitto/certs/mosquitto.cmdschool.org.crt
tls_version tlsv1.2

需要注意的是,紧跟端口的配置一般只在声明的端口范围内生效,修改完配置后,你需要重启服务使配置生效,

systemctl restart mosquitto.service

重启完毕后,我们建议你检查服务状态,

systemctl status mosquitto.service

并且,查看加密端口的倾听状态,

netstat -antp | grep mosquitto

如果信息显示如下则正常,

tcp        0      0 0.0.0.0:8883            0.0.0.0:*               LISTEN      27164/mosquitto
tcp6       0      0 :::8883                 :::*                    LISTEN      27164/mosquitto

2.4 服务端自测TLS证书

In Server,

2.4.1 配置名称解析

echo '10.168.0.91 mosquitto.cmdschool.org' >> /etc/hosts

注:以上仅适用于测试环境,生产环境请通过DNS实现名称解析

2.4.2 订阅主题

mosquitto_sub -t 'test/topic' -v --cafile ~/myca/ca.crt -h mosquitto.cmdschool.org

注:以上命令启动后会一直倾听,请不要按【Ctrl+C】等键关闭

2.4.3 发布消息

mosquitto_pub -t 'test/topic' -m 'hello world' --cafile ~/myca/ca.crt -h mosquitto.cmdschool.org

2.5 配置支持的密码算法

In Server,

2.5.1 列出openSSL的加密算法

openssl ciphers

可见如下输出,

ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:IDEA-CBC-SHA:PSK-3DES-EDE-CBC-SHA:KRB5-IDEA-CBC-SHA:KRB5-DES-CBC3-SHA:KRB5-IDEA-CBC-MD5:KRB5-DES-CBC3-MD5:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:KRB5-RC4-SHA:KRB5-RC4-MD5

2.5.2 声明mosquitto支持的加密算法

vim /etc/mosquitto/conf.d/tls.conf

将上一条命令的输出用“ciphers”参数在配置文件内声明,

ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:IDEA-CBC-SHA:PSK-3DES-EDE-CBC-SHA:KRB5-IDEA-CBC-SHA:KRB5-DES-CBC3-SHA:KRB5-IDEA-CBC-MD5:KRB5-DES-CBC3-MD5:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:KRB5-RC4-SHA:KRB5-RC4-MD5

需要注意的是,以上不一定要全部套用,需要根据你的实际环境和要求决定,修改完配置后,你需要重启服务使配置生效,

systemctl restart mosquitto.service

2.5.3 使用订阅主题验证新配置

mosquitto_sub -t 'test/topic' -v --cafile ~/myca/ca.crt

2.5.4 使用发布消息验证新配置

mosquitto_pub -t 'test/topic' -m 'hello world' --cafile ~/myca/ca.crt

2.6 非本机测试

2.6.1 部署证书到客户端

In Server,

scp ~/myca/ca.crt 10.168.0.8:~

2.6.2 配置客户端的名称解析

In Client,

echo '10.168.0.91 mosquitto.cmdschool.org' >> /etc/hosts

注:以上设置仅适用于测试环境,生产环境中请使用DNS代替

2.6.3 向服务器订阅主题

In Client,

mosquitto_sub -t 'test/topic' -v --cafile ~/ca.crt -h mosquitto.cmdschool.org

2.6.4 向服务器发布消息

In Client,

mosquitto_pub -t 'test/topic' -m 'hello world' --cafile ~/ca.crt -h mosquitto.cmdschool.org

注:
– 参数“-h”指定服务器端的域名
– 以上工具请按服务器的安装方法自行编译安装

2.7 要求验证客户端的证书(可选)

2.7.1 创建客户端秘钥

openssl genrsa -out client.key 2048

根据Mosquitto服务要求,我们使用不加密的签名创建服客户端证书,如果你需要加密签名过程,请使用如下命令创建,

cd ~/myca
openssl genrsa -des3 -out client.key 2048

命令行向导如下,

[...]
Enter pass phrase for client.key: ******
Verifying - Enter pass phrase for client.key: ******

注:以上设置的密码用于保护创建给CA的证书签名的CSR请求文件(即下一步骤输入的密码与以上设置不匹配,则无法继续)

2.7.2 创建给CA的证书签名的CSR请求文件

cd ~/myca
openssl req -out client.csr -key client.key -new

命令行向导如下,

Enter pass phrase for client.key: ******
[...]
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Guangdong
Locality Name (eg, city) [Default City]:Dongguan
Organization Name (eg, company) [Default Company Ltd]:cmdschool.org
Organizational Unit Name (eg, section) []:MQTT-Client
Common Name (eg, your name or your server's hostname) []:client1.cmdschool.org
Email Address []:
[...]
A challenge password []:
An optional company name []:

注意:
– 秘密验证步骤通过之后才能继续创建用于向CA请求签名的CSR证书(或进行自签名的CSR文件)
– 如果使用不加密的签名创建客户端证书,此步骤将被自动跳过
– 当要求输入通用名(即Common Name,简称CN)时,请输入客户端主机名或域名(由于服务器与客户端同一台,故而同名)
– 如果是生产环境,请将CSR证书发给CA请求签名并且跳过后面的自签名步骤(即自签名步骤不用执行)

2.7.3 创建自签名证书(可选)

cd ~
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365

命令行向导如下,

[...]
Enter pass phrase for ca.key:

注:
– 以上输入的是服务器端步骤一创建的CA密码
– 以上使用自己服务器的CA秘钥进行自签名(签名仅用于测试,不建议用于生产环境)

2.7.4 部署证书到客户端

In Server,

scp ~/myca/ca.crt ~/myca/client.crt ~/myca/client.key 10.168.0.8:~

2.7.5 订阅主题

In Client,

mosquitto_sub -t 'test/topic' -v --cafile ~/ca.crt --cert ~/client.crt --key ~/client.key  -h mosquitto.cmdschool.org

以上使用“–cert”与“–key”参数向服务器提交客户端证书,如果不使用以上参数,一般会有以下提示,

Error: A TLS error occurred.

2.7.6 发布消息

In Client,

mosquitto_pub -t 'test/topic' -m 'hello world' --cafile ~/ca.crt --cert ~/client.crt --key ~/client.key  -h mosquitto.cmdschool.org

官方文档
====================

官方手册
———–
https://mosquitto.org/man/mosquitto-tls-7.html
https://mosquitto.org/man/mosquitto-conf-5.html
https://mosquitto.org/man/mosquitto_sub-1.html
https://mosquitto.org/man/mosquitto_pub-1.html

知识扩展
———–
https://baike.baidu.com/item/TLS/2979545?fr=aladdin

非官方的参考文章
————–
https://github.com/owntracks/tools/blob/master/TLS/generate-CA.sh
http://rockingdlabs.dunmire.org/exercises-experiments/ssl-client-certs-to-secure-mqtt
https://jpmens.net/2014/07/03/the-mosquitto-mqtt-broker-gets-websockets-support/
https://primalcortex.wordpress.com/2016/03/31/mqtt-mosquitto-broker-with-ssltls-transport-security/
https://segmentfault.com/a/1190000014250065

证书创建视频
————–
https://asciinema.org/a/201826

创建证书多域名和多IP的配置方法
——————————
https://github.com/levitte/openssl/blob/43890d7fc963d8c5ec3084dcf6c6c20b5efcaa7f/doc/man1/req.pod
https://stackoverflow.com/questions/23523456/how-to-give-a-multiline-certificate-name-cn-for-a-certificate-generated-using
https://bowerstudios.com/node/1007

没有评论

发表评论

MQTT
如何自动创建Mosquitto的TLS证书?

1 基础知识 1.1 前言 本章将借助第三方的脚本(generate-CA.sh)配置Mosquit …

MQTT
如何编译部署Eclipse Mosquitto的认证插件?

1 基础知识 1.1 插件的介绍 – 插件用于从一个或多个后端为Mosquitto用户做 …

MQTT
如何编译部署Eclipse Mosquitto 1.5.8?

1 MQTT基础知识 1.1 MQTT的概念 – MQTT即英文“Message Que …