本章介绍 Apache ActiveMQ Artemis 的安全工作原理以及如何配置安全。

1. 基本配置

默认情况下启用安全。要完全禁用安全,请在 broker.xml 文件中将 security-enabled 属性设置为 false,例如:

<configuration...>
   <core...>
      ...
      <security-enabled>false</security-enabled>
      ...
   </core>
</configuration>

2. 缓存安全操作

出于性能原因,身份验证和授权分别被缓存。当缓存达到其最大大小时,会从缓存中删除条目(即失效),在这种情况下,将删除最不经常使用的条目,或者当条目在缓存中“停留太久”时。

缓存的大小由 authentication-cache-sizeauthorization-cache-size 配置参数控制。两者默认值为 1000。使用 0 将禁用相应的缓存。

缓存条目有效的时长由 security-invalidation-interval 控制,该值以毫秒为单位。默认值为 10000 毫秒。

3. 追踪已验证用户

为了帮助进行安全审计,提供了 populate-validated-user 选项。如果为 true,则服务器将使用 _AMQ_VALIDATED_USER 密钥将已验证用户的名称添加到消息中。对于 JMS 和 Stomp 客户端,此密钥映射到 JMSXUserID 密钥。对于基于其 SSL 证书进行身份验证的用户,此名称是其证书的 DN 映射到的名称。如果 security-enabledfalsepopulate-validated-usertrue,则服务器将只使用客户端提供的任何用户名(如果有)。此选项默认值为 false

还可以设置 reject-empty-validated-user。如果为 true,则服务器将拒绝任何没有已验证用户的消息。此选项默认值为 false

4. 基于角色的地址安全

Apache ActiveMQ Artemis 包含一个灵活的基于角色的安全模型,用于根据其地址对队列应用安全。

使用核心 中所述,Apache ActiveMQ Artemis 核心主要由绑定到地址的队列集组成。消息被发送到一个地址,服务器查找绑定到该地址的队列集,然后服务器将消息路由到这些队列集。

Apache ActiveMQ Artemis 允许根据队列的地址定义对队列的一组权限。可以使用地址的精确匹配,也可以使用 通配符匹配

可以对与地址匹配的队列集授予不同的权限。这些权限包括:

createAddress

此权限允许用户创建符合 match 的地址。

deleteAddress

此权限允许用户删除符合 match 的地址。

createDurableQueue

此权限允许用户在匹配的地址下创建持久队列。

deleteDurableQueue

此权限允许用户在匹配的地址下删除持久队列。

createNonDurableQueue

此权限允许用户在匹配的地址下创建非持久队列。

deleteNonDurableQueue

此权限允许用户在匹配的地址下删除非持久队列。

send

此权限允许用户向匹配的地址发送消息。

consume

此权限允许用户从绑定到匹配的地址的队列中使用消息。

browse

此权限允许用户浏览绑定到匹配地址的队列。

manage

此权限允许用户通过向管理地址发送管理消息来调用管理操作。

以下两个权限与对代理 管理 API 的操作有关。它们将管理操作分成两组,view 用于只读操作,edit 用于修改操作。拆分由正则表达式控制。与之匹配的方法将需要 view 权限,其他所有方法都需要 edit 权限。正则表达式可以通过配置属性 view-permission-method-match-pattern 进行修改。这些权限适用于 管理地址 以及 MBean 访问。它们被授予匹配以 管理前缀 为前缀的地址。

view

此权限允许访问管理操作的只读子集。

edit

此权限允许访问修改管理操作,即任何不在 view 集中的操作。

对于每项权限,都指定了授予该权限的角色列表。如果用户拥有这些角色中的任何一个,他/她将被授予对该地址集的该权限。

让我们看一个简单的例子,这是 broker.xml 文件中的安全块

<security-setting match="globalqueues.europe.#">
   <permission type="createDurableQueue" roles="admin"/>
   <permission type="deleteDurableQueue" roles="admin"/>
   <permission type="createNonDurableQueue" roles="admin, guest, europe-users"/>
   <permission type="deleteNonDurableQueue" roles="admin, guest, europe-users"/>
   <permission type="send" roles="admin, europe-users"/>
   <permission type="consume" roles="admin, europe-users"/>
</security-setting>

使用默认的 通配符语法# 字符表示“任何单词序列”。单词由 . 字符分隔。因此,上述安全块适用于以字符串“globalqueues.europe.”开头的任何地址。

只有拥有 admin 角色的用户才能创建或删除绑定到以字符串“globalqueues.europe.”开头的地址的持久队列。

任何拥有 adminguesteurope-users 角色的用户都可以创建或删除绑定到以字符串“globalqueues.europe.”开头的地址的临时队列。

任何拥有 admineurope-users 角色的用户都可以向这些地址发送消息或从绑定到以字符串“globalqueues.europe.”开头的地址的队列中使用消息。

用户与其拥有的角色之间的映射由安全管理器处理。Apache ActiveMQ Artemis 附带一个用户管理器,该管理器从磁盘上的文件读取用户凭据,还可以插入 JAAS 或 JBoss Application Server 安全。

有关配置安全管理器的更多信息,请参见“更改安全管理器”。

每个 XML 文件中可以包含零个或多个 security-setting 元素。当多个匹配项适用于地址集时,更具体的匹配项优先。

让我们看一个例子,这是另一个 security-setting

<security-setting match="globalqueues.europe.orders.#">
   <permission type="send" roles="europe-users"/>
   <permission type="consume" roles="europe-users"/>
</security-setting>

在此 security-setting 块中,匹配项 globalqueues.europe.orders.# 比之前的匹配项 globalqueues.europe.# 更具体。因此,与 globalqueues.europe.orders.# 匹配的任何地址都将从后一个 security-setting 块中获取其安全设置。

请注意,设置不会从前一个块继承。所有设置将从更具体的匹配块中获取,因此对于地址 globalqueues.europe.orders.plastics,唯一存在的权限是 europe-users 角色的 sendconsume 权限。权限 createDurableQueuedeleteDurableQueuecreateNonDurableQueuedeleteNonDurableQueue 不会从另一个 security-setting 块中继承。

通过不继承权限,可以有效地通过在更具体的 security-setting 块中不指定权限来拒绝权限。否则,将无法在地址子组中拒绝权限。

4.1. 使用完全限定队列名称的细粒度安全

在某些情况下,可能需要配置比整个地址更细粒度的安全。例如,考虑一个具有多个队列的地址

<addresses>
   <address name="foo">
      <anycast>
         <queue name="q1" />
         <queue name="q2" />
      </anycast>
   </address>
</addresses>

您可能希望将对 q1 的使用限制为一个角色,将对 q2 的使用限制为另一个角色。您可以在 security-settingmatch 中使用完全限定队列名称(即 FQQN)来实现,例如:

<security-setting match="foo::q1">
   <permission type="consume" roles="q1Role"/>
</security-setting>
<security-setting match="foo::q2">
   <permission type="consume" roles="q2Role"/>
</security-setting>
通配符匹配不与 FQQN 一起使用。此处使用 FQQN 的明确目标是精确

4.2. 将 viewedit 权限应用于管理 API

viewedit 权限可以选择应用于代理的管理 API。

对于 JMX MBean 访问的 RBAC,它们可以替换 management.xml 中的授权部分,如 broker.xml 中的 JMX 授权 中所述

对于通过发送到管理地址的消息访问的管理资源的 RBAC,通过配置 management-message-rbac 启用附加权限,如 管理消息的细粒度 RBAC 中所述

需要 viewedit 权限的操作之间的拆分可以通过 view-permission-method-match-pattern 进行控制

5. 安全设置插件

除了通过 XML 配置权限集之外,还可以通过实现 org.apache.activemq.artemis.core.server.SecuritySettingPlugin 的插件来配置这些权限,例如:

