启用 TLS 连接的故障排除
概述
本指南介绍了一种方法和一些工具,可以帮助诊断 TLS 连接问题和错误(TLS 警报)。它与关于 RabbitMQ 中的 TLS 的主要指南相辅相成。该策略是在排除过程中使用替代的 TLS 实现来测试所需的组件,以识别有问题的端点(客户端或服务器)。
请记住,如果两个特定组件之间的交互导致问题,则此过程无法保证识别问题。
本指南中推荐的步骤为
- 验证 有效配置
- 验证节点 是否侦听 TLS 连接
- 验证 文件权限
- 验证证书和私钥文件使用的 文件格式
- 验证 Erlang/OTP 中的 TLS 支持
- 验证证书/密钥对,并使用 OpenSSL 命令行工具 测试替代的 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 的连接
- 端口
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 连接 1883 上的 MQTT 侦听器
如果上述步骤不可行,检查节点的 日志文件 可能是一种可行的替代方法。它应该包含有关已启用 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 但未记录类似上述的消息,则可能是配置文件放置在错误的位置并且未被代理读取,或者节点在配置文件更改后未重新启动。有关配置文件验证的详细信息,请参阅 配置页面。
lsof
和 netstat
等工具可用于验证节点正在侦听哪些端口,如 网络故障排除 指南中所述。
检查证书、私钥和 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_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
它将启动一个使用提供的 CA 证书捆绑包、服务器证书和私钥的 OpenSSL s_server
。它将用于使用测试 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 节点建立 TLS 连接
一旦 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 客户端在端口 5679 上的 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 的客户端连接到代理的启用 TLS 的端口,并确保首先停止任何正在运行的 OpenSSL s_server
或 stunnel
实例。
证书链和验证深度
当使用由中间 CA 签名的客户端证书 时,可能需要配置 RabbitMQ 服务器以使用更高的 验证深度。
验证深度不足会导致 TLS 对等方验证失败。
了解 TLS 连接日志错误
在前面的许多步骤中,将生成新的代理日志文件条目。这些条目连同控制台命令的诊断输出应该有助于确定 TLS 相关错误的原因。以下是最常见的错误条目的列表
已记录的错误 | 解释 |
包含 | 使用的 Erlang/OTP 安装中缺少 |
包含 | 这意味着代理密钥文件或证书文件无效。确认密钥文件与证书匹配,并且两者都为 PEM 格式。PEM 格式是一种可打印的编码,具有可识别的分隔符。证书将以 |
包含 | 此错误与客户端验证相关。客户端提供的证书无效或没有证书。如果 ssl_options 将 |
包含 | 这是一个可能有多种原因的通用错误。确保您使用的是推荐版本的 Erlang。 |
包含 | 服务器已尝试验证其接收到的数据的一部分的完整性,但检查失败。这可能是由于网络设备出现问题、客户端中意外的套接字共享(例如,由于使用了 |