跳至主要内容
版本:4.0

LDAP 支持

概述

RabbitMQ 可以使用 LDAP 通过委托给外部 LDAP 服务器来执行 身份验证和授权。此功能由内置插件提供,必须启用

身份验证和授权操作将被转换为 LDAP 查询,这些查询使用由 RabbitMQ 操作员配置的模板。

为了提高效率并减少 LDAP 服务器的负载,LDAP 查询可以 缓存 一段时间。

LDAP 操作流程 部分提供了关于插件工作原理的更详细概述。

该插件主要针对 OpenLDAP 和 Microsoft Active Directory。其他 LDAP v3 实现应该也能很好地工作。

本指南简要概述了 LDAP 术语,但一般假定您对 LDAP 有基本了解。网上有许多面向初学者的 LDAP 入门指南,例如,一个两个,以及 LDAP 词汇表

本指南涵盖了 RabbitMQ 使用的 LDAP 操作流程,LDAP 模型如何 映射到 RabbitMQ 权限模型,如何 使用 TLS 连接到 LDAP 服务器,以及哪些工具可用于 排查故障代理 LDAP 请求。

先决条件

RabbitMQ LDAP 插件依赖于一个名为 eldap 的 LDAP 客户端。该库与 Erlang/OTP 一起提供。在某些操作系统上,Erlang 作为一组软件包而不是一个单一的软件包提供,因此,eldap 等组件**必须单独安装**在主运行时之外。

在 Debian 和 Ubuntu 上,eldaperlang-eldap 软件包提供。

sudo apt-get install -y erlang-eldap

在 Erlang 安装中,如果库不可用,则 **无法** 使用 LDAP 支持。

请参阅 Erlang 兼容性指南 以了解更多信息。

启用插件

LDAP 插件与 RabbitMQ 一起提供。要启用它,请使用 rabbitmq-plugins

rabbitmq-plugins enable rabbitmq_auth_backend_ldap

启用 LDAP AuthN 和 AuthZ 后端

启用插件后,需要配置节点以使用它。

这包括

以下示例将配置 RabbitMQ 以 **仅** 使用 LDAP 进行身份验证和授权,并忽略内部数据库

# use LDAP exclusively for authentication and authorisation
auth_backends.1 = ldap

advanced.config 文件 中,相同的设置将如下所示

{rabbit, [
{auth_backends, [rabbit_auth_backend_ldap]}
]}

以下示例将指示节点首先尝试 LDAP,然后在无法通过 LDAP 身份验证用户的情况下回退到内部数据库

# try LDAP first
auth_backends.1 = ldap
# fall back to the internal database
auth_backends.2 = internal

advanced.config 格式 中,相同的示例

{rabbit,[
{auth_backends, [rabbit_auth_backend_ldap, rabbit_auth_backend_internal]}
]}

在以下示例中,LDAP 将首先用于身份验证。如果在 LDAP 中找到了用户,则将根据 LDAP 检查密码,并根据内部数据库执行后续的授权检查(因此,LDAP 中的用户也必须存在于内部数据库中,可以选择使用空密码)。如果在 LDAP 中找不到用户,则使用仅内部数据库进行第二次尝试。

# use LDAP for authentication first
auth_backends.1.authn = ldap
# use internal database for authorisation
auth_backends.1.authz = internal
# fall back to the internal database
auth_backends.2 = internal

高级配置格式

{rabbit,[{auth_backends, [{rabbit_auth_backend_ldap, rabbit_auth_backend_internal},
rabbit_auth_backend_internal]}]}

配置

启用插件及其后端后,必须配置许多 LDAP 特定的设置。这些设置包括 LDAP 服务器列表、身份验证和授权设置等等。

默认配置允许所有用户访问所有虚拟主机中的所有对象,但不将它们设为管理员。可以通过配置 LDAP 查询来限制访问。

LDAP 服务器

为了使插件能够连接到 LDAP 服务器,必须使用 auth_ldap.servers 键配置至少一个服务器主机名或 IP 地址。如果提供多个值,列表值可以是主机名或 IP 地址。必须配置此值。以下示例配置插件以使用两个 LDAP 服务器。它们将按顺序尝试,直到连接到其中一个成功

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

使用经典配置格式的相同示例

