使用 TLS 保护集群(节点间)和 CLI 工具通信
概述
RabbitMQ 节点接受来自客户端的连接以及对等集群节点和 CLI 工具的连接。
主要的 TLS 和 TLS 故障排除指南解释了如何使用 TLS 保护客户端连接。可能需要为其他两种连接类型添加加密层和额外的身份验证层。本指南解释了如何做到这一点。
切换节点间和 CLI 工具通信需要配置一些运行时标志。它们为节点提供CA 证书捆绑包和证书/密钥对。CLI 工具也必须配置为使用证书/密钥对,因为启用 TLS 的节点不会接受来自 CLI 工具和对等节点的未加密连接。
本指南假定读者熟悉TLS 的基础知识和对等验证(身份验证),这些内容在主要的 TLS 指南中已涵盖。
本指南还假定您已经为每个集群节点以及将要使用 CLI 工具的每个主机生成了 CA 证书捆绑包和证书/密钥对。在生产环境中,这些证书通常由操作员或部署工具生成。对于开发和实验,有一种快速生成它们的方法,使用 OpenSSL 和 Python。
本指南将引用三个文件
ca_certificate.pem
:证书颁发机构捆绑包server_certificate.pem
:将由配置的节点(和/或 CLI 工具)使用的证书(公钥)server_key.pem
:将由配置的节点(和/或 CLI 工具)使用的私钥
在开始之前,请确保您已准备好这些文件。
基础知识
配置节点以通过启用 TLS 的连接进行通信涉及几个步骤。使用受支持的 Erlang 版本,有两种方法可以做到这一点。
这些步骤在所有受支持的操作系统上都非常相似,但由于 shell 语言不同,在 Windows 上会存在细微差别。
策略一 涉及以下步骤
- 告诉节点使用加密的节点间连接,使用运行时标志
-proto_dist inet_tls
- 将节点要使用的公钥和私钥合并到一个文件中
- 告诉节点在哪里找到其证书和私钥,使用另一个运行时标志
-ssl_dist_opt server_certfile
- 告诉节点任何其他所需的 TLS 设置,使用其他
-ssl_dist_opt
选项,例如:-ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true
以启用 安全重新协商
策略二 非常相似,但不是指定一组运行时标志,这些选项可以在类似于 RabbitMQ 的 advanced.config 文件的文件中指定,并且运行时将指向该文件。因此,步骤是
- 告诉节点使用加密的节点间连接,使用运行时标志
-proto_dist inet_tls
- 部署一个节点间 TLS 设置文件,其中包含有关证书/密钥对位置、CA 捆绑包位置、使用的 TLS 设置等信息
- 告诉节点在哪里找到其节点间 TLS 设置文件,使用另一个运行时标志
-ssl_dist_optfile
我们鼓励操作员选择最适合其选择的部署工具的策略。
对于这两种选项,都使用环境变量将这些选项传递给运行时。最好使用 配置指南 中解释的 rabbitmq-env.conf
来完成此操作。
一旦节点配置了使用 TLS 的节点间连接,CLI 工具(例如 rabbitmqctl
和 rabbitmq-diagnostics
)也必须使用 TLS 与节点通信。普通的 TCP 连接将失败。
部署节点间 TLS
一旦证书/密钥对文件和配置就位,就可以启动新节点。请注意,可能需要先停止节点,然后部署文件和配置,最后启动节点。这是因为配置为使用 TLS 的 CLI 工具将无法连接到不期望启用 TLS 的 CLI 工具连接的节点。
为了使节点和 CLI 工具成功执行 TLS 握手和对等验证,其他节点和 CLI 工具使用的相同的对等验证示例、证书/密钥对必须由初始节点或所有集群节点上都信任的不同 CA 签名。
这与 对等验证如何用于客户端和插件 TLS 连接 没有什么不同。
可以为所有节点和 CLI 工具重用单个证书/密钥对。该证书还可以使用通配符主题备用名称 (SAN) 或通用名称 (CN),例如 *.rabbitmq.example.local
,它将匹配集群中的每个主机名。
策略一(使用单个标志)在 Linux、macOS 和 BSD 上
合并证书和私钥
本指南中介绍的第一种策略要求节点的公钥和私钥合并到一个文件中。我们将其称为合并密钥文件。要合并它们,只需将私钥文件(例如下面的 server_key.pem
)连接到公钥文件(server_certificate.pem
)的末尾,从新行开始
cat server_certificate.pem server_key.pem > combined_keys.pem
这可以使用文本编辑器完成,而不仅仅是 cat
等命令行工具。
为节点间 TLS 配置单个运行时标志
假设上一节中的合并密钥文件已准备就绪,接下来我们推断 Erlang TLS 库路径并在 rabbitmq-env.conf
中导出 ERL_SSL_PATH
以指向它
# These commands ensure that `ERL_SSL_PATH` is the first line in
# /etc/rabbitmq/rabbitmq-env.conf and will preserve the existing
# contents of that file if it already exists
erl -noinput -eval 'io:format("ERL_SSL_PATH=~s~n", [filename:dirname(code:which(inet_tls_dist))])' -s init stop > /tmp/ssl-path.txt
cat /tmp/ssl-path.txt /etc/rabbitmq/rabbitmq-env.conf > /tmp/new-rabbitmq-env.conf
mv -f /tmp/new-rabbitmq-env.conf /etc/rabbitmq/rabbitmq-env.conf
这使得节点可以从该路径加载模块 inet_tls_dist
,该模块用于加密的节点间通信。
步骤二是告诉运行时使用该模块,使用 -proto_dist inet_tls
运行时标志。与其他运行时标志一样,SERVER_ADDITIONAL_ERL_ARGS
是传递它们的最佳且兼容的方式。
请注意,这里 **必须** 使用双引号,因为环境变量值是多行的
# -pa $ERL_SSL_PATH prepends the directory ERL_SSL_PATH points at to the code path
# -proto_dist inet_tls tells the runtime to encrypt inter-node communication
# -ssl_dist_opt server_certfile /path/to/combined_keys.pem tells the runtime
# where to find the combined certificate/key file
# -ssl_dist_opt server_password password required if the private key is encrypted
#
SERVER_ADDITIONAL_ERL_ARGS="-pa $ERL_SSL_PATH \
-proto_dist inet_tls \
-ssl_dist_opt server_certfile /path/to/combined_keys.pem \
-ssl_dist_opt server_password password
下一步是在前面的示例的基础上构建,并为节点间 TLS 连接启用安全重新协商。虽然这是可选的,但强烈建议这样做。相同的 -ssl_dist_opt
可用于启用更多 TLS 相关设置。本示例不涵盖这些设置
# -pa $ERL_SSL_PATH prepends the directory ERL_SSL_PATH points at to the code path
# -proto_dist inet_tls tells the runtime to encrypt inter-node communication
# -ssl_dist_opt server_certfile /path/to/combined_keys.pem tells the runtime
# where to find the combined certificate/key file
# -ssl_dist_opt server_password password required if the private key is encrypted
# -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true enables an additional TLS setting: secure renegotiation
SERVER_ADDITIONAL_ERL_ARGS="-pa $ERL_SSL_PATH \
-proto_dist inet_tls \
-ssl_dist_opt server_certfile /path/to/combined_keys.pem \
-ssl_dist_opt server_password password \
-ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
一旦节点配置了使用 TLS 的节点间连接,CLI 工具(例如 rabbitmqctl
和 rabbitmq-diagnostics
)也必须使用 TLS 与节点通信。普通的 TCP 连接将失败。
这与上面的示例使用 SERVER_ADDITIONAL_ERL_ARGS
所做的事情非常相似,但这次环境变量是 RABBITMQ_CTL_ERL_ARGS
。它控制 CLI 工具使用的运行时标志。
这是完整的 /etc/rabbitmq/rabbitmq-env.conf
文件
# IMPORTANT:
# the following path is system dependent (will
# change depending on the Erlang version, distribution,
# and installation method used). Please double check it before proceeding!
ERL_SSL_PATH="/usr/lib64/erlang/lib/ssl-9.4/ebin"
# -pa $ERL_SSL_PATH prepends the directory ERL_SSL_PATH points at to the code path
# -proto_dist inet_tls tells the runtime to encrypt inter-node communication
# -ssl_dist_opt server_certfile /path/to/combined_keys.pem tells the runtime
# where to find the combined certificate/key file
# -ssl_dist_opt server_password password required if the private key is encrypted
# -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true enables an additional TLS setting: secure renegotiation
SERVER_ADDITIONAL_ERL_ARGS="-pa $ERL_SSL_PATH \
-proto_dist inet_tls \
-ssl_dist_opt server_certfile /path/to/combined_keys.pem \
-ssl_dist_opt server_password password \
-ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
# Same settings as above but for CLI tools
RABBITMQ_CTL_ERL_ARGS="-pa $ERL_SSL_PATH \
-proto_dist inet_tls \
-ssl_dist_opt server_certfile /path/to/combined_keys.pem \
-ssl_dist_opt server_password password \
-ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
策略二(使用单个 TLS 选项文件)在 Linux、macOS 和 BSD 上
为节点间 TLS 使用单独的设置文件
现代 Erlang 版本支持运行时标志 -ssl_dist_optfile
,该标志可用于使用单个文件配置节点间通信的 TLS。这简化了在命令行本身上传递的参数。
这是使用此设置的完整 /etc/rabbitmq/rabbitmq-env.conf
文件。请注意,-ssl_dist_optfile
文件的名称并不重要,但它必须存储在有效的 rabbitmq
用户可读取的位置
# NOTE: the following path is system dependent and will change between Erlang
# versions
ERL_SSL_PATH="/usr/lib64/erlang/lib/ssl-9.4/ebin"
# -pa $ERL_SSL_PATH prepends the directory ERL_SSL_PATH points at to the code path
# -proto_dist inet_tls tells the runtime to encrypt inter-node communication
# -ssl_dist_optfile tells the runtime where to find its inter-node TLS configuration file
SERVER_ADDITIONAL_ERL_ARGS="-pa $ERL_SSL_PATH
-proto_dist inet_tls
-ssl_dist_optfile /etc/rabbitmq/inter_node_tls.config"
RABBITMQ_CTL_ERL_ARGS="-pa $ERL_SSL_PATH
-proto_dist inet_tls
-ssl_dist_optfile /etc/rabbitmq/inter_node_tls.config"
这是一个示例 /etc/rabbitmq/inter_node_tls.config
文件,它使用单独的服务器证书和私钥文件,启用对等验证并要求对等节点提供证书
[
{server, [
{cacertfile, "/full/path/to/ca_certificate.pem"},
{certfile, "/full/path/to/server_certificate.pem"},
{keyfile, "/full/path/to/server_key.pem"},
{password, "password-if-keyfile-is-encrypted"},
{secure_renegotiate, true},
{verify, verify_peer},
{fail_if_no_peer_cert, true}
]},
{client, [
{cacertfile, "/full/path/to/ca_certificate.pem"},
{certfile, "/full/path/to/client_certificate.pem"},
{keyfile, "/full/path/to/client_key.pem"},
{password, "password-if-keyfile-is-encrypted"},
{secure_renegotiate, true},
{verify, verify_peer}
]}
].
这些选项在 Erlang/OTP 文档中有进一步的文档说明。
Windows
上面针对 Linux、macOS 和 BSD 系统介绍的两种策略都可以在 Windows 上使用。所有基本原理都是相同的。
但是,有一些特定于 Windows 的细微差别。首先,由于 Windows shell 解析规则,输出 inet_tls_dist
模块位置的命令是不同的。它看起来像这样
erl -noinput -eval "io:format(""ERL_SSL_PATH=~s~n"", [filename:dirname(code:which(inet_tls_dist))])" -s init stop
接下来,包含自定义环境变量的文件在 Windows 上名为 rabbitmq-env-conf.bat
。此文件 **必须** 保存到安装 RabbitMQ 的管理用户的 %AppData%\RabbitMQ
目录中。
这是使用 -ssl_dist_opfile
设置(上面介绍的策略二)的完整 rabbitmq-env-conf.bat
文件。请注意正斜杠目录分隔符的使用。
@echo off
rem NOTE: If spaces are present in any of these paths,
rem double quotes must be used.
rem NOTE: the following path is **system dependent** and will vary between Erlang versions
rem and installation paths
set SSL_PATH="C:/Program Files/erl10.0.1/lib/ssl-9.0/ebin"
rem -pa $ERL_SSL_PATH prepends the directory ERL_SSL_PATH points at to the code path
rem -proto_dist inet_tls tells the runtime to encrypt inter-node communication
rem -ssl_dist_optfile tells the runtime where to find its inter-node TLS configuration file
set SERVER_ADDITIONAL_ERL_ARGS=-pa %SSL_PATH% ^
-proto_dist inet_tls ^
-ssl_dist_optfile C:/Users/rmq_user/AppData/Roaming/RabbitMQ/inter_node_tls.config
rem Same as above but for CLI tools
set CTL_ERL_ARGS=-pa %SSL_PATH% ^
-proto_dist inet_tls ^
-ssl_dist_optfile C:/Users/rmq_user/AppData/Roaming/RabbitMQ/inter_node_tls.config
下面是一个 inter_node_tls.config
文件示例。与其他操作系统一样,如果需要,还可以设置更多TLS 选项。
[
{server, [
{cacertfile, "C:/Path/To/ca_certificate.pem"},
{certfile, "C:/Path/To/server_certificate.pem"},
{keyfile, "C:/Path/To/server_key.pem"},
{password, "password-if-keyfile-is-encrypted"},
{secure_renegotiate, true},
{verify, verify_peer},
{fail_if_no_peer_cert, true}
]},
{client, [
{cacertfile, "C:/Path/To/ca_certificate.pem"},
{certfile, "C:/Path/To/client_certificate.pem"},
{keyfile, "C:/Path/To/client_key.pem"},
{password, "password-if-keyfile-is-encrypted"},
{secure_renegotiate, true},
{verify, verify_peer}
]}
].