身份验证、授权、访问控制
概述
本文档介绍了 RabbitMQ 中的 身份验证 和 授权 功能。它们共同允许操作员控制对系统的访问。
不同的用户只能被授予对特定 虚拟主机 (vhost) 的访问权限。他们在每个虚拟主机中的权限也可以受到限制。
RabbitMQ 支持两种主要的 身份验证机制 以及多种 身份验证和授权后端。
本指南涵盖了各种身份验证、授权和用户管理主题,例如:
- 访问控制基础
- 默认虚拟主机和用户
- 对默认用户施加的 连接限制
- 授权和资源权限
- 如何使用 CLI 工具 管理用户和权限
- 如何更改 所使用的身份验证或授权后端,或使用后端组合
- 如何 使用客户端 TLS 证书信息进行身份验证
- 如何 限制对主题交换机中主题的访问
- 用户标签及其使用方式
- 如何轮换凭据并 撤销用户的访问权限
- 生成密码时的 Shell 转义 字符
- 如何 预创建用户 及其权限
- 身份验证 和 授权失败 的故障排除
基于密码的 身份验证有专门的指南。OAuth 2 支持 和 TLS 支持(包括基于 x.509 证书的身份验证)这两个密切相关的主题也在专门的指南中进行了介绍。
术语和定义
身份验证和授权经常被混淆或互换使用。这是不对的,在 RabbitMQ 中,两者是分开的。为简单起见,我们将身份验证定义为“识别用户是谁”,将授权定义为“确定用户被允许做什么和不被允许做什么”。
基础知识
当客户端 连接 到 RabbitMQ 时,它们会指定一组凭据:用户名-密码对、JWT 令牌 或 x.509 证书。每个连接都有一个已通过身份验证的关联用户。它还针对一个 虚拟主机,用户必须在该主机上拥有一定的权限集。
用户凭据、目标虚拟主机和(可选)客户端 证书 在连接初始化时指定。
存在一对默认的凭据,称为 默认用户。默认情况下,此用户只能 用于主机本地连接。使用默认用户的远程连接将被拒绝。
生产环境 不应使用默认用户。请改为使用生成的凭据创建新的用户账户。
默认虚拟主机和用户
当服务器首次启动并检测到其数据库未初始化或已被重置/删除(节点为“空白节点”)时,它会初始化一个全新的数据库,包含以下资源:
- 一个名为
/(斜杠)的 虚拟主机 - 一个名为
guest的用户,默认密码为guest,被授予对/虚拟主机的完全访问权限
如果空白节点 在启动时导入定义,则不会创建此默认用户。
强烈建议 预先配置一个带有生成用户名和密码的新用户,或者 删除 guest 用户,或者至少将其密码 更改 为公众不知道的、合理的安全生成值。
身份验证:你是谁?
在应用程序连接到 RabbitMQ 并且能够执行操作之前,它必须进行身份验证,即出示并证明其身份。有了该身份,RabbitMQ 节点就可以查找其权限并 授权 其访问资源,例如 虚拟主机、队列、交换机等。
验证客户端身份的两种主要方式是 用户名/密码对 和 X.509 证书。用户名/密码对可以与各种 身份验证后端 一起使用,这些后端会对凭据进行验证。
未能通过身份验证的连接将被关闭,并在 服务器日志 中显示错误消息。
使用客户端 TLS (x.509) 证书数据进行身份验证
要使用 X.509 证书验证客户端连接,必须启用内置插件 rabbitmq-auth-mechanism-ssl,并且客户端必须 配置为使用 EXTERNAL 机制。使用此机制时,客户端提供的任何密码都将被忽略。
“guest”用户只能从本地主机连接
默认情况下,禁止 guest 用户从远程主机连接;它只能通过环回接口(localhost)连接。这适用于 所有协议的连接。任何其他用户(默认情况下)不会受到这种限制。
使用默认用户的远程连接将被拒绝,并显示类似于以下的 日志消息
[error] <0.918.0> PLAIN login refused: user 'guest' can only connect via localhost
环回用户列表通过 配置文件 中的 loopback_users 项进行配置。默认情况下,它包含一个条目:用户 guest,因为它拥有广为人知的默认凭据。
可以通过将 loopback_users 配置键设置为 none 来允许 guest 用户从远程主机连接。
强烈建议不要允许使用众所周知的默认凭据的默认用户进行远程连接:这样做会极大地降低集群的安全性。
允许 guest 进行远程连接的极简 RabbitMQ 配置文件 如下所示
# DANGER ZONE!
#
# allowing remote connections for default user is highly discouraged
# as it dramatically decreases the security of the cluster. Delete the default user
# instead and create a new one with generated secure credentials, or use JWT tokens,
# or x.509 certificates for clients to authenticate themselves
loopback_users = none
管理用户和权限
用户和权限可以使用 CLI 工具 和定义导入(见下文)进行管理。
开始之前:Shell 转义和生成密码
生成复杂的密码(通常涉及非字母数字字符)是一种常见的安全实践。这种做法完全适用于 RabbitMQ 用户。
Shell(bash、zsh 等)将某些字符(!、?、&、^、"、'、*、~ 等)解释为控制字符。
当在命令行中为 rabbitmqctl add_user、rabbitmqctl change_password 以及其他接受密码的命令指定密码时,必须针对所使用的 shell 对这些控制字符进行适当的转义。如果不正确转义,命令将失败,或者 RabbitMQ CLI 工具将从 shell 接收到不同的值。
当生成将在命令行上传递的密码时,使用极少数符号(例如 :、=)的长(例如 40 到 100 个字符)字母数字值是最安全的选择。
当通过 HTTP API 创建用户而不需要使用 shell(例如 curl)时,控制字符的限制不适用。但是,根据使用的编程语言,可能需要不同的转义规则。
添加用户
要添加用户,请使用 rabbitmqctl add_user 或 rabbitmqadmin users declare。两者都有多种指定 密码 的方法
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
- cmd
# will prompt for password, only use this option interactively
rabbitmqctl add_user "username"
# Password is provided via standard input.
# Note that certain characters such as !, &, $, #, and so on must be escaped to avoid
# special interpretation by the shell.
echo '2a55f70a841f18b97c3a7db939b7adc9e34a0f1b' | rabbitmqctl add_user 'username'
# Password is provided as a command line argument.
# Note that certain characters such as !, &, $, #, and so on must be escaped to avoid
# special interpretation by the shell.
rabbitmqctl add_user 'username' '2a55f70a841f18b97c3a7db939b7adc9e34a0f1b'
# This example uses a salted password hash instead of a plaintext value.
# To produce a salted hash of a password, use
# 'rabbitmqctl hash_password "my-secret-password"'
rabbitmqctl add_user --pre-hashed-password 'username' '{value produced by "rabbitmqctl hash_password"}'
# Password is provided as a command line argument.
# Note that certain characters such as !, &, $, #, and so on must be escaped to avoid
# special interpretation by the shell.
rabbitmqadmin users declare \
--name 'username' \
--password '2a55f70a841f18b97c3a7db939b7adc9e34a0f1b'
# This exampel uses a salted password hash instead of a plaintext value.
# To produce a salted hash of a password, use
# 'rabbitmqadmin passwords salt_and_hash "my-secret-password"'
rabbitmqadmin users declare \
--name 'username' \
--password-hash "{value producted by 'rabbitmqadmin passwords salt_and_hash'}"
# password is provided as a command line argument
rabbitmqctl.bat add_user 'username' '9a55f70a841f18b97c3a7db939b7adc9e34a0f1d'
# passwords with special characters must be quoted correctly
rabbitmqctl.bat add_user 'username' '"w63pnZ&LnYMO(t"'
# This example uses a salted password hash instead of a plaintext value.
# To produce a salted hash of a password, use
# 'rabbitmqctl.bat hash_password "my-secret-password"'
rabbitmqctl.bat add_user --pre-hashed-password 'username' '{value produced by "rabbitmqctl.bat hash_password"}'
# Password is provided as a command line argument.
# Passwords with special characters must be quoted correctly.
rabbitmqadmin.exe users declare ^
--name "username" ^
--password "9a55f70a841f18b97c3a7db939b7adc9e34a0f1d"
# This exampel uses a salted password hash instead of a plaintext value.
# To produce a salted hash of a password, use
# 'rabbitmqadmin.exe passwords salt_and_hash "my-secret-password"'
rabbitmqadmin.exe users declare ^
--name "username" ^
--password-hash "{value producted by 'rabbitmqadmin.exe passwords salt_and_hash'}"
rem password is provided as a command line argument
rabbitmqctl.bat add_user "username" "9a55f70a841f18b97c3a7db939b7adc9e34a0f1d"
rem passwords with special characters must be quoted correctly
rabbitmqctl.bat add_user "username" "w63pnZ&LnYMO(t"
新添加的用户必须被 授予权限 访问一个或多个虚拟主机,否则其连接将被拒绝。
列出用户
要列出集群中的用户,请使用 rabbitmqctl list_users 或 rabbitmqadmin users list
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl list_users
rabbitmqadmin users list
rabbitmqctl.bat list_users
rabbitmqadmin.exe users list
删除用户
要删除用户,请使用 rabbitmqctl delete_user 或 rabbitmqadmin users delete
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl delete_user 'username'
rabbitmqadmin users delete --name 'username'
rabbitmqctl.bat delete_user 'username'
rabbitmqadmin.exe users delete --name "username"
授予用户权限
要在 虚拟主机 中向用户授予 权限,请使用 rabbitmqctl set_permissions 或 rabbitmqadmin declare permissions
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
# First ".*" for configure permission on every entity
# Second ".*" for write permission on every entity
# Third ".*" for read permission on every entity
rabbitmqctl set_permissions -p "custom-vhost" "username" ".*" ".*" ".*"
# Grant full permissions to a user in a virtual host
rabbitmqadmin declare permissions \
--vhost "custom-vhost" \
--user "username" \
--configure ".*" \
--write ".*" \
--read ".*"
# First ".*" for configure permission on every entity
# Second ".*" for write permission on every entity
# Third ".*" for read permission on every entity
rabbitmqctl.bat set_permissions -p 'custom-vhost' 'username' '.*' '.*' '.*'
# Grant full permissions to a user in a virtual host
rabbitmqadmin.exe declare permissions ^
--vhost "custom-vhost" ^
--user "username" ^
--configure ".*" ^
--write ".*" ^
--read ".*"
清除用户在虚拟主机中的权限
要从用户在 虚拟主机 中的 权限 中撤销,请使用 rabbitmqctl clear_permissions 或 rabbitmqadmin delete permissions
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
# Revokes permissions in a virtual host
rabbitmqctl clear_permissions -p "custom-vhost" "username"
# Revokes permissions from a user in a virtual host
rabbitmqadmin delete permissions \
--vhost "custom-vhost" \
--user "username"
# Revokes permissions in a virtual host
rabbitmqctl.bat clear_permissions -p 'custom-vhost' 'username'
# Revokes permissions from a user in a virtual host
rabbitmqadmin.exe delete permissions ^
--vhost "custom-vhost" ^
--user "username"
为新虚拟主机预配置默认用户权限
可以在 rabbitmq.conf 中预配置默认用户权限,以便在创建名称匹配模式的新虚拟主机时自动授予权限。
## Grants user 'monitoring' access to all virtual hosts
## with certain permissions
default_users.monitoring.vhost_pattern = .*
default_users.monitoring.tags = monitoring
default_users.monitoring.configure = ^$
default_users.monitoring.read = .*
default_users.monitoring.write = ^$
此功能仅应用于授予服务账户(例如监控和自动化工具)对虚拟主机的访问权限。
对多个虚拟主机执行操作
每个 rabbitmqctl 和 rabbitmqadmin 权限管理操作都仅限于单个虚拟主机。批量操作必须通过脚本编写,虚拟主机列表来自 rabbitmqctl list_vhosts --silent 或 rabbitmqadmin vhosts list
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
# Assumes a Linux shell.
# Grants a user permissions to all virtual hosts.
for v in $(rabbitmqctl list_vhosts --silent); do rabbitmqctl set_permissions -p $v "a-user" ".*" ".*" ".*"; done
# Assumes a Linux shell.
# Grants a user permissions to all virtual hosts using rabbitmqadmin.
# Note: this example assumes rabbitmqadmin vhosts list outputs one vhost name per line
for v in $(rabbitmqadmin vhosts list --quiet | awk '{print $1}' | tail -n +2); do
rabbitmqadmin declare permissions --vhost "$v" --user "a-user" --configure ".*" --write ".*" --read ".*"
done
rabbitmqctl.bat list_vhosts --silent | %{ rabbitmqctl.bat set_permissions -p $_ 'a-user' '.*' '.*' '.*' }
# Grants a user permissions to all virtual hosts using rabbitmqadmin
# This approach uses rabbitmqctl for vhost listing as it's more straightforward for scripting
rabbitmqctl.bat list_vhosts --silent | %{ rabbitmqadmin.exe declare permissions --vhost $_ --user 'a-user' --configure '.*' --write '.*' --read '.*' }
播种(预创建)用户和权限
生产环境 通常需要预先配置(播种)多个虚拟主机、用户和用户权限。
这可以通过几种方式完成:
- 使用 CLI 工具
- 节点启动时导出和导入定义(推荐)
- 在配置文件中覆盖 默认凭据
CLI 工具
参见 用户管理 部分。
节点启动时导入定义
此过程涉及以下步骤:
- 设置临时节点,并使用 CLI 工具创建必要的虚拟主机、用户、权限等
- 将定义导出到定义文件
- 删除文件中不相关的部分
- 配置节点在启动时或启动后导入文件
请参阅定义指南中的 节点启动时导入定义 以了解更多信息。
节点启动后导入定义
请参阅定义指南中的 节点启动后导入定义。
覆盖默认用户凭据
可以使用两个配置选项来覆盖默认用户凭据。此用户将仅在 节点首次启动时 创建,因此它们必须在首次启动之前存在于配置文件中。
这些设置是:
# default is "guest", and its access is limited to localhost only.
# See ./access-control#default-state
default_user = a-user
# default is "guest"
default_pass = 768a852ed69ce916fa7faa278c962de3e4275e5f
与 rabbitmq.conf 中的所有值一样,# 字符开始注释,因此在生成的凭据中必须避免使用此字符。
默认用户凭据也可以加密。此主题在 配置值加密 中有更详细的介绍。
授权:权限如何工作
当 RabbitMQ 客户端与服务器建立连接并进行 身份验证 时,它会指定一个打算在其中操作的虚拟主机。此时将强制执行第一级访问控制,服务器检查用户是否拥有访问该虚拟主机的任何权限,否则将拒绝连接尝试。
资源(即交换机和队列)是特定虚拟主机内的命名实体;相同的名称在每个虚拟主机中表示不同的资源。当在资源上执行某些操作时,会强制执行第二级访问控制。
RabbitMQ 区分资源上的 configure(配置)、write(写入)和 read(读取)操作。configure 操作创建或销毁资源,或更改其行为。write 操作将消息注入到资源中。read 操作从资源中检索消息。
为了在资源上执行操作,必须向用户授予相应的权限。
- AMQP 0-9-1
- AMQP 1.0
- MQTT
下表显示了执行权限检查的所有 AMQP 0-9-1 命令所需的资源权限类型。
| AMQP 0-9-1 操作 | 配置 | write | read | |
|---|---|---|---|---|
| exchange.declare | (passive=false) | exchange | ||
| exchange.declare | (passive=true) | |||
| exchange.declare | (带 AE) | exchange | 交换机 (AE) | exchange |
| exchange.delete | exchange | |||
| queue.declare | (passive=false) | queue | ||
| queue.declare | (passive=true) | |||
| queue.declare | (带 DLX) | queue | 交换机 (DLX) | queue |
| queue.delete | queue | |||
| exchange.bind | 交换机 (destination) | 交换机 (source) | ||
| exchange.unbind | 交换机 (destination) | 交换机 (source) | ||
| queue.bind | queue | exchange | ||
| queue.unbind | queue | exchange | ||
| basic.publish | exchange | |||
| basic.get | queue | |||
| basic.consume | queue | |||
| queue.purge | queue |
下表显示了执行权限检查的所有 AMQP 1.0 命令所需的资源权限类型。
| AMQP 操作 | 配置 | write | read | |
|---|---|---|---|---|
| 声明交换机 | exchange | |||
| 声明交换机 | 带 AE | exchange | 交换机 (AE) | exchange |
| 删除交换机 | exchange | |||
| 绑定交换机到交换机 | 交换机 (destination) | 交换机 (source) | ||
| 解绑交换机 | 交换机 (destination) | 交换机 (source) | ||
| 声明队列 | queue | |||
| 声明队列 | 带 DLX | queue | 交换机 (DLX) | queue |
| 删除队列 | queue | |||
| 清除队列 | queue | |||
| 绑定队列到交换机 | queue | exchange | ||
| 解绑队列 | queue | exchange | ||
| 获取队列 | ||||
| 附加(发送方) | 交换机地址 | exchange | ||
| 附加(发送方) | 队列地址 | 交换机 (amq.default) | ||
| 附加(接收方) | queue |
权限以正则表达式的三元组表示(每个分别用于配置、写入和读取),基于每个虚拟主机。用户被授予对名称与正则表达式匹配的所有资源执行相应操作的权限。
例如,上表显示 queue.bind 协议操作需要在目标 queue 上具有 write 权限,而在目标 exchange 上需要 read 权限。
换句话说,为了允许用户将名为 queueA 的队列绑定到名为 exchangeB 的交换机,用户需要 write 权限正则表达式(针对正确的虚拟主机)匹配 queueA,而 read 权限正则表达式匹配 exchangeB。
为了方便起见,RabbitMQ 在执行权限检查时将 AMQP 0-9-1 默认交换机的空名称映射为 'amq.default'。
正则表达式 '^$'(即仅匹配空字符串)涵盖所有资源,并有效阻止用户执行任何操作。内置的 AMQP 0-9-1 资源名称以 amq. 为前缀,服务器生成的名称以 amq.gen 为前缀。
例如,'^(amq\.gen.*|amq\.default)$' 为用户提供对服务器生成名称和默认交换机的访问权限。空字符串 '' 是 '^$' 的同义词,并以完全相同的方式限制权限。
RabbitMQ 可能会 缓存 基于连接或频道的访问控制检查结果。因此,用户权限的更改可能仅在用户重新连接时生效。
有关如何设置访问控制的详细信息,请参阅 用户管理 部分以及 rabbitmqctl 手册页。
用户标签和管理 UI 访问
除了上述权限外,用户还可以拥有与他们关联的标签。目前只有管理 UI 访问受用户标签控制。
标签使用 rabbitmqctl 进行管理。新创建的用户默认没有任何标签。
请参阅 管理插件指南 以了解支持哪些标签以及它们如何限制管理 UI 访问。
主题授权
RabbitMQ 支持主题交换机的主题授权。当强制执行发布授权时,会考虑发布到主题交换机的消息的路由键(例如,在 RabbitMQ 默认授权后端中,将路由键与正则表达式匹配以决定消息是否可以路由到下游)。主题授权针对 STOMP 和 MQTT 等协议,这些协议围绕主题构建并在底层使用主题交换机。
主题授权是发布者现有检查之上的附加层。将消息发布到主题类型交换机将同时经过 basic.publish 和路由键检查。如果前者拒绝访问,则永远不会调用后者。
主题授权也可以针对主题消费者强制执行。请注意,它对不同的协议工作方式不同。主题授权的概念仅对 MQTT 和 STOMP 等面向主题的协议真正有意义。例如,在 AMQP 0-9-1 中,消费者从队列消费,因此适用标准的资源权限。此外,对于 AMQP 0-9-1,AMQP 0-9-1 主题交换机和队列/交换机之间的绑定路由键会根据配置的主题权限(如果有)进行检查。有关 RabbitMQ 如何处理主题授权的更多信息,请参阅 STOMP 和 MQTT 文档指南。
当使用默认授权后端时,如果未定义主题权限(这是全新 RabbitMQ 安装的情况),则始终授权发布到主题交换机或从主题消费。因此,使用此授权后端时,主题授权是可选的:您不需要批准任何交换机。因此,要使用主题授权,您需要选择加入并为一或多个交换机定义主题权限。有关详细信息,请参阅 rabbitmqctl 手册页。
内部(默认)授权后端支持权限模式中的变量扩展。支持三个变量:username、vhost 和 client_id。请注意,client_id 仅适用于 MQTT。例如,如果 tonyg 是连接的用户,则权限 ^{username}-.* 扩展为 ^tonyg-.*
如果使用不同的授权后端(例如 LDAP、HTTP、OAuth 2),请参阅这些后端的文档。
如果使用自定义授权后端,则通过实现 rabbit_authz_backend 行为的 check_topic_access 回调来强制执行主题授权。
撤销用户访问和凭据轮换
撤销用户访问
要撤销用户访问权限,推荐的过程是 删除用户。属于已删除用户的所有打开连接都将被关闭。
也可以清除用户权限,但这不会影响任何当前打开的连接。连接使用授权操作缓存,因此客户端操作最终会被拒绝。时间长短取决于所使用的 授权后端。
凭据轮换
存储在内部数据存储中的用户凭据的轮换通常涉及以下步骤:
- 使用 CLI 工具 更改用户密码 或使用
PUT /api/users/{user}HTTP API 端点对其进行更新 - 使用
rabbitmqctl close_all_user_connections或rabbitmqctl close_all_connections关闭所有现有连接 - 确保应用程序能够发现新凭据并重新连接,例如通过重新启动它们
如果怀疑凭据泄露,可以采用更彻底的凭据轮换程序:
- 评估用户的权限并 获取完整的集群定义文件
- 删除用户,从而撤销其访问权限并关闭所有使用这些凭据的现有连接
- 使用新的生成密码重新添加用户
- 重新授予用户访问其先前有权访问的所有虚拟主机的权限
- 确保应用程序能够发现新凭据并重新连接,例如通过重新启动它们
使用外部 authN 后端(如 LDAP)时,用户账户在 RabbitMQ 外部进行管理,因此凭据轮换程序也将在 RabbitMQ 外部进行。
身份验证和授权后端
身份验证和授权是可插拔的。插件可以提供以下实现:
- 身份验证("authn")后端:它们确定客户端身份并决定是否允许客户端连接
- 授权("authz")后端:它们确定已识别(已认证)的客户端是否被授权执行特定操作
插件提供这两个后端是可能的且常见的。RabbitMQ 附带了以下 内置插件,它们提供身份验证和授权后端:
以下内置插件提供授权后端实现:
某些插件(例如 源 IP 范围插件)也仅提供授权后端。
身份验证通常由内部数据库、LDAP 等处理。
可以将特殊的 缓存后端 与其他后端 组合使用,以显着减少它们在 LDAP 或 HTTP 服务器等外部服务上产生的负载。
组合后端
可以使用 auth_backends 配置键为 authn 或 authz 使用多个后端。当使用多个身份验证后端时,链中后端返回的第一个积极结果被视为最终结果。这不应与混合后端混淆(例如,使用 LDAP 进行身份验证,使用内部后端进行授权)。
以下示例将 RabbitMQ 配置为仅使用内部后端(这是默认设置):
# rabbitmq.conf
#
# 1 here is a backend name. It can be anything.
# Since we only really care about backend
# ordering, we use numbers throughout this guide.
#
# "internal" is an alias for rabbit_auth_backend_internal
auth_backends.1 = internal
上面的示例使用 rabbit_auth_backend_internal 的别名 internal。以下别名可用:
internal代表rabbit_auth_backend_internalldap代表rabbit_auth_backend_ldap(来自 LDAP 插件)oauth或oauth2代表rabbit_auth_backend_oauth2(来自 OAuth 2.0 插件)http代表rabbit_auth_backend_http(来自 HTTP 身份验证后端插件)dummy代表rabbit_auth_backend_dummy
对于没有快捷方式的插件,必须使用完整的模块名称(不是插件的名称!)
# note that the module name begins with a "rabbit_", not "rabbitmq_", like plugin
# names usually do
auth_backends.1 = rabbit_auth_backend_ip_range
使用第三方插件时,必须提供完整的模块名称。
以下示例将 RabbitMQ 配置为使用 LDAP 后端 进行身份验证和授权。不会咨询内部数据库。
auth_backends.1 = ldap
这将首先检查 LDAP,如果用户无法通过 LDAP 进行身份验证,则回退到内部数据库。
auth_backends.1 = ldap
auth_backends.2 = internal
与上述相同,但将回退到 HTTP 后端。
# rabbitmq.conf
#
auth_backends.1 = ldap
# uses module name instead of a short alias, "http"
auth_backends.2 = rabbit_auth_backend_http
# See HTTP backend docs for details
auth_http.user_path = http://my-authenticator-app/auth/user
auth_http.vhost_path = http://my-authenticator-app/auth/vhost
auth_http.resource_path = http://my-authenticator-app/auth/resource
auth_http.topic_path = http://my-authenticator-app/auth/topic
以下示例将 RabbitMQ 配置为使用内部数据库进行身份验证,并使用 源 IP 范围后端 进行授权。
# rabbitmq.conf
#
auth_backends.1.authn = internal
# uses module name because this backend is from a 3rd party
auth_backends.1.authz = rabbit_auth_backend_ip_range
以下示例将 RabbitMQ 配置为使用 LDAP 后端 进行身份验证,并使用内部后端进行授权。
# rabbitmq.conf
#
auth_backends.1.authn = ldap
auth_backends.1.authz = internal
下面的示例相当高级。它将首先检查 LDAP。如果用户在 LDAP 中找到,则根据 LDAP 检查密码,随后的授权检查将根据内部数据库执行(因此 LDAP 中的用户也必须存在于内部数据库中,但在那里不需要密码)。如果用户未在 LDAP 中找到,则仅使用内部数据库进行第二次尝试。
# rabbitmq.conf
#
auth_backends.1.authn = ldap
auth_backends.1.authz = internal
auth_backends.2 = internal
身份验证机制
RabbitMQ 支持多种 SASL 身份验证机制。服务器内置了四种此类机制:PLAIN、AMQPLAIN、ANONYMOUS 和 RABBIT-CR-DEMO,以及一种作为 插件 提供的机制 — EXTERNAL。
更多身份验证机制可以由插件提供。有关常规插件开发的更多信息,请参阅 插件开发指南。
内置身份验证机制
内置机制包括:
| 机制 | 描述 |
| PLAIN | SASL PLAIN 身份验证。这在 RabbitMQ 服务器和客户端中默认启用,并且是大多数其他客户端的默认设置。 |
| AMQPLAIN | 非标准版本的 PLAIN,保留用于向后兼容性。这在 RabbitMQ 服务器中默认启用。 |
| ANONYMOUS | 此机制默认启用,允许匿名客户端连接而不提供任何凭据。RabbitMQ 将在内部使用配置在 |
| EXTERNAL | 身份验证使用带外机制进行,例如 x509 证书对等验证、客户端 IP 地址范围或类似机制。此类机制通常由 RabbitMQ 插件提供。 |
| RABBIT-CR-DEMO | 非标准机制,演示质询-响应身份验证。此机制具有等同于 PLAIN 的安全性,并且 默认不在 RabbitMQ 服务器中启用。 |
服务器中的机制配置
auth_mechanisms 配置键决定向连接的客户端提供哪些安装的机制。
此变量应为与机制名称对应的接受值列表,例如,以下列表
auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
auth_mechanisms.3 = ANONYMOUS
默认使用。
服务器机制按优先顺序降序排列。请参阅 配置文件 文档。
客户端中的机制配置
应用程序必须选择加入才能使用不同的身份验证机制,例如 EXTERNAL。
Java 中的机制配置
Java 客户端默认不使用 javax.security.sasl 包,因为这在非 Oracle JDK 上可能是不可预测的,并且在 Android 上完全缺失。有一个特定于 RabbitMQ 的 SASL 实现,由 SaslConfig 接口配置。提供了一个 DefaultSaslConfig 类,使 SASL 配置在常见情况下更加方便。提供了一个 JDKSaslConfig 类作为到 javax.security.sasl 的桥梁。
ConnectionFactory.getSaslConfig() 和 ConnectionFactory.setSaslConfig(SaslConfig) 是与身份验证机制交互的主要方法。
.NET 中的机制配置
.NET 客户端基于 AuthMechanism 和 AuthMechanismFactory 接口提供了自己的 SASL 机制实现。ConnectionFactory.AuthMechanisms 属性是按优先顺序排列的身份验证机制工厂列表。
Erlang 中的机制配置
Erlang 客户端在 amqp_auth_mechanisms 模块中提供了自己的 SASL 机制实现。可以为 #amqp_params 记录提供按优先顺序排列的网络连接身份验证功能列表。
故障排除:身份验证
本节涵盖与身份验证相关的几个非常常见的问题。有关授权(权限)错误,请参阅 下方的另一个部分。
检查 服务器日志 在调查与身份验证相关的问题时至关重要。
不正确的权限
失败的身份验证尝试(即客户端指定了不正确的凭据时)将导致 服务器日志消息 如下所示:
2019-03-25 12:28:19.047 [info] <0.1613.0> accepting AMQP connection <0.1613.0> (127.0.0.1:63839 -> 127.0.0.1:5672)
2019-03-25 12:28:19.056 [error] <0.1613.0> Error on AMQP connection <0.1613.0> (127.0.0.1:63839 -> 127.0.0.1:5672, state: starting):
PLAIN login refused: user 'user2' - invalid credentials
2019-03-25 12:28:22.057 [info] <0.1613.0> closing AMQP connection <0.1613.0> (127.0.0.1:63839 -> 127.0.0.1:5672)
在使用 X.509 证书进行身份验证 的连接上的身份验证失败将被记录得不同。有关详细信息,请参阅 TLS 故障排除指南。
rabbitmqctl authenticate_user 可用于测试用户名和密码对的身份验证。
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqctl (PowerShell)
rabbitmqctl authenticate_user "a-username" "a/password"
# note that double quotes are required due to the & character
rabbitmqctl.bat authenticate_user 'a-username' '"a/p&assword"'
如果身份验证成功,它将以代码 0 退出。如果失败,将使用非零退出代码,并将打印失败错误消息。
rabbitmqctl authenticate_user 将使用 CLI 到节点的通信连接,尝试根据内部 API 端点验证用户名/密码对。连接被假定为受信任的。如果不是这种情况,其流量可以 使用 TLS 加密。
默认用户从远程主机的连接被拒绝
默认用户不能从远程主机连接是有原因的。启用此类连接会极大地降低集群的安全性。考虑为所有生产集群创建一个 带有生成凭据的唯一用户。
如果凭据被报告为正确,本地主机的连接成功但远程连接失败,则问题是 默认用户连接限制。
在这种情况下,错误如下所示:
2024-08-24 17:28:32.153698-04:00 [error] <0.1567.0> PLAIN login refused: user 'guest' can only connect via localhost
必须为从远程主机连接的客户端(包括 shovels 和 联邦链接)创建一个 带有生成凭据的单独用户。
AMQP 0-9-1 中的身份验证失败通知
根据 AMQP 0-9-1 规范,身份验证失败应导致服务器立即关闭 TCP 连接。然而,使用 RabbitMQ,客户端可以选择通过 身份验证失败通知 扩展接收更具体的通知。现代客户端库可以对用户透明地支持该扩展:无需配置,身份验证失败将导致可见的返回错误、异常或特定编程语言或环境中使用的其他问题通信方式。
故障排除:授权
检查 服务器日志 在调查与授权相关的问题时至关重要。
缺少权限
授权失败中最常见的情况是用户已创建,但未被 授予权限 以访问客户端尝试连接到的虚拟主机。
在这种情况下,连接将被拒绝,消息如下所示:
2019-03-25 12:26:16.301 [info] <0.1594.0> accepting AMQP connection <0.1594.0> (127.0.0.1:63793 -> 127.0.0.1:5672)
2019-03-25 12:26:16.309 [error] <0.1594.0> Error on AMQP connection <0.1594.0> (127.0.0.1:63793 -> 127.0.0.1:5672, user: 'user2', state: opening):
access to vhost '/' refused for user 'user2'
2019-03-25 12:26:16.310 [info] <0.1594.0> closing AMQP connection <0.1594.0> (127.0.0.1:63793 -> 127.0.0.1:5672, vhost: 'none', user: 'user2')
权限不足
另一种非常常见的情况是定义了权限,但对于客户端尝试执行的操作,它们 不足以执行操作。
在这种情况下,连接将被接受。
rabbitmqctl list_permissions 和 rabbitmqadmin users permissions 可用于检查用户在给定虚拟主机中的权限。
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl list_permissions --vhost /
# => Listing permissions for vhost "/" ...
# => user configure write read
# => user2 .* .* .*
# => guest .* .* .*
# => temp-user .* .* .*
rabbitmqctl list_permissions --vhost gw1
# => Listing permissions for vhost "gw1" ...
# => user configure write read
# => guest .* .* .*
# => user2 ^user2 ^user2 ^user2
# List permissions for all users in the default virtual host
rabbitmqadmin users permissions --vhost /
# List permissions for all users in a specific virtual host
rabbitmqadmin users permissions --vhost gw1
rabbitmqctl.bat list_permissions --vhost /
rabbitmqctl.bat list_permissions --vhost gw1
# List permissions for all users in the default virtual host
rabbitmqadmin.exe users permissions --vhost "/"
# List permissions for all users in a specific virtual host
rabbitmqadmin.exe users permissions --vhost "gw1"
授权失败(权限冲突)通过以下消息进行记录:
2019-03-25 12:30:05.209 [error] <0.1627.0> Channel error on connection <0.1618.0> (127.0.0.1:63881 -> 127.0.0.1:5672, vhost: 'gw1', user: 'user2'), channel 1:
operation queue.declare caused a channel exception access_refused: access to queue 'user3.q1' in vhost 'gw1' refused for user 'user2'