<security-settings>
   <security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
      <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
      <setting name="connectionURL" value="ldap://127.0.0.1:1024"/>
      <setting name="connectionUsername" value="uid=admin,ou=system"/>
      <setting name="connectionPassword" value="secret"/>
      <setting name="connectionProtocol" value="s"/>
      <setting name="authentication" value="simple"/>
   </security-setting-plugin>
</security-settings>

大多数此配置特定于插件实现。但是,有两个配置细节将为每个实现指定

class-name

security-setting-plugin 的此属性指示实现 org.apache.activemq.artemis.core.server.SecuritySettingPlugin 的类的名称。

setting

每个元素都表示一个名称/值对,该对将传递给实现以用于配置目的。

有关接口以及预期每个方法执行的操作的更多详细信息,请参见 org.apache.activemq.artemis.core.server.SecuritySettingPlugin 的 JavaDoc。

5.1. 可用插件

5.1.1. LegacyLDAPSecuritySettingPlugin

此插件将读取以前由 LDAPAuthorizationMapcachedLDAPAuthorizationMap 在 Apache ActiveMQ "Classic" 中处理的安全信息,并尽可能将其转换为 Artemis 安全设置。ActiveMQ "Classic" 和 Artemis 的安全实现并不完全匹配,因此需要进行一些转换才能实现近似等效的功能。

以下是一个插件配置的示例

<security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
   <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
   <setting name="connectionURL" value="ldap://127.0.0.1:1024"/>
   <setting name="connectionUsername" value="uid=admin,ou=system"/>
   <setting name="connectionPassword" value="secret"/>
   <setting name="connectionProtocol" value="s"/>
   <setting name="authentication" value="simple"/>
</security-setting-plugin>
class-name

实现是 org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin

initialContextFactory

用于连接到 LDAP 的初始上下文工厂。它必须始终设置为 com.sun.jndi.ldap.LdapCtxFactory(即默认值)。

connectionURL

使用 ldap URL 指定目录服务器的位置,ldap://Host:Port。您可以选择性地限定此 URL,方法是添加正斜杠,/,后跟目录树中特定节点的 DN。例如,ldap://ldapserver:10389/ou=system。默认值为 ldap://127.0.0.1:1024

connectionUsername

打开到目录服务器的连接的用户的 DN。例如,uid=admin,ou=system。目录服务器通常要求客户端提供用户名/密码凭据才能打开连接。

connectionPassword

connectionUsername 中的 DN 匹配的密码。在目录服务器中,在 DIT 中,密码通常存储为相应目录条目中的 userPassword 属性。

connectionProtocol

目前,唯一支持的值为空字符串。将来,此选项将允许您为与目录服务器的连接选择安全套接字层 (SSL)。

此选项必须显式设置为空字符串,因为它没有默认值。
authentication

指定绑定到 LDAP 服务器时使用的身份验证方法。可以采用以下两种值之一:simple(用户名和密码,默认值)或 none(匿名)。

目前不支持简单身份验证和安全层 (SASL) 身份验证。
destinationBase

指定其子级提供所有目标权限的节点的 DN。在这种情况下,DN 是一个字面值(也就是说,不会对属性值执行任何字符串替换)。例如,此属性的典型值为 ou=destinations,o=ActiveMQ,ou=system(即默认值)。

filter

指定一个 LDAP 搜索过滤器,该过滤器用于查找任何类型目标的权限。搜索过滤器尝试匹配队列或主题节点的子级或后代之一。默认值为 (cn=*)

roleAttribute

指定由 filter 匹配的节点的属性,其值为角色的 DN。默认值为 uniqueMember

adminPermissionValue

指定与 admin 权限匹配的值。默认值为 admin

readPermissionValue

指定与 read 权限匹配的值。默认值为 read

writePermissionValue

指定与 write 权限匹配的值。默认值为 write

enableListener

是否启用一个监听器,该监听器将自动接收在 LDAP 服务器中进行的更新并实时更新代理的授权配置。默认值为 true

某些 LDAP 服务器(例如 OpenLDAP)不支持允许“监听器”功能工作的“持久搜索”功能。对于这些服务器,将 refreshInterval 设置为大于 0 的值。

refreshInterval

从 LDAP 服务器刷新安全设置之前等待的时间(以秒为单位)。这可用于不支持使用 enableListener 所需的“持久搜索”功能的 LDAP 服务器(例如 OpenLDAP)。默认值为 0(即不刷新)。

请记住,这可能是一个潜在的昂贵操作,具体取决于刷新配置的频率以及数据集的大小,因此请注意如何配置 refreshInterval

mapAdminToManage

是否将旧的 admin 权限映射到 manage 权限。请参阅下面关于映射语义的详细信息。默认值为 false

allowQueueAdminOnRead

是否将旧的 read 权限映射到 createDurableQueuecreateNonDurableQueuedeleteDurableQueue 权限,以便 JMS 客户端无需 admin 权限即可创建持久和非持久订阅。这在 ActiveMQ "Classic" 中是允许的。默认值为 false

在 LDAP 中定义的队列或主题的名称将用作安全设置的“匹配”,权限值将从 ActiveMQ "Classic" 类型映射到 Artemis 类型,角色将按原样映射。

ActiveMQ "Classic" 只有 3 种权限类型:readwriteadmin。这些权限类型在他们的 网站 上有描述。但是,如前所述,ActiveMQ Artemis 有 9 种权限类型:createAddressdeleteAddresscreateDurableQueuedeleteDurableQueuecreateNonDurableQueuedeleteNonDurableQueuesendconsumebrowsemanage。以下是旧类型如何映射到新类型

read

consumebrowse

write

send

admin

