文章目录
- 1. 背景介绍
- 2. 系统架构
- 3. 证书签发
- 3.1 创建根证书
- 3.2 创建中间证书
- 3.3 创建设备证书
- 3.4 创建服务端证书
- 4. HAProxy开启双向认证
- 5. 验证
- 6. 总结
1. 背景介绍
MQTT协议已经成为当前物联网领域的关键技术之一,当前市面上主流的实现MQTT协议的产品主要有 EMQX、Mosquito、NanoMQ等。本文以EMQX开源版为基础,构建 MQTT Broker 集群,并使用 HAProxy代理 MQTT Broker 集群,由 HAProxy 开启双向认证,并终结TLS,HAProxy 到 MQTT Broker 集群的流量采用非加密模式。
2. 系统架构
设备端携带设备证书向NLB所在的域名发起业务请求,NLB将流量转发到 HAProxy 负载均衡服务,HAProxy校验设备证书的有效性,当校验通过后终结TLS,将流量分发到某个MQTT Broker节点。HAProxy的负载策略可采用循环负载。
3. 证书签发
使用 cfssl 工具签发设备证书。证书信任模型为:
3.1 创建根证书
- 首先创建配置文件config.json
{
"signing": {
"default": {
"expiry": "262800h"
},
"profiles": {
"intermediate": {
"usages": ["cert sign", "crl sign"],
"expiry": "700800h",
"ca_constraint": {
"is_ca": true,
"max_path_len": 1
}
},
"device": {
"usages": [
"client auth",
"signing",
"digital signing",
"key encipherment",
"server auth"
],
"expiry": "262800h"
}
}
}
}
- 创建根证书配置文件 root.json
{
"CN": "emqx.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "WuHan",
"O": "emqx",
"OU": "EMQX Root CA",
"ST": "China"
}
]
}
- 创建根CA证书
cfssl gencert -initca root.json | cfssljson -bare CaRoot
- 执行上边命令后将会得到根证书私钥、根证书请求文件、根证书。
3.2 创建中间证书
- 创建中间证书配置文件 intermediate.json
{
"CN": "intermediate.emqx.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "WuHan",
"L": "XS",
"O": "EMQX intermediate CA",
"OU": "EMQX intermediate CA"
}
]
}
- 使用根CA签发中间证书
cfssl gencert -ca=./CaRoot.pem -ca-key=./CaRoot-key.pem -config=./config.json -profile=intermediate ./intermediate.json | cfssljson -bare CaIntermediate
- 执行上边命令后将会生成中间证书私钥、中间证书申请文件、中间证书
3.3 创建设备证书
- 创建设备证书配置文件device-a-csr.json
{
"CN": "DEVICEAXXXXXXXX",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "WuHan",
"L": "XS",
"O": "EMQX DEVICE",
"OU": "EMQX DEVICE"
}
]
}
- 创建设备证书
cfssl gencert -ca=./CaRoot.pem -ca-key=./CaRoot-key.pem -config=./config.json -profile=device ./device-a-csr.json | cfssljson -bare device-a
- 执行上边命令将会得到设备证书私钥、设备证书申请文件、设备证书
3.4 创建服务端证书
- 创建服务端证书配置文件 emqx-server-csr.json
{
"CN": "emqx.xxx.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Hubei",
"L": "Wuhan",
"O": "emqx",
"OU": "EMQX Server"
}
]
}
- 使用根CA签发服务端证书
cfssl gencert -ca=./CaRoot.pem -ca-key=./CaRoot-key.pem -config=./config.json -profile=device ./emqx-server-csr.json | cfssljson -bare emqx-server
- 执行上边命令将会得到EMQX服务端证书私钥
emqx-server-key.pem
、证书申请文件emqx-server.csr
、服务端证书emqx-server.pem
。 - 将服务端证书私钥与服务端证书合并到一个PEM文件,得到 server-allinone.pem 证书文件。
cat emqx-server-key.pem emqx-server.pem |tee server-allinone.pem
4. HAProxy开启双向认证
修改/etc/haproxy/haproxy.cfg文件,开启MQTT Broker访问端口,并开启双向认证。
frontend emqx-tls
bind *:8091 ssl crt /etc/emqx/certs/server-allinone.pem ca-file /etc/haproxy/certs/CaIntermediate.pem ca-verify-file /etc/haproxy/certs/CaRoot.pem verify required
# 一层证书信任模型,设备证书直接由根证书签发时,ca-file 配置根证书
# bind *:8091 ssl crt /etc/emqx/certs/server-allinone.pem ca-file /etc/haproxy/certs/CaRoot.pem verify required
mode tcp
log global
option tcplog
default_backend emqx-backend
backend emqx-backend
mode tcp
option tcplog
balance roundrobin
default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 500000 maxqueue 10000 weight 100
server emqx-165 10.0.1.165:1883 check-send-proxy send-proxy-v2 check inter 10s fall 2 rise 5
server emqx-171 10.0.1.171:1883 check-send-proxy send-proxy-v2 check inter 10s fall 2 rise 5
- ca-file 指定中间证书,用于校验设备端证书的有效性
- ca-verify-file 指定根CA证书,用于校验中间证书的有效性,如果只有一层信任模型,这个参数通常不会使用
- crt 指定服务端证书,此处的服务端证书包含了证书及私钥
- verify required 表示开启双向认证,
- check-send-proxy send-proxy-v2 用于开启 Proxy Protocol 协议,MQTT Broker 可获取到设备端的IP地址
- maxconn 指定最大连接数,默认值2000,一定要修改这个值,否则设备连接最大数量将会被限制在2000个连接内
当 HAProxy 设置了 check-send-proxy 与 send-proxy-v2 参数后,需要 EMQX 开启 proxy-protocol 协议。开启方式时修改 /etc/emqx/emqx.conf 配置文件,在 1883 监听端口配置 proxy-protocol = true
listeners.tcp.default {
bind = "0.0.0.0:1883"
max_connections = 500000
proxy_protocol = true
}
5. 验证
使用 MQTT客户端工具向NLB所在的IP地址发起连接请求,请求参数携带根CA证书,设备证书,设备私钥,详细信息如下图所示:
点击CONNECT按钮发起连接请求。
如上图所示,客户端成功连接到MQTT Broker。
6. 总结
HAProxy 作为一款非常优秀的四层均衡程序,在大量的生产项目中得到广泛的应用,相较于NGINX在七层负载场景中广泛应用,四层负载均衡服务在TCP服务负载业务场景上有着更好的性能优势。云商的NLB服务作为高可靠的负载均衡服务,为何不直接将NLB的流量负载分发到MQTT Broker节点,还额外的安装HAProxy负载均衡程序,主要原因是云商NLB的功能通常比较基础,无法满足企业额外的定制化需求,所以,大量的业务场景中使用云商的NLB作为第一层负载入口,定制化的业务处理交给后边的HAProxy负载均衡服务实现。