使用 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
告诉节点在哪里可以找到其证书和私钥。 - 使用其他
-ssl_dist_opt
选项告诉节点任何所需的附加 TLS 设置,例如:-ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true
以启用安全重新协商
策略二非常相似,但不是指定一组运行时标志,这些选项可以指定在一个类似于 RabbitMQ 的advanced.config 文件的文件中,并且运行时将指向该文件。因此,步骤如下:
- 使用运行时标志
-proto_dist inet_tls
告诉节点使用加密的节点间连接。 - 部署一个节点间 TLS 设置文件,其中包含有关证书/密钥对位置、CA 捆绑包位置、使用的 TLS 设置等信息。
- 使用另一个运行时标志
-ssl_dist_optfile
告诉节点在哪里可以找到其节点间 TLS 设置文件。
我们鼓励运营商选择最适合其选择的部署工具的策略。
对于这两个选项,环境变量都用于将这些选项传递给运行时。这最好使用 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"
Linux、macOS 和 BSD 上的策略二(使用单个 TLS 选项文件)
使用单独的设置文件进行节点间 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}
]}
].