TLS 连接故障排除
概述
本指南介绍了一种方法和一些工具,可以帮助诊断 TLS 连接问题和错误(TLS 警报)。它与关于 RabbitMQ 中的 TLS 的主要指南相辅相成。该策略是在消除过程中使用替代 TLS 实现来测试所需组件,以识别有问题的端点(客户端或服务器)。
请记住,如果两个特定组件之间的交互是造成问题的原因,则此过程不能保证识别出问题。
本指南中推荐的步骤是
- 验证有效配置
- 验证节点监听 TLS 连接
- 验证文件权限
- 验证证书和私钥文件使用的文件格式
- 验证 Erlang/OTP 中的 TLS 支持
- 使用 OpenSSL 命令行工具 验证证书/密钥对并使用替代 TLS 客户端或服务器进行测试
- 验证可用和配置的 密码套件 和证书密钥用法选项
- 使用 TLS 终端代理 验证客户端连接
- 最后,再次测试实际客户端连接与实际服务器连接
当使用 RabbitMQ 节点和/或实际 RabbitMQ 客户端进行测试时,务必检查服务器和客户端的 日志。
检查有效节点配置
使用 TLS 设置 RabbitMQ 节点涉及修改配置。在执行任何其他 TLS 故障排除步骤之前,务必验证配置文件位置和有效配置(节点是否已成功加载)。有关详细信息,请参阅配置指南。
检查 TLS 监听器(端口)
此步骤检查 Broker 是否正在预期端口上监听,例如 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
部分。
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 的连接
- 端口
25672
上的节点间和 CLI 工具通信 - 端口
5672
上用于非 TLS 连接的 AMQP 0-9-1(以及 1.0,如果启用)监听器 - 端口
5671
上用于启用 TLS 连接的 AMQP 0-9-1(以及 1.0,如果启用)监听器 - 端口 15672 (HTTP) 和 15671 (HTTPS) 上的 HTTP API 监听器
- 用于非 TLS 连接的 MQTT 监听器 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,但未记录与上述类似的消息,则可能是配置文件放置位置不正确,并且 Broker 未读取该文件,或者节点在配置文件更改后未重新启动。有关配置文件验证的详细信息,请参阅配置页面。
诸如 lsof
和 netstat
之类的工具可用于验证节点正在监听哪些端口,如网络故障排除指南中所述。
检查证书、私钥和 CA 捆绑文件权限
RabbitMQ 必须能够读取其配置的 CA 证书捆绑包、服务器证书和私钥。这些文件必须存在并具有适当的权限。不正确的权限(例如,文件由安装它们的 root
或另一个超级用户帐户拥有)是 TLS 设置中非常常见的问题。
在 Linux、BSD 和 MacOS 上,目录权限也可能影响节点读取文件的能力。
当证书或私钥文件不可读或不存在时,节点将无法接受启用 TLS 的连接,或者 TLS 连接将挂起(行为因 Erlang/OTP 版本而异)。
当使用新样式配置文件格式配置证书和私钥路径时,节点将在启动时检查文件是否存在,如果不存在,则拒绝启动。
检查证书、私钥和 CA 捆绑文件格式
RabbitMQ 节点要求所有证书、私钥和 CA 证书捆绑文件均为 PEM 格式。不接受其他格式。
可以使用 OpenSSL CLI 工具将其他格式的文件转换为 PEM 文件。
检查 Erlang 中的 TLS 支持
与 Broker 建立 TLS 连接的另一个关键要求是 Broker 中的 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_client 和 s_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 构建支持的所有密码套件。
尝试 TLS 连接到 RabbitMQ 节点
一旦 RabbitMQ 节点配置为监听 TLS 端口,就可以使用 OpenSSL s_client
来测试 TLS 连接建立,这次是针对节点。此检查确定 Broker 是否可能已正确配置,而无需配置 RabbitMQ 客户端。该工具对于比较不同客户端的行为也很有用。该示例假定节点在 AMQP 0-9-1 和 AMQP 1.0 的默认 TLS 端口 5671 上在 localhost
上运行
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 会将解密的数据传递到 Broker 的“常规”端口(例如,AMQP 0-9-1 和 AMQP 1.0 的 5672 端口)。这提供了一定的信心,即客户端 TLS 配置是正确的,而与 Broker TLS 配置无关。
stunnel
是一个专用代理。在此示例中,它将在与 Broker 相同的主机上以守护程序模式运行。在下面的讨论中,假定 stunnel 仅临时使用。也可以使用 stunnel 执行 TLS 终止,但这超出了本指南的范围。
在此示例中,stunnel
将连接到 Broker 的未加密端口 (5672),并接受来自端口 5679 上启用 TLS 的客户端的 TLS 连接。
参数通过名为 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 的客户端连接到 Broker 的启用 TLS 的端口,确保首先停止任何正在运行的 OpenSSL s_server
或 stunnel
实例。
证书链和验证深度
当使用由中间 CA 签名的客户端证书时,可能需要配置 RabbitMQ 服务器以使用更高的验证深度。
验证深度不足将导致 TLS 对等方验证失败。
了解 TLS 连接日志错误
在前面的许多步骤中,将生成新的 Broker 日志文件条目。这些条目以及来自控制台上命令的诊断输出应有助于识别与 TLS 相关的错误的原因。以下是最常见的错误条目列表
记录的错误 | 说明 |
包含 | Erlang/OTP 安装中缺少 |
包含 | 这意味着 Broker 密钥文件或证书文件无效。确认密钥文件与证书匹配,并且两者均为 PEM 格式。PEM 格式是一种可打印的编码,带有可识别的分隔符。证书将分别以 |
包含 | 此错误与客户端验证有关。客户端正在呈现无效证书或未提供证书。如果 ssl_options 的 |
包含 | 这是一个通用错误,可能有多种原因。确保您使用的是推荐版本的 Erlang。 |
包含 | 服务器已尝试验证其接收到的一段数据的完整性,但检查失败。这可能是由于有问题的网络设备、客户端中意外的套接字共享(例如,由于使用了 |