[
{rabbitmq_auth_backend_ldap, [
{servers, ["ldap.eng.megacorp.local", "192.168.0.100"]}
]}
].

LDAP 服务器通常使用端口 389,这也是 LDAP 插件默认使用的端口。auth_ldap.port 可用于覆盖此设置

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

auth_ldap.port = 6389

使用经典配置格式的相同示例

[
{rabbitmq_auth_backend_ldap, [
{servers, ["ldap.eng.megacorp.local", "192.168.0.100"]},
{port, 6389}
]}
].

可以使用 auth_ldap.timeout 配置键为与 LDAP 服务器的 TCP 连接设置超时

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

# 15 seconds in milliseconds
auth_ldap.timeout = 15000

默认值为 infinity,即没有超时。

LDAP 服务器连接被池化,以避免过多的连接波动和 LDAP 服务器负载。默认情况下,池最多具有 64 个连接。这可以使用 auth_ldap.connection_pool_size 设置进行控制

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

auth_ldap.connection_pool_size = 256

在经过可通过 auth_ldap.idle_timeout(以毫秒或 infinity 为单位)配置的一段时间后,没有活动的池化连接将被关闭

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

auth_ldap.connection_pool_size = 256
# 300 seconds in milliseconds
auth_ldap.idle_timeout = 300000

建议使用 120 到 300 秒之间的值。

使用 TLS 连接到 LDAP 服务器

重要

从 Erlang 26 开始,TLS 客户端对等验证 默认情况下由 TLS 实现启用。

如果未配置客户端 TLS 证书和密钥对,则启用 TLS 的 LDAP 服务器连接将失败。如果不需要对等验证,则可以禁用它,否则必须为 LDAP 连接配置证书和私钥对。

可以使用 TLS 连接到 LDAP 服务器。要指示插件这样做,请将 auth_ldap.use_ssl 设置设置为 true。如果 LDAP 服务器使用 StartTLS,请改用 auth_ldap.use_starttls。请注意,这些设置是互斥的(不能组合使用)。这两个值的默认值为 false

客户端 TLS 设置使用 ssl_options 配置,这些设置与 RabbitMQ 中其他地方的 TLS 设置 非常相似。

以下是一个最小示例

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

# enables TLS for connections to the LDAP server
auth_ldap.use_ssl = true

# Disables peer certificate chain verification. See the section on Peer Verification
# below.
#
# Doing so loses one of the key benefits of TLS and make the setup less secure
# but also simplifies node configuration.
auth_ldap.ssl_options.verify = verify_none

该插件还可以使用 StartTLS 连接。此较旧且不安全的选项 **不建议** 使用,但对于较旧的 LDAP 服务器可能是必需的

auth_ldap.servers.1 = ldap.eng.megacorp.local
auth_ldap.servers.2 = 192.168.0.100

# Enables StartTLS for connections to the LDAP server.
# Prefer auth_ldap.use_ssl with reasonably modern LDAP servers!
auth_ldap.use_starttls = true

# Disables peer certificate chain verification. See the section on Peer Verification
# below.
#
# Doing so loses one of the key benefits of TLS and make the setup less secure
# but also simplifies node configuration.
auth_ldap.ssl_options.verify = verify_none

可用于 LDAP 的客户端 TLS 选项

有许多可用的 TLS 客户端选项

CA 证书、客户端证书和私钥

# local filesystem path to a CA certificate bundle file
auth_ldap.ssl_options.cacertfile = /path/to/ca_certificate.pem

# local filesystem path to a client certificate file
auth_ldap.ssl_options.certfile = /path/to/client_certfile.pem

# local filesystem path to a client private key file
auth_ldap.ssl_options.keyfile = /path/to/client_key.pem

SNI(服务器名称指示)

可以为传出的 TLS 连接到 LDAP 服务器配置 服务器名称指示 (SNI)。如果未设置,则默认值为用于连接的主机名(请参阅上面的 auth_ldap.servers.*)。

# Sets Server Name Indication for LDAP connections.
# If an LDAP server host is available via multiple domain names, set this value
# to the preferred domain name target LDAP server
auth_ldap.ssl_options.sni = ldap.identity.eng.megacorp.local

主机名验证

主机名验证不应与 对等证书链验证 混淆。这些设置是正交的,可以组合使用。