createAddressdeleteAddresscreateDurableQueuedeleteDurableQueuecreateNonDurableQueuedeleteNonDurableQueuemanage(如果 mapAdminToManagetrue

如前所述,为了实现一些等效性,在几个地方进行了转换。

  • 此映射默认不包括 Artemis manage 权限类型,因为 ActiveMQ "Classic" 中没有与此类似的类型。但是,如果 mapAdminToManagetrue,则旧的 admin 权限将映射到 manage 权限。

  • ActiveMQ "Classic" 中的 admin 权限与代理是否会在目标不存在时自动创建它以及用户是否向其发送消息有关。Artemis 自动允许在用户有权向其发送消息时自动创建目标。因此,插件默认情况下会将 admin 权限映射到 Artemis 中的上述 6 个权限。如果 mapAdminToManagetrue,则旧的 admin 权限也将映射到 manage 权限。

6. 安全套接字层 (SSL) 传输

当消息客户端连接到服务器,或者服务器通过不受信任的网络连接到其他服务器(例如通过桥接)时,Apache ActiveMQ Artemis 允许使用安全套接字层 (SSL) 传输对该流量进行加密。

有关配置 SSL 传输的更多信息,请参阅 配置传输

7. 用户凭据

Apache ActiveMQ Artemis 附带三个安全管理器实现

  • 灵活的可插拔 ActiveMQJAASSecurityManager,它支持任何标准 JAAS 登录模块。Artemis 附带几个登录模块,将在后面进一步讨论。这是默认的安全管理器。

  • ActiveMQBasicSecurityManager 不使用 JAAS,只支持通过用户名和密码凭据进行身份验证。它还支持通过管理 API 添加、删除和更新用户。所有用户和角色数据都存储在代理的绑定日志中,这意味着对主代理进行的任何更改都将在其备份上可用。

  • 旧的、已弃用的 ActiveMQSecurityManagerImpl,它从类路径上的属性文件(称为 artemis-users.propertiesartemis-roles.properties)读取用户凭据(即用户名、密码和角色信息)。

7.1. JAAS 安全管理器

使用 Java Authentication and Authorization Service (JAAS) 时,大部分配置取决于使用哪个登录模块。但是,每种情况都有一些共性。首先要查看的是 bootstrap.xml。以下是一个使用 PropertiesLogin JAAS 登录模块(从属性文件读取用户、密码和角色信息)的示例

<jaas-security domain="PropertiesLogin"/>

无论使用哪个登录模块,都需要在 bootstrap.xml 中指定它。此处的 domain 属性引用 login.config 中的相关登录模块条目。例如

PropertiesLogin {
    org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule required
        debug=true
        org.apache.activemq.jaas.properties.user="artemis-users.properties"
        org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

login.config 文件是一个标准的 JAAS 配置文件。您可以在 Oracle 网站 上了解更多关于此文件的信息。简而言之,该文件定义了

  • 条目的别名(例如 PropertiesLogin

  • 登录模块的实现类(例如 org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule

  • 一个标志,指示登录模块的成功是 requiredrequisitesufficient 还是 optional(有关这些标志的更多详细信息,请参阅 JavaDoc

  • 特定于登录模块实现的配置选项列表

默认情况下,login.config 的位置和名称在 Artemis 命令行上指定,该命令行由 linux 上的 etc/artemis.profile 和 Windows 上的 etc\artemis.profile.cmd 设置。

7.1.1. 双重身份验证

JAAS 安全管理器还支持另一个配置参数 - certificate-domain。当您想基于 SSL 证书(例如使用下面讨论的 CertificateLoginModule)对使用 SSL 连接的客户端进行身份验证时,这很有用,但您仍然希望使用用户名和密码对使用非 SSL 连接的客户端进行身份验证。以下是在 bootstrap.xml 中的示例

<jaas-security domain="PropertiesLogin" certificate-domain="CertLogin"/>

以下是相应的 login.config

PropertiesLogin {
   org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule required
       debug=false
       org.apache.activemq.jaas.properties.user="artemis-users.properties"
       org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

CertLogin {
   org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule required
       debug=true
       org.apache.activemq.jaas.textfiledn.user="cert-users.properties"
       org.apache.activemq.jaas.textfiledn.role="cert-roles.properties";
};

当代理以这种方式配置时,任何使用 SSL 和客户端证书连接的客户端将使用 CertLogin 进行身份验证,任何不使用 SSL 连接的客户端将使用 PropertiesLogin 进行身份验证。

7.2. JAAS 登录模块

7.2.1. GuestLoginModule

允许没有凭据的用户(以及根据其配置方式,也可能允许具有无效凭据的用户)访问代理。通常,访客登录模块与另一个登录模块(例如属性登录模块)链接。它由 org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule 实现。

org.apache.activemq.jaas.guest.user

要分配的用户名;默认值为“guest”。

org.apache.activemq.jaas.guest.role

要分配的角色名称;默认值为“guests”。

credentialsInvalidate

布尔标志;如果为 true,则拒绝包含密码的登录请求(即只有当用户未提供密码时,访客登录才会成功);默认值为 false

debug

布尔标志;如果为 true,则启用调试;这仅用于测试或调试;通常,它应该设置为 false 或省略;默认值为 false

访客登录模块有两个基本用例,如下所示

  • 没有凭据或凭据无效的访客。

  • 只有没有凭据的访客。

以下代码段显示了如何为具有无凭据或无效凭据的用户登录作为访客的用例配置 JAAS 登录条目。在此示例中,访客登录模块与属性登录模块结合使用。

activemq-domain {
  org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient
      debug=true
      org.apache.activemq.jaas.properties.user="artemis-users.properties"
      org.apache.activemq.jaas.properties.role="artemis-roles.properties";

  org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
      debug=true
      org.apache.activemq.jaas.guest.user="anyone"
      org.apache.activemq.jaas.guest.role="restricted";
};

根据用户登录数据,身份验证过程如下

  • 用户使用有效密码登录 - 属性登录模块成功验证用户身份并立即返回。不会调用访客登录模块。

  • 用户使用无效密码登录 - 属性登录模块无法验证用户身份,身份验证过程将继续进行到访客登录模块。访客登录模块成功验证用户身份并返回访客主体。

  • 用户使用空白密码登录 - 属性登录模块无法验证用户身份,身份验证过程将继续进行到访客登录模块。访客登录模块成功验证用户身份并返回访客主体。

以下代码片段展示了如何为仅使用没有凭据的用户以访客身份登录的用例配置 JAAS 登录条目。要支持此用例,您必须在访客登录模块的配置中将 credentialsInvalidate 选项设置为 true。您还应注意,与前面的示例相比,登录模块的顺序已颠倒,附加到属性登录模块的标志已更改为必需。

activemq-guest-when-no-creds-only-domain {
    org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
        debug=true
       credentialsInvalidate=true
       org.apache.activemq.jaas.guest.user="guest"
       org.apache.activemq.jaas.guest.role="guests";

    org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule requisite
        debug=true
        org.apache.activemq.jaas.properties.user="artemis-users.properties"
        org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

根据用户登录数据,身份验证过程如下

  • 用户使用有效密码登录 - 访客登录模块无法验证用户身份(因为用户在 credentialsInvalidate 选项启用时提供了密码),身份验证过程将继续进行到属性登录模块。属性登录模块成功验证用户身份并返回。

  • 用户使用无效密码登录 - 访客登录模块无法验证用户身份,身份验证过程将继续进行到属性登录模块。属性登录模块也无法验证用户身份。最终结果是身份验证失败。

  • 用户使用空白密码登录 - 访客登录模块成功验证用户身份并立即返回。不会调用属性登录模块。

7.2.2. PropertiesLoginModule

JAAS 属性登录模块提供了一个简单的身份验证数据存储,其中相关用户数据存储在一个一对扁平文件中。这对演示和测试来说很方便,但对于企业系统,与 LDAP 的集成更可取。它由 org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule 实现。

org.apache.activemq.jaas.properties.user

包含用户和密码属性的文件的路径

org.apache.activemq.jaas.properties.role

包含用户和角色属性的文件的路径

org.apache.activemq.jaas.properties.password.codec

要使用的密码编解码器的完全限定类名。有关其工作原理的更多详细信息,请参阅 密码屏蔽 文档。

reload

布尔标志;是否在修改发生时重新加载属性文件;默认为 false

debug

布尔标志;如果为 true,则启用调试;这仅用于测试或调试;通常,它应该设置为 false 或省略;默认值为 false

在属性登录模块的上下文中,artemis-users.properties 文件包含一列形式为 UserName=Password 的属性。例如,要定义用户 systemuserguest,您可以创建如下文件

system=manager
user=password
guest=password

artemis-users.properties 中的密码可以被哈希。此类密码应遵循语法 ENC(<hash>)

可以使用 Artemis *实例* 中的 user CLI 命令轻松地将哈希密码添加到 artemis-users.properties 中。此命令不会从 Artemis 主目录工作,并且在代理启动之前也不会工作。

./artemis user add --user-command-user guest --user-command-password guest --role admin

这将使用默认编解码器对密码执行“单向”哈希,并使用指定的 value 更改 artemis-users.propertiesartemis-roles.properties 文件。

artemis-roles.properties 文件包含一列形式为 Role=UserList 的属性,其中 UserList 是一个以逗号分隔的用户列表。例如,要定义角色 adminsusersguests,您可以创建如下文件

admins=system
users=system,user
guests=guest

如上所述,Artemis 命令行界面支持一个命令来 add 用户。还支持通过命令行界面以及正常的管理界面(例如 JMX、Web 控制台等)来 list(一个或所有)用户、remove 用户以及 reset 用户的密码和/或角色。

警告

仅当使用 PropertiesLoginModule 时,才能进行操作用户和角色数据的管理和 CLI 操作。

通常,不建议使用属性文件和代理中心的用户信息管理来执行除最基本用例之外的任何操作。代理旨在处理消息。它不负责管理用户,尽管出于方便目的,该功能在有限的范围内提供。建议在企业级生产用例中使用 LDAP。

7.2.3. LDAPLoginModule

LDAP 登录模块允许您通过检查传入的凭据与存储在中央 X.500 目录服务器中的用户数据来执行身份验证和授权。对于已经拥有 X.500 目录服务器的系统,这意味着您可以快速将 ActiveMQ Artemis 与现有安全数据库集成,并且可以使用 X.500 系统管理用户帐户。它由 org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule 实现。

initialContextFactory

必须始终设置为 com.sun.jndi.ldap.LdapCtxFactory

connectionURL

使用 ldap URL(ldap://Host:Port)指定目录服务器的位置。您可以通过添加正斜杠 / 以及目录树中特定节点的 DN 来选择性地限定此 URL。例如,ldap://ldapserver:10389/ou=system。

authentication

指定绑定到 LDAP 服务器时使用的身份验证方法。可以取以下任一值:simple(用户名和密码)、GSSAPI(Kerberos SASL)或 none(匿名)。

connectionUsername

打开与目录服务器连接的用户 DN。例如,uid=admin,ou=system。目录服务器通常要求客户端提供用户名/密码凭据才能打开连接。

connectionPassword

connectionUsername 中的 DN 匹配的密码。在目录服务器中,在 DIT 中,密码通常存储为对应目录条目中的 userPassword 属性。

saslLoginConfigScope

在 JAAS 配置(login.config)中使用的范围,以获取 Kerberos 发起方凭据(当 authentication 方法为 SASL GSSAPI 时)。默认值为 broker-sasl-gssapi

connectionProtocol

当前,唯一支持的值是空字符串。将来,此选项将允许您为与目录服务器的连接选择安全套接字层 (SSL)。此选项必须显式设置为空字符串,因为它没有默认值。

connectionTimeout

指定表示以毫秒为单位的连接超时的整数的字符串表示形式。如果 LDAP 提供程序无法在该时间段内建立连接,它将中止连接尝试。整数应大于零。小于或等于零的整数表示使用网络协议(即 TCP)的超时值。

如果未指定 connectionTimeout,则默认情况下将等待连接建立或直到底层网络超时。

当请求连接池以用于连接时,此属性还决定了当池中的所有连接都在使用中并且已达到最大池大小时,连接的最大等待时间。如果此属性的值在这种情况下小于或等于零,则提供程序将无限期地等待连接可用;否则,提供程序将在超过最大等待时间时中止等待。有关更多详细信息,请参阅 connectionPool

readTimeout

指定表示 LDAP 操作读取超时的整数的字符串表示形式。如果 LDAP 提供程序无法在该时间段内获取 LDAP 响应,它将中止读取尝试。整数应大于零。小于或等于零的整数表示未指定读取超时,这等效于无限期地等待响应,直到收到响应为止。

如果未指定 readTimeout,则默认情况下将等待响应,直到收到响应为止。

userBase

选择 DIT 的特定子树来搜索用户条目。子树由一个 DN 指定,该 DN 指定子树的基节点。例如,通过将此选项设置为 ou=User,ou=ActiveMQ,ou=system,用户条目的搜索将限制在 ou=User,ou=ActiveMQ,ou=system 节点下方的子树中。

userSearchMatching

指定一个 LDAP 搜索过滤器,它将应用于由 userBase 选择的子树。在传递到 LDAP 搜索操作之前,您在此处提供的字符串值将经过字符串替换,如 java.text.MessageFormat 类所实现。从本质上讲,这意味着特殊字符串 {0} 将被从传入的客户端凭据中提取的用户名替换。

替换后,该字符串将被解释为 LDAP 搜索过滤器,其中 LDAP 搜索过滤器的语法由 IETF 标准 RFC 2254 定义。Oracle 的 JNDI 教程 搜索过滤器 中提供了一个关于搜索过滤器语法的简短介绍。

例如,如果此选项设置为 (uid={0}) 且接收到的用户名为 jdoe,则搜索过滤器在字符串替换后变为 (uid=jdoe)。如果将生成的搜索过滤器应用于由用户基 ou=User,ou=ActiveMQ,ou=system 选择的子树,它将匹配条目 uid=jdoe,ou=User,ou=ActiveMQ,ou=system(以及可能更深层嵌套的条目,具体取决于指定的搜索深度 - 请参阅 userSearchSubtree 选项)。

userSearchSubtree

指定相对于由 userBase 指定的节点的用户条目的搜索深度。此选项是一个布尔值。false 表示它将尝试匹配 userBase 节点的一个子条目(映射到 javax.naming.directory.SearchControls.ONELEVEL_SCOPE)。true 表示它将尝试匹配属于 userBase 节点的子树的任何条目(映射到 javax.naming.directory.SearchControls.SUBTREE_SCOPE)。

userRoleName

指定用户条目中包含用户角色名称列表的多值属性的名称(其中角色名称被代理的授权插件解释为组名)。如果省略此选项,则不会从用户条目中提取任何角色名称。

roleBase

如果要将角色数据直接存储在目录服务器中,可以使用角色选项(roleBaseroleSearchMatchingroleSearchSubtreeroleName)的组合作为指定 userRoleName 选项的替代方案(或附加方案)。此选项选择 DIT 的特定子树来搜索角色/组条目。子树由一个 DN 指定,该 DN 指定子树的基节点。例如,通过将此选项设置为 ou=Group,ou=ActiveMQ,ou=system,角色/组条目的搜索将限制在 ou=Group,ou=ActiveMQ,ou=system 节点下方的子树中。

roleName

指定角色条目中包含角色/组名称的属性类型(例如 C、O、OU 等)。如果省略此选项,则使用角色的完整 DN。

roleSearchMatching

指定一个 LDAP 搜索过滤器,它将应用于由 roleBase 选择的子树。它的工作方式与 userSearchMatching 选项类似,只是它支持两个替换字符串,如下所示

  • {0} - 替换匹配的用户条目的完整 DN(即用户搜索的结果)。例如,对于用户 jdoe,替换的字符串可能是 uid=jdoe,ou=User,ou=ActiveMQ,ou=system

  • {1} - 替换接收到的用户名。例如,jdoe

例如,如果将此选项设置为 (member=uid={1}) 并且接收到的用户名为 jdoe,则在进行字符串替换后,搜索过滤器将变为 (member=uid=jdoe)(假设使用 ApacheDS 搜索过滤器语法)。如果将生成的搜索过滤器应用于角色基础所选择的子树 ou=Group,ou=ActiveMQ,ou=system,则它将匹配所有具有 member 属性等于 uid=jdoe 的角色条目(member 属性的值是 DN)。

+ 必须始终设置此选项以启用角色搜索,因为它没有默认值。不设置它将禁用角色搜索,并且角色信息必须来自 userRoleName

+ 如果使用 OpenLDAP,则搜索过滤器的语法为 (member:=uid=jdoe)

roleSearchSubtree

指定角色条目的搜索深度,相对于由 roleBase 指定的节点。此选项可以接受布尔值,如下所示

  • false(默认) - 尝试匹配 roleBase 节点的子条目之一(映射到 javax.naming.directory.SearchControls.ONELEVEL_SCOPE)。

  • true — 尝试匹配属于 roleBase 节点的子树的任何条目(映射到 javax.naming.directory.SearchControls.SUBTREE_SCOPE)。

authenticateUser

禁用身份验证的布尔标志。当此模块仅用于主体现有已验证主体角色映射时,此选项很有用;默认为 true

referral

指定如何处理推荐;有效值:ignorefollowthrow;默认值为 ignore

ignorePartialResultException

在搜索 Active Directory (AD) 时使用的布尔标志。AD 服务器不会自动处理推荐,这会导致在搜索遇到推荐时抛出 PartialResultException,即使 referral 设置为 ignore。设置为 true 以忽略这些异常;默认为 false

expandRoles

指示是否启用角色扩展功能的布尔值;默认为 false。如果启用,则会找到角色中的角色。例如,角色 A 在角色 B 中。用户 X 在角色 A 中,这意味着用户 X 由于在角色 A 中而在角色 B 中。

expandRolesMatching

指定应用于由 roleBase 选择的子树的 LDAP 搜索过滤器。在传递到 LDAP 搜索操作之前,您在此处提供的字符串值将经过字符串替换,如 java.text.MessageFormat 类所实现的那样。本质上,这意味着特殊字符串 {0} 将被从先前角色搜索中提取的角色名称替换。必须始终设置此选项以启用角色扩展,因为它没有默认值。示例值:(member={0})

noCacheExceptions

逗号分隔的类名或正则表达式列表,用于匹配在与 LDAP 服务器通信期间可能抛出的异常;默认为空。通常,任何身份验证失败都将存储在身份验证缓存中,以便基础安全数据存储(例如 LDAP)免受任何不必要的流量。例如,密码错误的应用程序在短时间内多次尝试登录可能会对 LDAP 服务器产生负面影响。但是,如果失败是由于临时网络故障,例如 security-invalidation-interval 相对较高,则缓存此类失败会更好。用户可以枚举缓存应忽略的任何相关异常(例如 java.net.ConnectException)。异常名称或正则表达式应与相关堆栈跟踪中的根本原因匹配。用户可以通过启用 org.apache.activemq.artemis.core.security.impl.SecurityStoreImpl 的调试日志记录来确认已跳过配置的异常。

debug

布尔标志;如果为 true,则启用调试;这仅用于测试或调试;通常,它应该设置为 false 或省略;默认值为 false

任何 LDAP 登录模块本身无法识别的其他配置选项都将按原样传递到底层 LDAP 连接逻辑。

在由 userBase 选项指定的节点下添加用户条目。在目录中创建新用户条目时,选择支持 userPassword 属性的对象类(例如,personinetOrgPerson 对象类通常适合)。创建用户条目后,添加 userPassword 属性,以保存用户的密码。

如果要将角色数据存储在专用角色条目中(每个节点代表特定角色),请按如下方式创建角色条目。创建 roleBase 节点的新的子节点,其中子节点的 objectClassgroupOfNames。将新子节点的 cn(或 roleName 指定的任何属性类型)设置为角色/组的名称。为角色/组的每个成员定义一个 member 属性,将 member 值设置为相应用户的 DN(其中 DN 是完全指定,uid=jdoe,ou=User,ou=ActiveMQ,ou=system,或部分指定,uid=jdoe)。

如果要向用户条目添加角色,您需要自定义目录模式,方法是向用户条目的对象类添加合适的属性类型。所选属性类型必须能够处理多个值。

7.2.4. CertificateLoginModule

JAAS 证书身份验证登录模块必须与 SSL 结合使用,并且客户端必须配置自己的证书。在这种情况下,身份验证实际上是在 SSL/TLS 握手期间执行的,而不是直接由 JAAS 证书身份验证插件执行。插件的作用如下

  • 为了进一步限制可接受用户的集合,因为只有相关属性文件中明确列出的用户 DN 才有资格进行身份验证。

  • 将组列表与接收到的用户身份相关联,以促进与授权功能的集成。

  • 要求存在传入证书(默认情况下,SSL/TLS 层配置为将客户端证书的存在视为可选)。

JAAS 证书登录模块在两个平面文件中存储证书 DN 集合。这些文件将用户名和组 ID 列表与每个 DN 相关联。

证书登录模块由以下类实现

org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule

以下 CertLogin 登录条目显示了如何在 login.config 文件中配置证书登录模块

CertLogin {
    org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
        debug=true
        org.apache.activemq.jaas.textfiledn.user="users.properties"
        org.apache.activemq.jaas.textfiledn.role="roles.properties";
};

在上面的示例中,JAAS 域配置为使用单个 org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule 登录模块。此登录模块支持的选项如下

debug

布尔标志;如果为 true,则启用调试;这仅用于测试或调试;通常,应将其设置为 false 或省略;默认为 false

org.apache.activemq.jaas.textfiledn.user

指定用户属性文件的位置(相对于包含登录配置文件的目录)。

org.apache.activemq.jaas.textfiledn.role

指定角色属性文件的位置(相对于包含登录配置文件的目录)。

reload

布尔标志;是否在修改发生时重新加载属性文件;默认为 false

normalise

布尔标志;是否应验证 DN 值并将其规范化为用于匹配的 X500Name 字符串格式;默认为 false。使用此选项可以避免下面讨论的有关 DN 字符串形式的歧义。当为 true 时,DN 字符串将被验证,然后规范化为内部 X500Name 格式。

在证书登录模块的上下文中,users.properties 文件包含一系列形式为 UserName=StringifiedSubjectDNUserName=/SubjectDNRegExp/ 的属性。例如,要定义用户 systemuserguest 以及匹配多个 DN 的 hosts 用户,您可以创建一个如下所示的文件

system=CN=system,O=Progress,C=US
user=CN=humble user,O=Progress,C=US
guest=CN=anon,O=Progress,C=DE
hosts=/CN=host\\d+\\.acme\\.com,O=Acme,C=UK/

请注意,反斜杠字符必须转义,因为它在属性文件中具有特殊处理。

每个用户名都映射到一个主体 DN,以字符串形式编码(其中字符串编码由 RFC 2253 指定)。例如,系统用户名映射到 CN=system,O=Progress,C=US 主体 DN。在执行身份验证时,插件从接收到的证书中提取主体 DN,将其转换为标准字符串格式,并通过测试字符串是否相等来将其与 users.properties 文件中的主体 DN 进行比较。因此,您必须注意确保出现在 users.properties 文件中的主体 DN 与从用户证书中提取的主体 DN 完全匹配。

从技术上讲,DN 字符串格式中存在一些残余的歧义。例如,domainComponent 属性可以以字符串形式表示为 DC 或 OID 0.9.2342.19200300.100.1.25。通常,您不必担心这种歧义。但如果更改了 Java 安全层的底层实现,它可能会成为问题。

从用户证书中获取主体 DN 的最简单方法是调用 keytool 实用程序以打印证书内容。要打印密钥库文件中证书的内容,请执行以下步骤

  1. 将证书从密钥库文件导出到临时文件。例如,要从 broker.ks 密钥库文件中导出别名为 broker-localhost 的证书,请输入以下命令

    keytool -export -file broker.export -alias broker-localhost -keystore broker.ks -storepass password

    运行此命令后,导出的证书将位于文件 broker.export 中。

  2. 打印出导出的证书的内容。例如,要打印出 broker.export 的内容,请输入以下命令

    keytool -printcert -file broker.export

    这将生成类似于此处显示的内容的输出

    Owner: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
    Issuer: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
    Serial number: 4537c82e
    Valid from: Thu Oct 19 19:47:10 BST 2006 until: Wed Jan 17 18:47:10 GMT 2007
    Certificate fingerprints:
             MD5:  3F:6C:0C:89:A8:80:29:CC:F5:2D:DA:5C:D7:3F:AB:37
             SHA1: F0:79:0D:04:38:5A:46:CE:86:E1:8A:20:1F:7B:AB:3A:46:E4:34:5C

    Owner: 后面的字符串给出了主体 DN。用于输入主体 DN 的格式取决于您的平台。上面的 Owner: 字符串可以表示为 CN=localhost,\ OU=broker,\ O=Unknown,\ L=Unknown,\ ST=Unknown,\ C=UnknownCN=localhost,OU=broker,O=Unknown,L=Unknown,ST=Unknown,C=Unknown

roles.properties 文件包含一系列形式为 Role=UserList 的属性,其中 UserList 是用逗号分隔的用户列表。例如,要定义角色 adminsusersguests,您可以创建一个如下所示的文件

admins=system
users=system,user
guests=guest

7.2.5. SCRAMPropertiesLoginModule

SCRAM 属性登录模块实现了 SASL 挑战响应,用于 SCRAM-SHA 机制。org.apache.activemq.jaas.properties.user 引用的属性文件中的数据需要由登录模块本身生成,作为用户注册的一部分。它包含密码知识的证明,而不是密码本身。有关更多使用细节,请参阅 SCRAM-SHA SASL 机制

amqp-sasl-scram {
   org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule required
       org.apache.activemq.jaas.properties.user="artemis-users.properties"
       org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

7.2.6. SCRAMLoginModule

SCRAM 登录模块将有效的 SASL SCRAM-SHA 已验证身份转换为 JAAS 用户主体。然后可以使用此主体进行 角色映射

{
   org.apache.activemq.artemis.spi.core.security.jaas.SCRAMLoginModule
};

7.2.7. ExternalCertificateLoginModule

外部证书登录模块用于将已验证的 TLS 客户端证书的 subjectDN 传播到 JAAS 用户主体。这允许后续登录模块为 TLS 客户端证书执行角色映射。

org.apache.activemq.artemis.spi.core.security.jaas.ExternalCertificateLoginModule required
    ;

7.2.8. PrincipalConversionLoginModule

主体转换登录模块用于将现有的已验证主体转换为 JAAS 用户主体。该模块配置了用于匹配现有主体的类名列表。如果不存在用户主体,则第一个匹配的主体将作为相同名称的用户主体添加。

org.apache.activemq.artemis.spi.core.security.jaas.PrincipalConversionLoginModule required
     principalClassList=org.apache.x.Principal,org.apache.y.Principal
    ;

7.2.9. Krb5LoginModule

Kerberos 登录模块用于将已验证的 SASL GSSAPI kerberos 令牌身份传播到已验证的 JAAS 用户主体。这允许后续登录模块为 kerberos 身份执行角色映射。

org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule required
    ;

使登录配置可供 JAAS 使用的最简单方法是将包含文件 login.config 的目录添加到您的 CLASSPATH 中。

7.2.10. KubernetesLoginModule

Kubernetes 登录模块允许您通过将 Bearer 令牌与 Kubernetes API 进行验证来执行身份验证和授权。身份验证通过提交 Kubernetes 集群验证的 TokenReview 请求来完成。响应将告诉您用户是否已通过身份验证以及关联的用户名和角色。它由 org.apache.activemq.artemis.spi.core.security.jaas.KubernetesLoginModule 实现。

ignoreTokenReviewRoles

如果为 true,则不从 TokenReview 用户组映射角色。默认值为 false。

org.apache.activemq.jaas.kubernetes.role

包含角色映射的文件的可选路径,在 ignoreTokenReviewRoles=true 时很有用。

reload

布尔标志;是否在修改发生时重新加载属性文件;默认值为 false

debug

布尔标志;如果为 true,则启用调试;这仅用于测试或调试;通常,它应该设置为 false 或省略;默认值为 false

登录模块必须允许查询所需的 Rest API。为此,它将使用 /var/run/secrets/kubernetes.io/serviceaccount/token 下的可用令牌。此外,为了信任连接,客户端将使用同一文件夹中存在的 ca.crt 文件。这两个文件将挂载到容器中。运行 KubernetesLoginModule 的服务帐户必须被允许 create::TokenReviewsystem:auth-delegator 角色通常用于此目的。

可选的角色属性文件由一系列形式为 Role=UserList 的属性组成,其中 UserList 是用逗号分隔的用户列表。例如,要定义角色 admins、users 和 guests,您可以创建如下文件

admins=system:serviceaccounts:example-ns:admin-sa
users=system:serviceaccounts:other-ns:test-sa

7.3. SCRAM-SHA SASL 机制

SCRAM(加盐质询响应身份验证机制)是一种身份验证机制,可以使用密码建立相互身份验证。Apache ActiveMQ Artemis 支持 SCRAM-SHA-256 和 SCRAM-SHA-512 SASL 机制,为 AMQP 连接提供身份验证。

SCRAM 的以下属性使其即使在未加密的连接上使用 SCRAM-SHA 也安全。

  • 密码不会在通信通道上明文传输。客户端受到挑战,要求提供证明它知道正在验证用户的密码,而服务器受到挑战,要求提供证明它拥有用于初始化其身份验证存储的密码。只有证据被交换。

  • 服务器和客户端在每次身份验证交换中都生成一个新的挑战,使其能够抵御重放攻击。

7.3.1. 配置服务器以使用 SCRAM-SHA

所需的 SCRAM-SHA 机制必须在 broker.xml 中的 AMQP 接收器上启用,方法是将它们添加到 saslMechanisms 列表 url 参数中。在此示例中,SASL 仅限于 SCRAM-SHA-256 机制。

  <acceptor name="amqp">tcp://127.0.0.1:5672?protocols=AMQP;saslMechanisms=SCRAM-SHA-256;saslLoginConfigScope=amqp-sasl-scram

值得注意的是,它引用了 sasl 登录配置范围 saslLoginConfigScope=amqp-sasl-scram,该范围包含相关的 SCRAM 登录模块。该机制使用 JAAS 完成 SASL 交换。

以下是 login.config 的示例配置范围,它将使用属性文件实现 SCRAM-SHA-256。

amqp-sasl-scram {
   org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule required
       org.apache.activemq.jaas.properties.user="artemis-users.properties"
       org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

7.3.2. 在服务器上配置具有 SCRAM-SHA 数据的用户

使用 SCRAM-SHA,服务器的用户属性文件不包含任何密码,而是包含可用于响应挑战的派生数据。密码的安全的编码形式必须使用 org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule 的主方法从 artemis-server 模块中生成,并将生成的行插入到您的 artemis-users.properties 文件中。

java -cp "<distro-lib-dir>/*" org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule <username> <password> [<iterations>]

可以在 amqp 示例、examples/protocols/amqp/sasl-scram/src/main/resources/activemq/server0/artemis-users.properties 中找到输出示例。

7.4. Kerberos 身份验证

在服务器可以接受 Kerberos 凭据之前,您必须在部署环境中设置 Kerberos 基础设施。服务器可以通过使用 JAAS 和 Kerberos 登录模块来获取其 Kerberos 接收器凭据。JDK 提供了 Krb5LoginModule,它执行必要的 Kerberos 协议步骤来验证并获取 Kerberos 凭据。

7.4.1. GSSAPI SASL 机制

通过 AMQP 使用 SASL,Kerberos 身份验证使用 GSSAPI SASL 机制得到支持。使用 SASL 进行 Kerberos 身份验证时,TLS 可以以通常的方式用于为通信通道提供完整性和机密性。

GSSAPI SASL 机制必须在 broker.xml 中的 AMQP 接收器上启用,方法是将它添加到 saslMechanisms 列表 url 参数中:saslMechanisms="GSSAPI<,PLAIN, etc>

<acceptor name="amqp">tcp://0.0.0.0:5672?protocols=AMQP;saslMechanisms=GSSAPI</acceptor>

服务器上的 GSSAPI 机制实现将使用名为 amqp-sasl-gssapi 的 JAAS 配置范围来获取其 Kerberos 接收器凭据。可以使用 url 参数在 AMQP 接收器上指定另一个配置范围:saslLoginConfigScope=<some other scope>

以下是 login.config 的示例配置范围,它将为 Kerberos 接收器主体 amqp/localhost 获取 Kerberos keyTab。

amqp-sasl-gssapi {
    com.sun.security.auth.module.Krb5LoginModule required
    isInitiator=false
    storeKey=true
    useKeyTab=true
    principal="amqp/localhost"
    debug=true;
};

7.5. 角色映射

在服务器上,Kerberos 或 SCRAM-SHA JAAS 验证的主体必须使用相应的 Apache ActiveMQ Artemis Krb5LoginModuleSCRAMLoginModule 登录模块作为 Apache ActiveMQ Artemis UserPrincipal 添加到主体的主体集中。它们是独立的,以允许转换和角色映射尽可能严格或宽松。

然后,可以使用 PropertiesLoginModuleLDAPLoginModule 将已验证的主体映射到 Apache ActiveMQ Artemis 角色。请注意,在 Kerberos 的情况下,对等主体不存在作为 Apache ActiveMQ Artemis 用户,而仅作为角色成员。

在以下示例中,任何现有的 Kerberos 验证的对等体将转换为 Apache ActiveMQ Artemis 用户主体,并根据需要通过 LDAPLoginModule 应用角色映射。

activemq {
  org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule required
    ;
  org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule optional
    initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
    connectionURL="ldap://127.0.0.1:1024"
    authentication=GSSAPI
    saslLoginConfigScope=broker-sasl-gssapi
    connectionProtocol=s
    userBase="ou=users,dc=example,dc=com"
    userSearchMatching="(krb5PrincipalName={0})"
    userSearchSubtree=true
    authenticateUser=false
    roleBase="ou=system"
    roleName=cn
    roleSearchMatching="(member={0})"
    roleSearchSubtree=false
    ;
};

7.6. 基本安全管理器

顾名思义,ActiveMQBasicSecurityManager基本的。它不像 JAAS 安全管理器那样可插拔,而且它支持通过用户名和密码凭据进行身份验证。此外,基于 Hawtio 的 Web 控制台需要 JAAS。因此,如果您计划使用 Web 控制台,您仍然需要配置 login.config。但是,根据您的用例,此安全管理器可能仍然有一些优势。

所有用户和角色数据都存储在绑定日志(或使用 JDBC 时存储在绑定表中)。这里的优势在于,在主备用例中,对主代理执行的任何用户管理将在故障转移后反映到备用代理上。

通常情况下,LDAP 将用于此类用例,但并非每个人都愿意或能够管理独立的 LDAP 服务器。LDAP 的一个重要好处是,用户数据可以在多个活动代理之间共享。但是,这在 ActiveMQBasicSecurityManager 中是不可能的,实际上,在任何其他可能开箱即用的配置中也是不可能的。但是,如果您只想在单个活动/备用对之间共享用户数据,那么基本安全管理器可能适合您。

用户管理由代理的管理 API 提供。这包括添加、列出、更新和删除用户和角色的功能。与所有管理功能一样,这可以通过 JMX、管理消息、HTTP(通过 Jolokia)、Web 控制台等来实现。这些功能也可以从 ActiveMQ Artemis 命令行界面获得。让代理直接存储此数据意味着它必须正在运行才能管理用户。没有办法手动修改绑定数据。

需要明确的是,通过 HTTP 进行的任何管理访问(例如 Web 控制台或 Jolokia)都将通过 Hawtio JAAS 进行。通过 JConsole 或其他远程 JMX 工具进行的 MBean 访问将通过基本安全管理器进行。管理消息也将通过基本安全管理器进行。

7.6.1. 配置

ActiveMQBasicSecurityManager 的配置与所有安全管理器实现一样,都在 bootstrap.xml 中进行。首先删除 <jaas-security /> 部分,并添加 <security-manager /> 配置,如下所示。

ActiveMQBasicSecurityManager 由于以下原因需要一些特殊的配置。

  • 存储用户和角色数据的绑定数据无法手动修改。

  • 代理必须正在运行才能管理用户。

  • 代理通常需要从第一次启动开始就受到保护。

例如,如果代理配置为使用 ActiveMQBasicSecurityManager 并从头开始启动,那么没有客户端能够连接,因为没有配置任何用户和角色。但是,为了配置用户和角色,需要使用管理 API,这将需要正确的凭据。这是一个 两难 问题。因此,必须配置“引导”凭据,这些凭据将在代理启动时自动创建。有一些属性可以定义以下内容。

  • 单个用户,可以使用其凭据添加其他用户。

  • 要批量加载用户和角色的属性文件。

以下是单个引导用户配置的示例。

<broker xmlns="https://activemq.apache.org/schema">

   <security-manager class-name="org.apache.activemq.artemis.spi.core.security.ActiveMQBasicSecurityManager">
      <property key="bootstrapUser" value="myUser"/>
      <property key="bootstrapPassword" value="myPass"/>
      <property key="bootstrapRole" value="myRole"/>
   </security-manager>

   ...
</broker>
bootstrapUser

引导用户的名称。

bootstrapPassword

引导用户的密码;支持屏蔽。

bootstrapRole

引导用户的角色。

如果您的用例需要在代理启动时多个用户可用,那么您可以使用如下配置。

<broker xmlns="https://activemq.apache.org/schema">

   <security-manager class-name="org.apache.activemq.artemis.spi.core.security.ActiveMQBasicSecurityManager">
      <property key="bootstrapUserFile" value="artemis-users.properties"/>
      <property key="bootstrapRoleFile" value="artemis-roles.properties"/>
   </security-manager>

   ...
</broker>
bootstrapUserFile

要从中加载用户的文件的名称。这是一个属性文件,格式与 PropertiesLoginModule 使用的用户属性文件完全相同。此文件应位于代理的类路径上(例如,在 etc 目录中)。

bootstrapRoleFile

引导用户的角色。这是一个属性文件,格式与 PropertiesLoginModule 使用的角色属性文件完全相同。此文件应位于代理的类路径上(例如,在 etc 目录中)。

无论您是配置单个引导用户还是从属性文件加载多个用户,使用其创建其他用户的任何用户都应位于对 activemq.management 地址具有适当权限的角色中。例如,如果您指定了 bootstrapUser,那么 bootstrapRole 将需要以下权限。

  • createNonDurableQueue

  • createAddress

  • consume

  • manage

  • send

例如

<security-setting match="activemq.management.#">
   <permission type="createNonDurableQueue" roles="myRole"/>
   <permission type="createAddress" roles="myRole"/>
   <permission type="consume" roles="myRole"/>
   <permission type="manage" roles="myRole"/>
   <permission type="send" roles="myRole"/>
</security-setting>

任何 bootstrap 凭据都将在您每次启动代理时重置,无论以前在运行时对它们进行了哪些更改,因此,根据您的用例,您应该决定是否要使 bootstrap 配置永久存在,或者是否要在初始配置后将其删除。

8. 映射外部角色

来自外部身份验证提供者(即 LDAP)的角色可以映射到内部使用的角色。这通过安全设置块中的角色映射条目来完成。

<security-settings>
   [...]
   <role-mapping from="cn=admins,ou=Group,ou=ActiveMQ,ou=system" to="my-admin-role"/>
   <role-mapping from="cn=users,ou=Group,ou=ActiveMQ,ou=system" to="my-user-role"/>
</security-settings>
角色映射是累加的。这意味着用户将保留原始角色以及新分配的角色。
此角色映射仅影响用于通过配置的接收器授权队列访问的那些角色。它不能用于映射访问 Web 控制台所需的那些角色。

9. SASL

AMQP 支持 SASL。支持以下机制:PLAIN、EXTERNAL、ANONYMOUS、GSSAPI、SCRAM-SHA-256、SCRAM-SHA-512。发布的列表可以通过 amqp 接受器 saslMechanisms 属性进行限制。

只有在从 TLS 客户端证书获得主体时才会选择 EXTERNAL。

10. 更改用于集群的用户名/密码

为了使集群连接正常工作,集群中的每个节点都必须与其他节点建立连接。它们用于此目的的用户名/密码应始终从安装默认值更改,以防止安全风险。

有关如何执行此操作的说明,请参阅 管理

11. 保护控制台

Artemis 附带一个 Web 控制台,允许用户通过嵌入式服务器浏览 Artemis 文档。默认情况下,Web 访问是纯 HTTP。它在 bootstrap.xml 中配置。

<web path="web">
    <binding uri="https://127.0.0.1:8161">
        <app url="console" war="console.war"/>
    </binding>
</web>

或者,您可以编辑上述配置以使用 HTTPS 协议启用安全访问。例如:

<web path="web">
    <binding uri="https://127.0.0.1:8443"
             keyStorePath="${artemis.instance}/etc/keystore.jks"
             keyStorePassword="password">
        <app url="jolokia" war="jolokia-war-1.3.5.war"/>
    </binding>
</web>

如示例所示,要启用 https,首先要做的是将 bind 配置为 https url。此外,您将需要配置一些额外的属性,如下所述。

keyStorePath

密钥库文件的路径。

keyStorePassword

密钥库的密码。

clientAuth

布尔标志指示是否需要客户端身份验证。默认值为 false

trustStorePath

信任库文件的路径。这仅在 clientAuthtrue 时需要。

trustStorePassword

信任库的密码。

11.1. 使用客户端证书配置访问

Web 控制台支持使用客户端证书进行身份验证,请参阅以下步骤

  • 证书登录模块 添加到 login.config 文件中,即

    activemq-cert {
     org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule required
         debug=true
         org.apache.activemq.jaas.textfiledn.user="cert-users.properties"
         org.apache.activemq.jaas.textfiledn.role="cert-roles.properties";
    };
  • 更改 hawtio 领域以匹配 证书登录模块login.config 文件中定义的领域。这在 artemis.profile 中通过系统属性 -Dhawtio.role=activemq-cert 配置。

  • 为客户端创建密钥对并将公钥导入信任库文件。

    keytool -storetype pkcs12 -keystore client-keystore.p12 -storepass securepass -keypass securepass -alias client -genkey -keyalg "RSA" -keysize 2048 -dname "CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -ext bc=ca:false -ext eku=cA
    keytool -storetype pkcs12 -keystore client-keystore.p12 -storepass securepass -alias client -exportcert -rfc > client.crt
    keytool -storetype pkcs12 -keystore client-truststore.p12 -storepass securepass -keypass securepass -importcert -alias client-ca -file client.crt -noprompt
  • 使用客户端身份验证启用 HTTPS 协议的安全访问,使用在上一步中创建的信任库文件来设置 trustStorePathtrustStorePassword

    <web path="web">
       <binding uri="https://127.0.0.1:8443"
                keyStorePath="${artemis.instance}/etc/server-keystore.p12"
                keyStorePassword="password"
                clientAuth="true"
                trustStorePath="${artemis.instance}/etc/client-truststore.p12"
                trustStorePassword="password">
          <app url="jolokia" war="jolokia-war-1.3.5.war"></app>
       </binding>
    </web>
  • 使用在上一步中创建的私钥来设置您的客户端,即,如果客户端应用程序是浏览器,请在浏览器中安装私钥。

12. 控制 JMS ObjectMessage 反序列化

Artemis 提供了一种简单的类过滤机制,用户可以使用它来指定哪些包是可信的,哪些包不可信。来自可信包的类的对象可以毫无问题地反序列化,而来自“不可信”包的类的对象将被拒绝反序列化。

Artemis 保持一个 拒绝列表 来跟踪不可信的包,并保持一个 允许列表 来跟踪可信的包。默认情况下,这两个列表都是空的,这意味着任何可序列化对象都可以反序列化。如果对象的类与拒绝列表中的某个包匹配,则不允许反序列化。如果它与允许列表中的某个包匹配,则可以反序列化对象。如果一个包同时出现在拒绝列表和允许列表中,则拒绝列表中的包优先。如果一个类既不与 拒绝列表 匹配也不与 允许列表 匹配,则该类反序列化将被拒绝,除非允许列表为空(这意味着用户根本没有指定允许列表)。

如果一个类被认为是“匹配”,则

  • 它的完整名称与列表中的一个条目完全匹配。

  • 它的包与列表中的一个条目匹配,或者是一个条目的子包。

例如,如果一个类的完整名称是“org.apache.pkg1.Class1”,则一些匹配的条目可能是

  • org.apache.pkg1.Class1 - 精确匹配。

  • org.apache.pkg1 - 精确包匹配。

  • org.apache — 子包匹配。

一个 * 在拒绝或允许列表中表示“全部匹配”。

12.1. 通过连接工厂配置

要指定 允许拒绝 列表,可以使用 URL 参数 deserializationDenyListdeserializationAllowList。例如,使用 JMS

ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://0?deserializationDenyList=org.apache.pkg1,org.some.pkg2");

以上语句创建了一个工厂,该工厂有一个拒绝列表,包含两个禁止的包,“org.apache.pkg1”和“org.some.pkg2”,用逗号分隔。

12.2. 通过系统属性配置

有两个系统属性可用于指定拒绝列表和允许列表

org.apache.activemq.artemis.jms.deserialization.allowlist

允许列表条目的逗号分隔列表。

org.apache.activemq.artemis.jms.deserialization.denylist

拒绝列表条目的逗号分隔列表。

定义后,VM 中所有 JMS 对象消息的反序列化都将根据这两个列表进行检查。但是,如果您创建了一个 ConnectionFactory 并为其设置了一组新的拒绝/允许列表,则新值将覆盖系统属性。

12.3. 资源适配器的配置

使用 JMS 资源适配器接收消息的消息 Bean 也可以通过正确配置其资源适配器的相关属性来控制其对象反序列化。您可以使用资源适配器中的连接工厂配置两个属性

deserializationDenyList

拒绝列表的逗号分隔值

deserializationAllowList

允许列表的逗号分隔值

一旦指定,这些属性最终会设置在相应的内部工厂上。

13. 掩盖密码

有关在 broker.xml 中掩盖密码的详细信息,请参阅 掩盖密码 章节。

14. 自定义安全管理器

如果需要,可以更改代理的安全实现的基础。代理使用一个名为“安全管理器”的组件来实现实际的身份验证和授权检查。默认情况下,代理使用 org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager 来提供 JAAS 集成,但用户可以提供他们自己的 org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5 实现,并在 bootstrap.xml 中使用 security-manager 元素进行配置,例如:

<broker xmlns="https://activemq.apache.org/schema">

   <security-manager class-name="com.foo.MySecurityManager">
      <property key="myKey1" value="myValue1"/>
      <property key="myKey2" value="myValue2"/>
   </security-manager>

   ...
</broker>

security-manager 示例 更详细地演示了如何执行此操作。

15. 每接受器安全域

可以通过在单个 acceptor 上指定安全域来覆盖代理的 JAAS 安全域。只需使用 securityDomain 参数并指示要使用的 login.config 中的哪个域,例如:

<acceptor name="myAcceptor">tcp://127.0.0.1:61616?securityDomain=mySecurityDomain</acceptor>

连接到此接受器的任何客户端都将使用 mySecurityDomain 执行安全。