使用pika与RabbitMQ进行TLS加密连接

时间:2019-10-15 21:08:20

标签: ssl rabbitmq pika

我发现无法在客户端使用python的pika库与RabbitMQ代理建立加密连接。我的起点是pika教程示例here,但我无法使其正常工作。我已经进行了如下操作。

(1) RabbitMQ配置文件为:

listeners.tcp.default = 5672
listeners.ssl.default = 5671

ssl_options.verify               = verify_peer
ssl_options.fail_if_no_peer_cert = false
ssl_options.cacertfile           = /etc/cert/tms.crt
ssl_options.certfile             = /etc/cert/tms.crt
ssl_options.keyfile              = /etc/cert/tmsPrivKey.pem

auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
auth_mechanisms.3 = EXTERNAL

(2)使用以下命令启用了 rabbitmq-auth-mechanism-ssl插件

rabbitmq-plugins enable rabbitmq_auth_mechanism_ssl

通过以下方式检查启用状态可以确认成功启用:rabbitmq-plugins list

(3)使用here中所述的openssl工具验证了 TLS证书的正确性。

(4)用于建立连接的客户端程序是:

#!/usr/bin/env python
import logging
import pika
import ssl
from pika.credentials import ExternalCredentials

logging.basicConfig(level=logging.INFO)
context = ssl.create_default_context(
                        cafile="/Xyz/sampleNodeCert/tms.crt")
context.load_cert_chain("/Xyz/sampleNodeCert/node.crt",
                        "/Xyz/sampleNodeCert/nodePrivKey.pem")

ssl_options = pika.SSLOptions(context, '127.0.0.1')
conn_params = pika.ConnectionParameters(host='127.0.0.1',
                                        port=5671,
                                        ssl_options=ssl_options,
                                        credentials=ExternalCredentials())

with pika.BlockingConnection(conn_params) as conn:
     ch = conn.channel()
     ch.queue_declare("foobar")
     ch.basic_publish("", "foobar", "Hello, world!")
     print(ch.basic_get("foobar"))

(5)客户端程序失败,并显示以下错误消息

pika.exceptions.ProbableAuthenticationError: ConnectionClosedByBroker: (403) 'ACCESS_REFUSED - Login was refused using authentication mechanism EXTERNAL. For details see the broker logfile.'

(6)RabbitMQ代理中的日志消息是:

2019-10-15 20:17:46.028 [info] <0.642.0> accepting AMQP connection <0.642.0> (127.0.0.1:48252 -> 127.0.0.1:5671)
2019-10-15 20:17:46.032 [error] <0.642.0> Error on AMQP connection <0.642.0> (127.0.0.1:48252 -> 127.0.0.1:5671, state: starting):
EXTERNAL login refused: user 'CN=www.node.com,O=Node GmbH,L=NodeTown,ST=NodeProvince,C=DE' - invalid credentials
2019-10-15 20:17:46.043 [info] <0.642.0> closing AMQP connection <0.642.0> (127.0.0.1:48252 -> 127.0.0.1:5671)

(7)完成此测试的环境是在Erlang 22.0.7上使用RabbitMQ 3.7.17的Ubuntu 18.04。在客户端,使用的是python3版本3.6.8。

问题:有人对我的测试失败的原因有任何想法吗?在哪里可以找到使用pika与RabbitMQ建立加密连接的完整工作示例?

NB:我熟悉this post,但是帖子中的所有提示都没有帮助我。

1 个答案:

答案 0 :(得分:1)

研究了link上面提供的Luke Bakken之后,我现在可以回答我自己的问题了。关于我的原始示例的主要变化是,我使用无密码用户配置RabbitMQ代理,该用户的名称与服务器端和客户端上TLS证书的CN字段相同。为了说明这一点,下面,我再次详细介绍示例:

(1) RabbitMQ配置文件是:

listeners.tcp.default = 5672
listeners.ssl.default = 5671

ssl_cert_login_from = common_name

ssl_options.verify               = verify_peer
ssl_options.fail_if_no_peer_cert = true
ssl_options.cacertfile           = /etc/cert/tms.crt
ssl_options.certfile             = /etc/cert/tms.crt
ssl_options.keyfile              = /etc/cert/tmsPrivKey.pem

auth_mechanisms.1 = EXTERNAL
auth_mechanisms.2 = PLAIN
auth_mechanisms.3 = AMQPLAIN

请注意,使用ssl_cert_login_from配置选项,我要求从TLS证书的“公用名”(CN)字段中获取RabbitMQ帐户的用户名。

(2)使用以下命令启用 rabbitmq-auth-mechanism-ssl插件

rabbitmq-plugins enable rabbitmq_auth_mechanism_ssl

可以通过以下命令检查启用状态来确认成功启用:rabbitmq-plugins list

(3)签名的TLS证书必须使颁发者和主题CN字段彼此相等,并且等于RabbitMQ代理节点的主机名。就我而言,检查RabbitMQ日志文件(在/var/log/rabbitmq中)显示代理正在运行在名为rabbit@pnp-vm2的节点上。因此,主机名是pnp-vm2。为了检查客户端证书的CN字段,我使用以下命令:

ap@pnp-vm2:openssl x509 -noout -text -in /etc/cert/node.crt | fgrep CN
        Issuer: C = CH, ST = CH, L = Location, O = Organization GmbH, CN = pnp-vm2
        Subject: C = DE, ST = NodeProvince, L = NodeTown, O = Node GmbH, CN = pnp-vm2

如您所见,Issuer CN字段和Subject CN字段都等于:“ pnp-vm2”(它是RabbitMQ代理的主机名,请参见上文)。我尝试仅在两个CN字段之一中使用此名称,但是无法建立与代理的连接。在我的测试环境中,创建具有相同CN名称的客户端证书很容易,但是在操作环境中,这样做可能会困难得多。另外,我不太了解这种限制的原因:是错误还是功能?它起源于我正在使用的特定RabbitMQ库(python的pika)还是AMQP协议中?这些问题可能值得一个专门的帖子。

(4)用于建立连接的客户端程序是:

#!/usr/bin/env python
import logging
import pika
import ssl
from pika.credentials import ExternalCredentials

logging.basicConfig(level=logging.INFO)
context = ssl.create_default_context(cafile="/home/ap/RocheTe/cert/sampleNodeCert/tms.crt")
context.load_cert_chain("/home/ap/RocheTe/cert/sampleNodeCert/node.crt",
                        "/home/ap/RocheTe/cert/sampleNodeCert/nodePrivKey.pem")

ssl_options = pika.SSLOptions(context, 'pnp-vm2')
conn_params = pika.ConnectionParameters(host='a.b.c.d',
                                        port=5671,
                                        ssl_options=ssl_options,
                                        credentials=ExternalCredentials(),
                                        heartbeat=0)

with pika.BlockingConnection(conn_params) as conn:
    ch = conn.channel()
    ch.queue_declare("foobar")
    ch.basic_publish("", "foobar", "Hello, world!")
    print(ch.basic_get("foobar"))
    input("Press Enter to continue...")

此处,“ a.b.c.d”是运行RabbitMQ代理的计算机的IP地址。

(5)完成此测试的环境是在Erlang 22.0.7上使用RabbitMQ 3.7.17的Ubuntu 18.04。在客户端,使用的是python3版本3.6.8。

最后一个警告:通过这种配置,我能够建立与RabbitMQ Broker的安全连接,但是由于我仍然不了解的原因,无法启动RabbitMQ Web管理工具... < / p>