文档章节

EMQ X 服务器 SSL/TLS 安全连接配置指南

EMQX
 EMQX
发布于 08/13 15:50
字数 1898
阅读 20
收藏 0

前言

EMQ X 内置对 TLS/DTLS 的支持,包括支持单双向认证、X.509 证书等多种身份认证和 LB Proxy Protocol V1/2 等。你可以为 EMQ X 支持的所有协议启用 TLS/DTLS,也可以将 EMQ X 提供的 HTTP API 配置为使用 TLS。本文以自签证书的方式介绍如何在 EMQ X 中为 MQTT 启用 TLS。

自签 CA 并签发证书

创建证书

1.准备

$ docker pull centos:centos7
$ docker run -it --name centos7 centos:centos7 /bin/sh
$ yum install openssl
$ yum install vim
$ mkdir /opt/ssl
$ cd /opt/ssl/
$ cp /etc/pki/tls/openssl.cnf ./
$ rm -rf /etc/pki/CA/*.old
## 生成证书索引库数据库文件
$ touch /etc/pki/CA/index.txt
## 指定第一个颁发证书的序列号
$ echo 01 > /etc/pki/CA/serial
$ rm -rf certs;mkdir certs

2.生成 CA 自签名证书

$ openssl genrsa -out certs/root-ca.key 2048
$ openssl req -new -x509 -days 365 -config ./openssl.cnf -key certs/root-ca.key -out certs/root-cacert.pem -subj "/C=CN/ST=hangzhou/O=EMQ/CN=RootCA"

查看证书

$ openssl x509 -in certs/root-cacert.pem -noout -text
...
            X509v3 Basic Constraints:
                CA:TRUE
...

3.签发客户端证书

$ openssl genrsa -out certs/client.key 2048
$ openssl req -new -days 365 -key certs/client.key -out certs/client-cert.csr -subj "/C=CN/ST=hangzhou/O=EMQ/CN=Client"
$ openssl ca -config ./openssl.cnf -extensions v3_req -days 365 -in certs/client-cert.csr -out certs/client-cert.pem -cert certs/root-cacert.pem -keyfile certs/root-ca.key

查看证书

$ openssl x509 -in certs/client-cert.pem -noout -text
...
            X509v3 Basic Constraints:
                CA:FALSE
...

4.签发服务端证书

$ openssl genrsa -out certs/server.key 2048
$ openssl req -new -days 365 -key certs/server.key -out certs/server-cert.csr -subj "/C=CN/ST=hangzhou/O=EMQ/CN=Server"
$ openssl ca -config ./openssl.cnf -extensions v3_req -days 365 -in certs/server-cert.csr -out certs/server-cert.pem -cert certs/root-cacert.pem -keyfile certs/root-ca.key

5.验证

$ openssl verify -CAfile certs/root-cacert.pem certs/server-cert.pem

单向认证测试

$ openssl s_server -accept 2009 -key certs/server.key -cert certs/server-cert.pem
$ openssl s_client -connect localhost:2009 -CAfile certs/root-cacert.pem -showcerts
Verify return code: 0 (ok)

双向认证测试

$ openssl s_server -accept 2009 -key certs/server.key -cert certs/server-cert.pem -CAfile certs/root-cacert.pem -Verify 1
$ openssl s_client -connect localhost:2009 -key certs/client.key -cert certs/client-cert.pem -CAfile certs/root-cacert.pem -showcerts
Verify return code: 0 (ok)

自签二级 CA 并签发证书

创建证书

1.创建 Root CA

创建 Root CA 自签名证书的步骤与前文一致,不再赘述。

$ ls certs
root-ca.key  root-cacert.pem

2.创建二级 CA

$ openssl genrsa -out certs/second-ca.key 2048
$ openssl req -new -days 365 -key certs/second-ca.key -out certs/second-cacert.csr -subj "/C=CN/ST=hangzhou/O=EMQ/CN=SecondCA"
$ openssl ca -config ./openssl.cnf -extensions v3_ca -days 365 -in certs/second-cacert.csr -out certs/second-cacert.pem -cert certs/root-cacert.pem -keyfile certs/root-ca.key

3.签发客户端证书与服务器证书

与前文类似,只不过需要将 Root CA 的信息替换成 Second CA 的。最后我们将得到以下文件:

$ ls -l certs
total 48
-rw-r--r-- 1 root root  948 Aug  6 05:58 client-cert.csr
-rw-r--r-- 1 root root 3973 Aug  6 05:59 client-cert.pem
-rw-r--r-- 1 root root 1679 Aug  6 05:58 client.key
-rw-r--r-- 1 root root 1675 Aug  6 05:53 root-ca.key
-rw-r--r-- 1 root root 1212 Aug  6 05:53 root-cacert.pem
-rw-r--r-- 1 root root 1679 Aug  6 05:54 second-ca.key
-rw-r--r-- 1 root root  952 Aug  6 05:54 second-cacert.csr
-rw-r--r-- 1 root root 4194 Aug  6 05:54 second-cacert.pem
-rw-r--r-- 1 root root  948 Aug  6 05:59 server-cert.csr
-rw-r--r-- 1 root root 3973 Aug  6 05:59 server-cert.pem
-rw-r--r-- 1 root root 1675 Aug  6 05:59 server.key

4.验证

$ openssl verify -CAfile certs/root-cacert.pem -untrusted certs/second-cacert.pem certs/server-cert.pem
certs/server-cert.pem: OK
$ openssl verify -CAfile certs/root-cacert.pem -untrusted certs/second-cacert.pem certs/client-cert.pem
certs/client-cert.pem: OK
$ cat certs/root-cacert.pem > certs/cacert.pem;cat certs/second-cacert.pem >> certs/cacert.pem
$ openssl verify -CAfile certs/cacert.pem certs/client-cert.pem
certs/client-cert.pem: OK

单向认证测试

1.OpenSSL 作为 Server 与 Client

$ openssl s_server -accept 2009 -key certs/server.key -cert certs/server-cert.pem
$ openssl s_client -connect localhost:2009 -CAfile certs/cacert.pem -showcerts
Verify return code: 0 (ok)

Note: Client 既可以使用 root-cacert.pemsecond-cacert.pem 合并后的 cacert.pem,也可以使用 second-cacert.pem

2.OpenSSL 作为 Client, EMQ X 作为 Server

假设你已经成功安装了 EMQ X,我们将之前生成的证书一并拷贝到 emqx/etc/certs 目录下:

$ cp certs/* emqx/etc/certs/

然后修改 emqx.conf 配置如下:

listener.ssl.external.keyfile = etc/certs/server.key
listener.ssl.external.certfile = etc/certs/server-cert.pem

启动 EMQ X 并将日志等级改为 Debug。

$ ./emqx/bin/emqx start
$ ./emqx/bin/emqx_ctl log set-level debug

使用 openssl s_client 连接 EMQ X 并发送一个 Client ID 为 "a" 的 MQTT Connect 报文。

$ echo -en "\x10\x0d\x00\x04MQTT\x04\x00\x00\x00\x00\x01a" | openssl s_client -connect localhost:8883 -CAfile certs/cacert.pem -showcerts
Verify return code: 0 (ok)

如果你在 emqx/log/erlang.log.1 中看到以下日志,说明 SSL 认证成功。

2019-08-06 15:13:30.748 [debug] 127.0.0.1:60737 [Protocol] RECV CONNECT(Q0, R0, D0, ClientId=a, ProtoName=MQTT, ProtoVsn=4, CleanStart=false, KeepAlive=0, Username=undefined, Password=undefined)

3.emqtt 作为 Client,EMQ X 作为 Server

EMQ X 继续保持运行,编译并启动 emqtt

$ git clone -b v1.0.1 https://github.com/emqx/emqtt.git
$ cd emqtt
$ make
$ erl -pa _build/default/lib/*/ebin
## connect to broker
1> {ok, ConnPid} = emqtt:start_link([{client_id, <<"my_client">>}, {ssl, true}, {ssl_opts, [{cacertfile,"../certs/cacert.pem"}]}, {port, 8883}]).
{ok,<0.80.0>}
2> {ok, _Props} = emqtt:connect(ConnPid).
{ok,undefined}
## subscribe
3> {ok, _Props, _ReasonCodes} = emqtt:subscribe(ConnPid, {<<"hello">>, 0}).
{ok,undefined,[0]}
## publish
4> ok = emqtt:publish(ConnPid, <<"hello">>, <<"Hello World!">>, 0).
ok
## receive message
5> receive
    {publish, Message} ->
        io:format("Message: ~p~n", [Message])