# take wildcards into account when performing hostname verification
auth_ldap.ssl_options.hostname_verification = wildcard
# disables hostname verification
auth_ldap.ssl_options.hostname_verification = none

对等验证

从 Erlang 26 开始,LDAP TLS 客户端默认情况下会执行 对等证书链验证

对等证书链验证 不应与主机名匹配验证混淆。这些设置是正交的,可以组合使用。

# Enables peer certificate chain verification.
# This behavior is the default starting with Erlang 26 (and thus RabbitMQ 3.13+)/
auth_ldap.ssl_options.verify = verify_peer
# Disables peer certificate chain verification.
#
# Doing so loses one of the key benefits of TLS and make the setup less secure
# but also simplifies node configuration.
auth_ldap.ssl_options.verify = verify_none
# if target LDAP server does not present a certificate, should the connection be aborted?
auth_ldap.ssl_options.fail_if_no_peer_cert = true

对等链验证深度

可以为使用多个中间证书的服务器增加 证书链验证深度

auth_ldap.ssl_options.depth = 5

启用的 TLS 版本

# use TLSv1.2 only
ssl_options.versions.1 = tlsv1.2

advanced.config 中的 TLS 选项

以下示例使用 advanced.config 格式

[
{rabbitmq_auth_backend_ldap, [
{servers, ["ldap1.eng.megacorp.local", "ldap2.eng.megacorp.local"]},

{use_ssl, true},
{ssl_options, [{cacertfile, "/path/to/ca_certificate.pem"},
{certfile, "/path/to/server_certificate.pem"},
{keyfile, "/path/to/server_key.pem"},
{verify, verify_peer},
{fail_if_no_peer_cert, true}]},
{server_name_indication, "ldap.identity.eng.megacorp.local"},
{ssl_hostname_verification, wildcard}
]}
].

LDAP 查询缓存以提高效率并减少负载

一个特殊的 缓存后端 可以与其他后端结合使用 结合,以显著减少它们在 LDAP 服务器上产生的负载。

建议生产集群在依赖 LDAP 进行身份验证和授权时,将它与缓存后端结合使用。对于大多数系统来说,15 到 60 秒的缓存间隔在安全性和效率之间取得了良好的平衡。

LDAP 基础知识和术语

本节介绍了本文档中使用的一些基本 LDAP 术语。有关 LDAP 入门的介绍,请参阅 这个概述 Digital Ocean 和 LDAP 词汇表 来自 ldap.com。

术语描述
绑定LDAP 中的“身份验证请求”。
可分辨名称 (DN)

可分辨名称是 LDAP 目录(树)中用于标识对象(如用户或组)的唯一键。插件将在身份验证阶段(见下文)将客户端提供的用户名转换为可分辨名称。您可以将 DN 视为文件系统中的绝对文件路径。

通用名称 (CN)

树中对象的简短标识符。此标识符在 LDAP 数据库中的对象类(类型)之间会不同。例如,一个人的通用名称将是全名。一个组的通用名称将是该组的名称。您可以将 CN 视为文件系统中的文件名。

属性

对象的属性(键值对)。可以把它看作面向对象编程语言中对象的字段。

对象类

一组预定义的属性。可以把它看作面向对象语言中的类型(类)。

条目

LDAP 数据库实体,例如,人或组。它与一个对象类相关联,并且具有一个或多个属性,包括一个通用名称。由于实体位于 LDAP 数据库树中的某个位置,因此它还必须具有唯一标识它的可分辨名称。条目是 LDAP 插件查询(查找、检查成员资格、比较属性等)使用的对象。LDAP 数据库必须具有一些条目(通常是用户、组)才能在实践中用于 RabbitMQ 身份验证和授权。

LDAP 操作流程

为了执行 LDAP 查询,插件将打开到列表中第一个可到达的 LDAP 服务器的连接。然后,根据凭据配置,它将执行匿名绑定或“简单绑定”(使用用户名/密码对对用户进行 LDAP 服务器身份验证)。用于执行绑定的凭据可以从客户端提供的用户名派生,如下一节所述。

如果配置了虚拟主机访问查询,则将首先执行该查询,否则将无条件地授予虚拟主机访问权限。

