跳至主内容
版本:4.2

故障排除 TLS 连接

概述

本指南介绍了一种方法和一些工具,可以帮助诊断 TLS 连接问题和错误(TLS 警报)。它附属于关于 RabbitMQ 中的 TLS 的主指南。策略是通过消除过程,使用备用的 TLS 实现来测试所需组件,以识别有问题的端(客户端或服务器)。

请记住,如果两个特定组件之间的交互是导致问题的原因,则无法保证此过程能够识别问题。

本指南推荐的步骤是

在使用 RabbitMQ 节点和/或真实 RabbitMQ 客户端进行测试时,检查服务器和客户端的 日志 非常重要。

检查有效节点配置

使用 TLS 设置 RabbitMQ 节点涉及修改配置。在执行任何其他 TLS 故障排除步骤之前,重要的是要验证配置文件位置和有效配置(节点是否已成功加载)。有关详细信息,请参阅 配置指南

检查 TLS 侦听器(端口)

此步骤检查代理是否在 预期端口 上侦听,例如 AMQP 0-9-1 和 1.0 的 5671,MQTT 的 8883 等。

要验证节点上是否已启用 TLS,请使用 [rabbitmq-diagnostics](./man/rabbitmq-diagnostics.8) listeners 命令或 [rabbitmq-diagnostics](./man/rabbitmq-diagnostics.8) status 命令中的 listeners 部分。

侦听器部分看起来会像这样

Interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Interface: [::], port: 5671, protocol: amqp/ssl, purpose: AMQP 0-9-1 and AMQP 1.0 over TLS
Interface: [::], port: 15672, protocol: http, purpose: HTTP API
Interface: [::], port: 15671, protocol: https, purpose: HTTP API over TLS (HTTPS)
Interface: [::], port: 1883, protocol: mqtt, purpose: MQTT