after
    1000 ->
        io:format("Error: receive timeout!~n")
end.
Message: #{client_pid => <0.80.0>,dup => false,packet_id => undefined,
           payload => <<"Hello World!">>,properties => undefined,qos => 0,
           retain => false,topic => <<"hello">>}
ok
## disconnect from broker
6> ok = emqtt:disconnect(ConnPid).

连接建立成功,可以正常订阅发布,SSL 单向认证测试通过。

4.mqtt.fx 作为 Client, EMQ X 作为 Server

EMQ X 继续保持运行,启动 mqtt.fx,参照下图完成配置:

**Note: **这里只能使用 second-cacert.pem 作为 CA Certificate。

点击 Connect 按钮,连接成功,并且可以正常订阅发布,SSL 双向认证通过。

双向认证测试

1.OpenSSL 作为 Server 与 Client

$ openssl s_server -accept 2009 -key certs/server.key -cert certs/server-cert.pem -CAfile certs/cacert.pem -Verify 1
## Use root CA
$ openssl s_client -connect localhost:2009 -key certs/client.key -cert certs/client-cert.pem -CAfile certs/cacert.pem -showcerts
Verify return code: 0 (ok)
## Use second CA
$ openssl s_client -connect localhost:2009 -key certs/client.key -cert certs/client-cert.pem -CAfile certs/second-cacert.pem -showcerts
Verify return code: 19 (self signed certificate in certificate chain)