此时,连接可以被认为已成功协商和建立。例如,应该可以在其上打开一个通道。对连接执行的所有后续操作都将执行授权查询之一。例如,声明队列将执行资源访问查询(在下面介绍)。将消息发布到主题交换机将另外执行主题访问查询。请参阅 访问控制指南 以了解更多信息。

用户名和可分辨名称

在简单绑定阶段,user_dn_pattern 模式用于将提供的用户名转换为用于绑定的值。默认情况下,该模式按原样传递提供的值(即,该模式为 ${username})。如果指定了 user_bind_pattern,则它优先于 user_dn_pattern。如果在可分辨名称查找阶段需要使用不同的 user_dn_pattern,这将非常有用。请注意,以上内容不适用于匿名绑定,也不适用于 dn_lookup_bind 未设置为 as_user 的情况。

客户端连接提供用户名,这些用户名被转换为 LDAP 中的可分辨名称 (DN)。有两种方法可以做到这一点。最简单的方法是使用 user_dn_pattern 进行字符串替换。要使用此选项,请将 user_dn_pattern 设置为包含 ${username} 确切一次实例的字符串,这是一个将被替换为客户端提供的用户名值的变量。

例如,将 user_dn_pattern 设置为 "cn=${username},ou=People,dc=example,dc=com" 将导致用户名 simon 被转换为 DN cn=simon,ou=People,dc=example,dc=com。默认值为 "${username}",换句话说,用户名被原样使用。

将用户名转换为可分辨名称的另一种方法是通过 LDAP 查找。为此,请将 auth_ldap.dn_lookup_attribute 设置为代表用户名的属性名称,并将 auth_ldap.dn_lookup_base 设置为查询的基准 DN。可以在两个时间点之一执行查找,即在尝试以所述用户身份绑定之前或之后。

要在绑定后执行查找,请将 auth_ldap.dn_lookup_bind 保持其默认值 as_user。然后,LDAP 插件将使用用户的普通(未修改)用户名进行绑定以进行登录,然后查找其 DN。为了使此方法起作用,需要将 LDAP 服务器配置为允许使用普通用户名进行绑定(Microsoft Active Directory 通常会执行此操作)。

要在绑定之前执行查找,请按如下方式设置 dn_lookup_binddn_lookup_basedn_lookup_attribute。然后,LDAP 插件将首先使用这些凭据进行绑定以进行查找,然后使用用户的 DN 和密码进行绑定以进行登录。

auth_ldap.dn_lookup_bind.user_dn = CN=myuser,OU=users,DC=gopivotal,DC=com
auth_ldap.dn_lookup_bind.password = test1234
auth_ldap.dn_lookup_attribute = userPrincipalName
auth_ldap.dn_lookup_base = DC=gopivotal,DC=com

考虑以下示例

auth_ldap.dn_lookup_attribute = userPrincipalName
auth_ldap.dn_lookup_base = DC=gopivotal,DC=com

使用此配置,可以使用电子邮件地址进行身份验证(userPrincipalName 值通常是电子邮件地址),并让本地 Active Directory 服务器返回实际的 DN 以进行登录。

如果同时设置了 auth_ldap.dn_lookup_attributeauth_ldap.user_dn_pattern,则将结合这两种方法:插件将填写模板,然后搜索 DN。

auth_ldap.dn_lookup_bind 的默认值为 as_user。对于 auth_ldap.dn_lookup_baseauth_ldap.dn_lookup_attribute,它是 none

LDAP 活动日志记录

插件可以使用 auth_ldap.log(在经典配置格式中为 rabbitmq_auth_backend_ldap.log)设置来控制 LDAP 活动日志记录的详细程度。这对于故障排除至关重要。

将该值设置为 true 将启用 LDAP 插件用于做出决策的逻辑的详细日志记录。在这种模式下,绑定请求结果中的凭据将被清除。此模式不推荐用于生产系统,但有时可能会有用。

network 的值与上述类似,但会另外导致在较低(LDAP 客户端)级别记录 LDAP 网络流量,并将绑定请求凭据清除。此设置可能会导致过度日志记录,应谨慎使用。

network_unsafe 的值会导致在较低(LDAP 客户端)级别记录 LDAP 网络流量,并将绑定请求凭据(如密码)写入日志;此模式不得在生产环境中使用,因为它会违反几乎所有广泛采用的安全策略。但是,它对于在开发和 QA 环境中进行故障排除非常有用。

