使用 pika 与 RabbitMQ 的 TLS 加密连接



我发现在客户端使用 python 的 pika 库无法与 RabbitMQ 代理建立加密连接。我的起点是这里的pika教程示例,但我无法使其工作。我按以下方式进行。

(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( 使用此处所述的 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( 完成此测试的环境是 Ubuntu 18.04,在 Erlang 22.0.7 上使用 RabbitMQ 3.7.17。在客户端,使用了python3版本3.6.8。

问题:有人知道为什么我的测试失败吗?在哪里可以找到使用 pika 设置与 RabbitMQ 的加密连接的完整工作示例?

注意:我很熟悉这篇文章,但帖子中的任何提示都没有帮助我。

在研究了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

如您所见,颁发者 CN 字段和主题 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( 进行此测试的环境是 Ubuntu 18.04,在 Erlang 22.0.7 上使用 RabbitMQ 3.7.17。在客户端,使用了python3版本3.6.8。

最后一句警告:通过这种配置,我能够建立与 RabbitMQ 代理的安全连接,但由于我仍然不明白的原因,启动 RabbitMQ Web 管理工具变得不可能了......

对于任何试图用鼠兔做到这一点的人来说,答案真的是

将主机设置为 client_certificate.pem 文件中client_certificate的 CN 名称

它看起来像

/CN=..本地/O=客户端

你只需要..本地(如果是自签名证书(

最新更新