2.OpenSSL 作为 Client, EMQ X 作为 Server

修改 emqx.conf 配置如下:

listener.ssl.external.keyfile = etc/certs/server.key
listener.ssl.external.certfile = etc/certs/server-cert.pem
listener.ssl.external.cacertfile = etc/certs/cacert.pem
## 开启双向认证
listener.ssl.external.verify = verify_peer
## 禁止单向认证
listener.ssl.external.fail_if_no_peer_cert = true

启动 EMQ X 并将日志等级改为 Debug。

$ ./emqx/bin/emqx start
$ ./emqx/bin/emqx_ctl log set-level debug

使用 openssl s_client 连接 EMQ X 并发送一个 Client ID 为 "a" 的 MQTT Connect 报文。

## Use root CA
$ echo -en "\x10\x0d\x00\x04MQTT\x04\x00\x00\x00\x00\x01a" | openssl s_client -connect localhost:8883 -CAfile certs/cacert.pem -cert certs/client-cert.pem -key certs/client.key -showcerts
Verify return code: 0 (ok)
## Use second CA
$ echo -en "\x10\x0d\x00\x04MQTT\x04\x00\x00\x00\x00\x01a" | openssl s_client -connect localhost:8883 -CAfile certs/second-cacert.pem -cert certs/client-cert.pem -key certs/client.key -showcerts
Verify return code: 19 (self signed certificate in certificate chain)

如果你在 emqx/log/erlang.log.1 中看到以下日志,说明 SSL 双向认证成功。

2019-08-06 15:47:03.925 [debug] 127.0.0.1:61343 [Protocol] RECV CONNECT(Q0, R0, D0, ClientId=a, ProtoName=MQTT, ProtoVsn=4, CleanStart=false, KeepAlive=0, Username=undefined, Password=undefined)

3.emqtt 作为 Client,EMQ X 作为 Server

EMQ X 继续保持运行,启动 emqtt