最后,false(默认值)将停用 LDAP 流量日志记录。

以下示例将 LDAP 日志记录级别设置为 network

auth_ldap.log = network

经典配置格式中的相同示例

[
{rabbitmq_auth_backend_ldap, [
%% ...
{log, network}
]}
]

用于授权查询的绑定

对于身份验证,此插件会以它试图验证的用户身份绑定到 LDAP 服务器。other_bind 设置控制如何为授权查询绑定,以及如何检索未提供密码登录的用户的详细信息(例如,使用 EXTERNAL 身份验证机制)。

可接受的值为 as_user(以已验证的用户身份绑定)或 anon(匿名绑定),或者由两个选项 other_bind.user_dnother_bind.password 表示,以使用指定的用户名和密码进行绑定。例如

auth_ldap.other_bind.user_dn = a-username
auth_ldap.other_bind.password = a-password

使用经典配置格式

[
{rabbitmq_auth_backend_ldap, [
{other_bind, {"a-username", "a-password"}}
]}
].

请注意,在用户连接时未提供密码的情况下,无法使用默认的 as_user 配置。在这种情况下,请使用 auth_ldap.other_bind.user_dnauth_ldap.other_bind.passwordanon 选项。

auth_ldap.other_bind 的默认值为 as_user

组成员资格查找

插件支持多个组成员资格查找查询。group_lookup_base 设置控制用于搜索嵌套组的基准 DN。它仅由 {in_group_nested, ...} 查询使用。有关更多信息,请参阅 有关查询的部分

在以下示例中,ou=groups,dc=example,dc=com 是包含所有组的目录。请注意,它使用的是 经典配置格式

[
{rabbitmq_auth_backend_ldap, [
%% ...
{group_lookup_base, "ou=groups,dc=example,dc=com"}
]}
]

默认值为 'none'

配置授权

RabbitMQ 权限模型如何映射到 LDAP

RabbitMQ 权限模型 与 LDAP 的权限模型不同。此外,使用 LDAP 架构的方式因公司而异。因此,需要一种机制来定义 RabbitMQ 授权功能使用哪些 LDAP 请求。授权由四个可配置的查询控制

  • rabbitmq_auth_backend_ldap.vhost_access_query
  • rabbitmq_auth_backend_ldap.resource_access_query
  • rabbitmq_auth_backend_ldap.topic_access_query
  • rabbitmq_auth_backend_ldap.tag_queries

每个查询都定义了一个查询,用于确定用户是否可以访问虚拟主机,是否可以访问资源(例如,交换机、队列、绑定)以及他们拥有哪些 标签

请注意较长的 rabbitmq_auth_backend_ldap 前缀。查询使用用 Erlang 术语(数据结构)表示的特定于域的语言来表示,因此只能使用 高级配置格式 进行定义。

查询及其类型

上面提到的每个查询都在不同的授权阶段使用,并且必须计算为 true 或 false。特定的查询类型(表达式,例如,值比较或组成员资格检查)将在本指南的后面部分介绍。

查询可以是多种类型之一。每种类型代表一个布尔表达式或函数:比较、字符串匹配、对象存在性检查、组成员资格检查等。查询可以嵌套,并且可以使用布尔运算符进行组合。

默认值(表达式)可以在下表中找到

查询目的默认表达式
rabbitmq_auth_backend_ldap.vhost_access_query验证用户是否被允许访问虚拟主机{constant, true}
rabbitmq_auth_backend_ldap.resource_access_query验证用户是否被允许访问资源(队列、交换机等){constant, true}
rabbitmq_auth_backend_ldap.topic_access_query验证用户是否被允许发布到主题{constant, true}
rabbitmq_auth_backend_ldap.tag_queries检查用户是否适用已知标签[{administrator, {constant, false}}]

这意味着所有用户都被授予对所有虚拟主机中所有对象的访问权限,但他们不是系统管理员。

所有将字符串作为参数的查询类型都支持字符串替换,其中可以替换与正在进行的查询相关的变量。每个查询都支持不同的变量。

