美文网首页物联网与android
EMQ X 服务器 SSL/TLS 安全连接配置指南

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

作者: EMQ | 来源:发表于2019-08-13 15:49 被阅读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,参照下图完成配置:

    image-20190808150338975.png

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

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

    1.png

    双向认证测试

    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,参照下图完成配置:

    image-20190808144846677.png

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

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

    ![画板 14@3x-100.jpg](https://img.haomeiwen.com/i12653154/fe4684c6d753d1e4.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

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

    相关文章

      网友评论

        本文标题:EMQ X 服务器 SSL/TLS 安全连接配置指南

        本文链接:https://www.haomeiwen.com/subject/anqbjctx.html