$ erl -pa _build/default/lib/*/ebin
## connect to broker
1> {ok, ConnPid} = emqtt:start_link([{client_id, <<"my_client">>}, {ssl, true}, {ssl_opts, [{certfile,"../certs/client-cert.pem"},{keyfile,"../certs/client.key"}, {cacertfile,"../certs/cacert.pem"}]}, {port, 8883}]).
{ok,<0.182.0>}
2> {ok, _Props} = emqtt:connect(ConnPid).
{ok,undefined}
## subscribe
3> {ok, _Props, _ReasonCodes} = emqtt:subscribe(ConnPid, {<<"hello">>, 0}).
{ok,undefined,[0]}
## publish
4> ok = emqtt:publish(ConnPid, <<"hello">>, <<"Hello World!">>, 0).
ok
## receive message
5> receive
    {publish, Message} ->
        io:format("Message: ~p~n", [Message])
after
    1000 ->
        io:format("Error: receive timeout!~n")
end.
Message: #{client_pid => <0.182.0>,dup => false,packet_id => undefined,
           payload => <<"Hello World!">>,properties => undefined,qos => 0,
           retain => false,topic => <<"hello">>}
ok
## disconnect from broker
6> ok = emqtt:disconnect(ConnPid).

连接建立成功,可以正常订阅发布,SSL 双向认证测试通过。

4.mqtt.fx 作为 Client, EMQ X 作为 Server

EMQ X 继续保持运行,启动 mqtt.fx,参照下图完成配置:

Note: CA File 可以使用 root-cacert.pemsecond-cacert.pem 合并后的 cacert.pem,也可以使用 second-cacert.pem

点击 Connect 按钮,连接成功,并且可以正常订阅发布,SSL 双向认证通过。


更多信息请访问我们的官网 emqx.io,或关注我们的开源项目 github.com/emqx/emqx ,详细文档请访问 官方文档

© 著作权归作者所有

EMQX
粉丝 4
博文 54
码字总数 71436
作品 0
杭州
私信 提问
EMQ 2.3.5 正式版发布, 支持基于 TLS 连接集群

EMQ 2.3.5 版本发布,新增 etc/ssl_dist.conf 配置文件,正式支持基于 TLS 连接集群。 Bug 修复和增强 Feature: Add etc/ssl_dist.conf file for erlang SSL distribution (emq-relx#178) F......

emqtt
2018/03/05
933
1
Nginx 教程 #3:SSL 设置

大家好!分享即关怀,我们很乐意与你分享其他的一些知识。我们准备了一个 Nginx 指南,分为三个系列。如果你已经知道一些 Nginx 知识或者想扩展你的经验和认知,这个再合适不过了。 我们将告...

oschina
2018/02/02
4.9K
1
Nginx 教程 #3:SSL 设置

大家好!分享即关怀,我们很乐意与你分享其他的一些知识。我们准备了一个 Nginx 指南,分为三个系列。如果你已经知道一些 Nginx 知识或者想扩展你的经验和认知,这个再合适不过了。 我们将告...

Mr_zebra
2018/02/08
18
0
OpenSSL曝出新型漏洞"DROWN",沃通发布安全建议

据悉,外国研究人员发现OpenSSL出现新的安全漏洞"DROWN",该漏洞将对SSL协议造成安全威胁,攻击者有可能利用这个漏洞对https站点进行攻击。沃通CA得知消息后,第一时间发布安全建议,并为SSL...

sslor
2016/03/03
58
0
mbed TLS 简明教程(二)

原文地址 译者:远方的自由 转载请注明出处: http://blog.csdn.net/z2066411585 上一篇文章mbed TLS 简明教程(一) 简要描述了mbed TLS. 下面主要通过示例程序来说明mbed tls的连接过程. 示例...

程序手艺人
2018/01/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Red Hat Enterprise Linux 7.7 下载

Red Hat Enterprise Linux 7.7 下载 链接: https://pan.baidu.com/s/1JzerTht7seAu93S2H9pljQ 提取码: n8tv 链接: https://pan.baidu.com/s/14csR7RO6S0rb_GjOiA4U8w 提取码: 6s5o —————......

zzimac
12分钟前
3
0
五、数据库连接池

[TOC] 1.基本介绍 <u>无连接池的问题</u> 程序开发的过程中每次使用一个Connection对象都会向底层申请一个对象,用完再关闭连接,这使得每个Connection对象的利用率很低,以至于浪费了资源,...

清醒以敬
12分钟前
2
0
哈希算法的四个应用场景

第一个应用是唯一标识,哈希算法可以对大数据做信息摘要,通过一个较短的二进制编码来表示很大的数据. 第二个应用是用于校验数据的完整性和正确性. 第三个应用是安全加密,我们讲到任何哈希算...

无名氏的程序员
16分钟前
2
0
Spring Boot and Rabbit MQ 异常的时候消息的状态

我们有一个处理消息的方法。 在处理消息的时候出现了异常,那出现异常后这个消息会怎么处理呢。 根据我们的实际情况的观察,如果出现了异常。 但是你没有捕获或者处理异常,这个消息会一直存...

honeymoose
23分钟前
3
0
SpringBoot + WebSocket 开发笔记

1. 服务端的实现,我尝试了两种方式: 第一种是用“@ServerEndPoint”注解来实现,实现简单; 第二种稍显麻烦,但是可以添加拦截器在WebSocket连接建立和断开前进行一些额外操作。   不管用...

Airship
26分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部