vhost_access_query 支持

  • ${username}:身份验证时提供的用户名
  • ${user_dn}:用户的识别名称
  • ${vhost}:我们正在查询访问权限的虚拟主机

resource_access_query 支持

  • ${username}:身份验证时提供的用户名
  • ${user_dn}:用户的识别名称
  • ${vhost}:资源所在的虚拟主机
  • ${resource}:资源类型,可以是 "exchange" 或 "queue"
  • ${name}:资源的名称
  • ${permission}:对资源请求的访问类型,可以是 "configure"、"write" 或 "read"

tag_queries 支持

  • ${username}:身份验证时提供的用户名
  • ${user_dn}:用户的识别名称
  • ${vhost}:**并非所有情况下都可用虚拟主机信息**。它可以用于提供额外的上下文,例如对应用程序或用户进行分组

topic_access_query 支持

  • ${username}:身份验证时提供的用户名
  • ${user_dn}:用户的识别名称
  • ${vhost}:资源所在的虚拟主机
  • ${resource}:在这种情况下始终为 "topic"
  • ${name}:资源的名称
  • ${permission}:可以是 "write"(发布)或 "read"(消费、队列和交换机到交换机的绑定,用于主题交换机)
  • ${routing_key}:已发布消息的路由键("write" 权限)或主题交换机到队列/交换机绑定的路由键("read" 权限)

最后,如果身份验证时提供的用户名采用 Domain\User 格式(在某些 Active Directory 环境中就是这样),则上述每个查询都会提供两个 *额外* 的变量

  • ${ad_domain} - Domain\User 中的域部分
  • ${ad_user} - Domain\User 中的用户部分

资源访问的术语 "configure"、"write" 和 "read" 与内置 RabbitMQ 权限系统中的含义相同,请参见 ./access-control。有关 topic_access_query,另请参见 主题授权

第一次熟悉查询 DSL 时,打开上面记录的 log 配置参数会有所帮助。这会导致 LDAP 插件向 RabbitMQ 日志写入对它执行的查询及其因此做出的决定的相当详细的描述。

虚拟主机访问

rabbitmq_auth_backend_ldap.vhost_access_query 是用于控制虚拟主机访问权限的查询。如果查询结果为 true,则授予访问权限。

请注意,在用户能够访问虚拟主机之前,必须在 RabbitMQ 中创建该虚拟主机;与用户和权限不同,虚拟主机不能完全存在于 LDAP 中。

用户标签

tag_queries 由一个键值映射组成,它将标签的名称映射到要执行的查询,以确定用户是否拥有该标签。需要列出用户应该拥有所有标签的查询列表。

授权查询参考

常量查询

{constant, Bool}

这将始终返回 true 或 false,无条件地授予或拒绝访问权限。示例

{tag_queries, [{administrator, {constant, false}},
{management, {constant, true}}]}

这授予所有用户使用管理插件的能力,但不会使他们成为管理员。

存在查询

{exists, Pattern}

这将把变量替换到模式中,如果存在具有结果 DN 的对象,则返回 true。示例

{vhost_access_query, {exists, "ou=${vhost},ou=vhosts,dc=example,dc=com"}}

这授予对所有虚拟主机的访问权限,这些虚拟主机存在于 ou=vhosts,dc=example,dc=com 中的组织单位,所有用户都拥有访问权限。

在组查询

{in_group, Pattern}
{in_group, Pattern, AttributeName}

与存在查询类似,将参数替换到模式中以查找对象。但是,此查询返回 true,如果已登录用户是成员;针对 member 属性或任何命名属性进行检查。示例

{vhost_access_query, {in_group, "cn=${vhost}-users,ou=vhosts,dc=example,dc=com"}}

当用户在 ou=vhosts,dc=example,dc=com 中的适当命名对象(例如 groupOfNames)中列为 member 属性时,这会授予对虚拟主机的访问权限。

在嵌套组查询

{in_group_nested, Pattern}
{in_group_nested, Pattern, AttributeName}
{in_group_nested, Pattern, AttributeName, Scope}

类似于 in_group 查询,但也会遍历组层次结构,例如,如果已登录用户是某个组的成员,而该组又是另一个组的成员。成员资格针对 member 属性或任何命名属性进行检查。组在由 group_lookup_base 配置键定义的 DN 或 dn_lookup_base 变量(如果前者为 none)中搜索。如果两个查找基变量都设置为 none,则查询将始终返回 false。搜索范围可以设置为 subtreesingle_level

  • subtree 搜索查找基下的所有对象
  • single_level 搜索直接包含在查找基中的组