在上面的示例中,节点上有 6 个 TCP 侦听器。其中两个接受 TLS 连接

  • 节点间和 CLI 工具通信(端口 25672
  • AMQP 0-9-1(如果已启用,则为 1.0)侦听器(非 TLS 连接,端口 5672
  • AMQP 0-9-1(如果已启用,则为 1.0)侦听器(TLS 连接,端口 5671
  • HTTP API 侦听器(端口 15672(HTTP)和 15671(HTTPS))
  • MQTT 侦听器(非 TLS 连接,端口 1883)

如果上述步骤不可行,检查节点的 日志文件 是一种可行的替代方法。它应该包含有关已启用 TLS 侦听器的条目,如下所示

2018-09-02 14:24:58.611 [info] <0.664.0> started TCP listener on [::]:5672
2018-09-02 14:24:58.614 [info] <0.680.0> started SSL listener on [::]:5671

如果节点配置为使用 TLS,但未记录类似上述的消息,则可能是配置文件放置在错误的位置,代理未读取该文件,或者在更改配置文件后未重新启动节点。有关配置文件验证的详细信息,请参阅 配置页面

可以使用 lsofnetstat 等工具来验证节点正在侦听的端口,如 故障排除网络 指南中所述。

检查证书、私钥和 CA 捆绑包文件权限

RabbitMQ 必须能够读取其配置的 CA 证书捆绑包、服务器证书和私钥。文件必须存在并且具有适当的权限。权限不正确(例如,文件由 root 或安装它们的另一个超级用户帐户拥有)是 TLS 设置中非常常见的问题。

在 Linux、BSD 和 MacOS 上,目录权限也会影响节点读取文件的能力。

当证书或私钥文件不可读或不存在时,节点将无法接受 TLS 连接,或者 TLS 连接将挂起(行为因 Erlang/OTP 版本而异)。

当使用 新样式配置格式 配置证书和私钥路径时,节点将在启动时检查文件是否存在,如果不存在则拒绝启动。

检查证书、私钥和 CA 捆绑包文件格式

RabbitMQ 节点要求所有证书、私钥和 CA 证书捆绑包文件必须为 PEM 格式。其他格式将不被接受。

可以使用 OpenSSL CLI 工具将其他格式的文件 转换为 PEM 文件

检查 Erlang 中的 TLS 支持

与代理建立 TLS 连接的另一个关键要求是代理本身支持 TLS。通过运行以下命令确认 Erlang VM 支持 TLS:

rabbitmq-diagnostics --silent tls_versions

或者,在 Windows 上

rabbitmq-diagnostics.bat --silent tls_versions

输出将如下所示

tlsv1.2
tlsv1.1
tlsv1
sslv3

对于不提供 rabbitmq-diagnostics tls_versions 命令的版本,请使用

rabbitmqctl eval 'ssl:versions().'

或者,在 Windows 上

rabbitmqctl.bat eval 'ssl:versions().'

在这种情况下,输出将如下所示

[{ssl_app,"9.1"},
{supported,['tlsv1.2','tlsv1.1',tlsv1]},
{supported_dtls,['dtlsv1.2',dtlsv1]},
{available,['tlsv1.2','tlsv1.1',tlsv1,sslv3]},
{available_dtls,['dtlsv1.2',dtlsv1]}]

如果报告了错误,请确认 Erlang/OTP 安装 包含了 TLS 支持

还可以列出节点上可用的密码套件

rabbitmq-diagnostics cipher_suites --format openssl --silent

或者,在 Windows 上

rabbitmq-diagnostics.bat cipher_suites --format openssl --silent

还可以检查本地 Erlang 运行时支持的 TLS 版本。为此,请在命令行中运行 erl(或 Windows 上的 werl.exe)以打开 Erlang shell 并输入

%% the trailing dot is significant!
ssl:versions().

请注意,这将报告本地节点上支持的版本(对于 PATH 中找到的运行时),这可能与被检查的 RabbitMQ 节点使用的版本不同。

使用 OpenSSL 工具测试 TLS 连接

OpenSSL 的 s_clients_server 是常用的命令行工具,可用于测试 TLS 连接和证书/密钥对。它们通过测试备用的 TLS 客户端和服务器实现来帮助缩小问题范围。例如,如果某个 TLS 客户端成功地与 s_server 一起工作,但与 RabbitMQ 节点不能,那么根本原因很可能在服务器端。同样,如果 s_client 客户端可以成功连接到 RabbitMQ 节点,但另一个客户端不能,那么应该首先仔细检查客户端设置。

下面的示例通过在两个单独的 shell(终端窗口)中连接 s_client 客户端和 s_server 服务器来尝试确认证书和密钥可用于建立 TLS 连接。

该示例将假定您具有以下 证书和密钥文件(这些文件名由 tls-gen 使用)

项目位置
CA 证书(公钥)ca_certificate.pem
服务器证书(公钥)server_certificate.pem
服务器私钥server_key.pem
客户端证书(公钥)client_certificate.pem
客户端私钥client_key.pem

在一个终端窗口或标签页中执行以下命令

openssl s_server -accept 8443 \
-cert server_certificate.pem -key server_key.pem -CAfile ca_certificate.pem

它将启动一个 OpenSSL s_server,该服务器使用提供的 CA 证书捆绑包、服务器证书和私钥。它将用于通过测试 TLS 连接到此示例服务器来验证证书。

在另一个终端窗口中,运行以下命令,将 CN_NAME 替换为证书中预期的主机名或 CN 名称

openssl s_client -connect localhost:8443 \
-cert client_certificate.pem -key client_key.pem -CAfile ca_certificate.pem \
-verify 8 -verify_hostname CN_NAME

它将打开与上面启动的示例 TLS 服务器的新 TLS 连接。您可以省略 -verify_hostname 参数,但 OpenSSL 将不再执行该验证。

如果证书和密钥已正确创建,则两个标签页中都会出现 TLS 连接输出。现在,示例客户端和示例服务器之间存在一个连接,类似于 telnet

如果 信任链 能够建立,第二个终端将显示一个验证确认,代码为 0

Verify return code: 0 (ok)

就像使用命令行工具一样,非零代码表示某种错误。

如果报告了错误,请确认证书和密钥已正确生成,并且使用了匹配的证书/私钥对。此外,证书的 使用场景 可以在生成时受到限制。这意味着一个本应用于客户端进行身份验证的证书将被服务器(例如 RabbitMQ 节点)拒绝。

对于适用于自签名证书的环境,我们建议使用 tls-gen 进行生成。

验证可用的密码套件

RabbitMQ 节点和客户端在其允许在 TLS 握手中使用的 密码套件 方面可能受到限制。确保双方有一些共同的密码套件,否则握手将失败。

证书的密钥使用属性也可以限制可使用的密码套件。

请参阅主 TLS 指南中的 配置密码套件公钥使用扩展 以了解更多信息。

openssl ciphers -v

将显示本地 OpenSSL 构建支持的所有密码套件。

尝试连接到 RabbitMQ 节点

一旦 RabbitMQ 节点配置为侦听 TLS 端口,就可以使用 OpenSSL s_client 来测试 TLS 连接的建立,这次是针对该节点。此检查可确定代理是否可能已正确配置,而无需配置 RabbitMQ 客户端。该工具还有助于比较不同客户端的行为。示例假定节点在 localhost 上运行,使用 AMQP 0-9-1 和 AMQP 1.0 的默认 TLS 端口 5671

openssl s_client -connect localhost:5671 -cert client_certificate.pem -key client_key.pem -CAfile ca_certificate.pem

输出应与使用端口 8443 的情况类似。连接建立时,节点日志文件应 包含新条目

2018-09-27 15:46:20 [info] <0.1082.0> accepting AMQP connection <0.1082.0> (127.0.0.1:50915 -> 127.0.0.1:5671)
2018-09-27 15:46:20 [info] <0.1082.0> connection <0.1082.0> (127.0.0.1:50915 -> 127.0.0.1:5671): user 'user' authenticated and granted access to vhost 'virtual_host'

节点将期望客户端执行协议握手(AMQP 0-9-1、AMQP 1.0 等)。如果在短时间窗口内(默认情况下对于大多数协议为 10 秒)未发生这种情况,节点将关闭连接。

使用 Stunnel 验证客户端连接

stunnel 是一个可用于验证 TLS 客户端的工具。在此配置中,客户端将与 stunnel 建立安全连接,stunnel 将解密的数据转发到代理的“常规”端口(例如,AMQP 0-9-1 和 AMQP 1.0 的 5672)。这在一定程度上可以确信客户端 TLS 配置是正确的,并且与代理 TLS 配置无关。

stunnel 是一个专用代理。在此示例中,它将在与代理相同的宿主上以守护进程模式运行。在接下来的讨论中,假定 stunnel 只会临时使用。也可以使用 stunnel 进行 TLS 终止,但这超出了本指南的范围。

在此示例中,stunnel 将连接到代理的未加密端口(5672),并接受来自 TLS 客户端的 TLS 连接(端口 5679)。

参数通过名为 stunnel.conf 的配置文件传递。它包含以下内容

foreground = yes

[rabbit-amqp]
connect = localhost:5672
accept = 5679
cert = client/key-cert.pem
debug = 7

stunnel 启动如下

cat client_key.pem client_certificate.pem > client/key-cert.pem
stunnel stunnel.conf

stunnel 需要一个证书及其对应的私钥。证书和私钥文件必须像上面使用 cat 命令一样连接起来。stunnel 要求密钥不能受密码保护。现在,TLS 客户端应该能够连接到端口 5679,任何 TLS 错误都会出现在启动 stunnel 的控制台上。

验证 RabbitMQ 客户端连接到 RabbitMQ 节点

假设之前的步骤都没有产生错误,那么您可以放心地将经过测试的 TLS 客户端连接到代理的 TLS 端口,确保首先停止任何正在运行的 OpenSSL s_serverstunnel 实例。

证书链和验证深度

当使用由 中间 CA 签名 的客户端证书时,可能需要配置 RabbitMQ 服务器使用更高的 验证深度

验证深度不足将导致 TLS 对端验证失败。

理解 TLS 连接日志错误

在之前的许多步骤中都会生成新的代理日志文件条目。这些条目与控制台命令的诊断输出一起,应有助于识别与 TLS 相关的错误原因。以下是最常见错误条目的列表

记录的错误解释

包含 {undef, [{crypto,hash,... 的条目

使用的 Erlang/OTP 安装中缺少 crypto 模块,或者该模块已过时。在 Debian、Ubuntu 和其他基于 Debian 的发行版上,这通常意味着尚未安装 erlang-ssl 包。

包含 {ssl_upgrade_error, ekeyfile}{ssl_upgrade_error, ecertfile} 的条目

这意味着代理密钥文件或证书文件无效。确认密钥文件与证书匹配,并且两者都为 PEM 格式。PEM 格式是一种可打印编码,具有可识别的分隔符。证书将以 -----BEGIN CERTIFICATE----------END CERTIFICATE----- 分别开头和结尾。密钥文件同样以 -----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY----- 分别开头和结尾。

包含 {ssl_upgrade_failure, ... certify ...} 的条目

此错误与客户端验证有关。客户端提供的证书无效或不提供证书。如果 ssl_options 的 verify 选项设置为 verify_peer,则尝试暂时使用 verify_none 值。确保客户端证书已正确生成,并且客户端正在提供正确的证书。

包含 {ssl_upgrade_error, ...} 的条目

这是一个通用错误,可能有多种原因。确保您使用的是推荐版本的 Erlang。

包含 {tls_alert,"bad record mac"} 的条目

服务器尝试验证接收到的数据块的完整性,但检查失败。这可能是由于有问题的网络设备、客户端中无意的套接字共享(例如,由于使用了 fork(2))或客户端 TLS 实现中的错误。

© . This site is unofficial and not affiliated with VMware.