范围的默认值为 subtree。查询使用从用户到目标组的深入搜索。搜索过程将检测并跳过循环路径。如果用户是许多组的成员,而这些组又是许多组的成员,则此查询可能会占用大量时间和内存。当组用于成员资格层次结构时,使用此查询。如果可能,仍然建议使用普通的 {in_group, ...} 查询:嵌套组可能难以推断。示例

[
{group_lookup_base, "ou=groups,dc=example,dc=com"},
{vhost_access_query, {in_group_nested, "cn=${vhost}-groups,ou=groups,dc=example,dc=com"}, "member", single_level}
]

当用户是 member 属性值定义的组层次结构的成员,并且位于 ou=groups,dc=example,dc=com 目录中时,这会授予对虚拟主机的访问权限。

对于查询

{for, [{Name, Value, SubQuery}, ...]}

这允许您拆分查询并使用不同的子查询处理不同的情况。

选项应该是一个三元组列表,每个三元组包含一个名称、一个值和一个子查询。名称是变量的名称(即在 ${} 替换中使用的内容)。值是该变量的可能值。

请注意,值是不同的 Erlang 类型;resourcepermission 具有原子值(例如 resource 可以是 exchange),而其他键具有二进制值(例如 name 可能为 <<"amq.fanout">>)。

示例

{resource_access_query,
{for, [{resource, exchange, {for, [{permission, configure,
{in_group, "cn=wheel,dc=example,dc=com"}
},
{permission, write, {constant, true}},
{permission, read, {constant, true}}
]}},
{resource, queue, {constant, true}}]}}

这允许 wheel 组的成员声明和删除交换机,并允许所有用户执行所有其他操作。

布尔查询

{'not', SubQuery}
{'and', [SubQuery1, SubQuery2, SubQuery3, ...]}
{'or', [SubQuery1, SubQuery2, SubQuery3, ...]}

这些可用于将子查询与布尔逻辑结合起来。'and' 和 'or' 查询都接受任意长的子查询列表,如果所有或任何子查询分别计算为 true,则返回 true。

请注意,'and'、'or' 和 'not' 是 Erlang 中的保留字,因此在配置文件中,关键字需要用单引号引起来,如上所示。示例

 {'or',
[{'and',
[{equals, "${name}", "test1"},
{equals, "${username}", "user1"}]},
{'and',
[{equals, "${name}", "test2"},
{'not', {equals, "${username}", "user1"}}]}
]}}

此示例授予对名为 "test1" 到 "user1" 的对象的完全访问权限,并授予对 "test2" 的访问权限,但 "user1" 除外。

相等查询

{equals, StringSubQuery1, StringSubQuery2}

接受两个字符串,并检查其中一个是否与另一个匹配。请注意,两个字符串都是依次进行的子查询(如以下的 stringattribute 类型)。

这对于比较其中一个字符串替换变量的值与常量、属性值等很有用。示例

{resource_access_query,
{for, [{permission, configure, {equals, {attribute, "${user_dn}", "description"},
{string, "can-declare-${resource}s"}
}
},
{permission, write, {constant, true}},
{permission, read, {constant, true}}
]
}

这根据用户描述字段中是否存在字符串 "can-declare-exchanges" 和 "can-declare-queues" 来授予声明和删除交换机和队列的权限,并授予所有人写入和读取交换机的权限。

匹配查询

{match, StringSubQuery, RESubQuery}

接受一个字符串和一个正则表达式,并检查其中一个是否与另一个匹配。请注意,字符串和正则表达式都是依次进行的子查询(如以下的 stringattribute 类型)。示例

{resource_access_query, {match, {string, "${name}"},
{string, "^${username}-"}}
}

这允许用户配置、读取和写入任何名称以其自己的用户名后跟连字符开头的对象。

字符串子查询

{string, Pattern}

只需将参数替换到字符串中。由于这返回的是字符串而不是布尔值,因此应该在 matchequals 查询中使用它。请参见上面的示例。作为简写,您可以使用普通字符串而不是 {string, Pattern}

属性子查询

{attribute, DNPattern, AttributeName}

返回从 LDAP 中检索到的对象的属性值。由于这返回的是字符串而不是布尔值,因此应该在 matchequals 查询中使用它。请参见上面的示例。

示例配置

将所有内容整合在一起,这里有一个示例配置。它同时使用了 标准配置高级配置 文件。这使得所有用户能够访问管理插件,但不会使他们成为管理员。对虚拟主机的访问权限由每个虚拟主机的组成员资格控制。只有 admin 的成员才能声明、删除或绑定交换机和队列,但所有用户都可以发布到交换机并从队列中声明。发布到主题类型交换机仅限于路由键以 "a" 开头的消息,并且从主题中消费不受限制(主题授权)。

标准配置 (rabbitmq.conf) 用于配置身份验证后端和几个 LDAP 插件参数

auth_backends.1 = ldap

auth_ldap.servers.1 = my-ldap-server
auth_ldap.user_dn_pattern = cn=${username},ou=People,dc=example,dc=com
auth_ldap.use_ssl = false
auth_ldap.port = 389
auth_ldap.log = false

高级配置 用于定义 LDAP 查询

[{rabbitmq_auth_backend_ldap,[
{vhost_access_query, {in_group,
"ou=${vhost}-users,ou=vhosts,dc=example,dc=com"}},
{resource_access_query,
{for, [{permission, configure, {in_group, "cn=admin,dc=example,dc=com"}},
{permission, write,
{for, [{resource, queue, {in_group, "cn=admin,dc=example,dc=com"}},
{resource, exchange, {constant, true}}]}},
{permission, read,
{for, [{resource, exchange, {in_group, "cn=admin,dc=example,dc=com"}},
{resource, queue, {constant, true}}]}}
]
}},
{topic_access_query,
{for, [{permission, write, {match, {string, "${routing_key}"}, {string, "^a"}}},
{permission, read, {constant, true}}
]
}},
{tag_queries, [{administrator, {constant, false}},
{management, {constant, true}}]}
]}].

或者,您可以使用 经典配置格式 在单个文件中配置所有内容

[
{rabbit, [{auth_backends, [rabbit_auth_backend_ldap]}]},
{rabbitmq_auth_backend_ldap,
[ {servers, ["my-ldap-server"]},
{user_dn_pattern, "cn=${username},ou=People,dc=example,dc=com"},
{use_ssl, false},
{port, 389},
{log, false},
{vhost_access_query, {in_group,
"ou=${vhost}-users,ou=vhosts,dc=example,dc=com"}},
{resource_access_query,
{for, [{permission, configure, {in_group, "cn=admin,dc=example,dc=com"}},
{permission, write,
{for, [{resource, queue, {in_group, "cn=admin,dc=example,dc=com"}},
{resource, exchange, {constant, true}}]}},
{permission, read,
{for, [{resource, exchange, {in_group, "cn=admin,dc=example,dc=com"}},
{resource, queue, {constant, true}}]}}
]
}},
{topic_access_query,
{for, [{permission, write, {match, {string, "${routing_key}"}, {string, "^a"}}},
{permission, read, {constant, true}}
]
}},
{tag_queries, [{administrator, {constant, false}},
{management, {constant, true}}]}
]
}
].

故障排除

使用 LDAP 进行身份验证和/或授权会在系统中引入另一个活动部分。由于 LDAP 服务器是通过网络访问的,因此 网络故障排除TLS 故障排除 指南中涵盖的一些主题适用于 LDAP。

为了对身份验证和授权阶段执行的 LDAP 操作进行故障排除,强烈建议 启用 LDAP 流量日志记录

ldapsearch 是一个与 LDAP 配套的命令行工具,它使您能够对 OpenLDAP 安装执行任意 LDAP 查询。这在对复杂的授权查询进行故障排除时非常有用。 ldp.exe 是 Active Directory 的对应工具。

LDAP 代理

可以使用 LDAP 代理修改此插件执行的 LDAP 请求。 ldaptor 是一个库,可用于将自定义逻辑构建到代理中。

操作员应注意,使用代理将使 LDAP 请求故障排除 更加困难。

© 2024 RabbitMQ. All rights reserved.