默认情况下,Apache ActiveMQ Artemis 服务器配置文件中的所有密码都以明文形式存在。这通常不会造成安全问题,因为这些文件应该受到很好的保护,防止未经授权的访问。但是,在某些情况下,用户不希望将其密码暴露给不必要的人员。

Apache ActiveMQ Artemis 可以配置为在其配置文件中使用“掩码”密码。掩码密码是真实密码的模糊字符串表示。为了掩码密码,用户将使用“编解码器”。编解码器接收真实密码并输出掩码版本。然后,用户可以用新的掩码密码替换配置文件中的真实密码。当 Apache ActiveMQ Artemis 加载掩码密码时,它使用编解码器将其解码回真实密码。

Apache ActiveMQ Artemis 提供了一个默认编解码器。用户可以选择使用或实现自己的编解码器来掩码密码。

一般来说,可以使用两种方法之一来识别掩码密码。第一种是ENC()语法,即任何包含在ENC()中的字符串值都将被视为掩码密码。例如

ENC(xyz)

以上表示密码已掩码,掩码值为xyz

ENC()语法是掩码密码的**首选方法**,并且在 Artemis 的每个密码配置中都得到普遍支持。

另一种传统方法是使用mask-password属性来指示配置文件中的密码应被视为“掩码”。例如

<mask-password>true</mask-password>
<cluster-password>xyz</cluster-password>

这种方法现在已**弃用**,仅为了保持向后兼容性而存在。较新的配置可能不支持它。

1. 生成掩码密码

要掩码密码,请使用 Artemis *实例* 的bin目录中的mask命令。此命令不会从 Artemis 主目录工作。

默认情况下,mask命令使用默认编解码器的传统双向算法,除非在broker.xml中定义了自定义编解码器,并且--password-codec选项为true。传统的双向算法现在已**弃用**,仅为了保持向后兼容性而存在,请改用自定义编解码器。以下是一个简单的示例

./artemis mask <plaintextPassword>

您将得到类似以下内容

result: 32c6f67dae6cd61b0a7ad1702033aa81e6b2a760123f4360

只需复制32c6f67dae6cd61b0a7ad1702033aa81e6b2a760123f4360,并使用ENC()语法用它替换您的明文密码,例如ENC(32c6f67dae6cd61b0a7ad1702033aa81e6b2a760123f4360)

您还可以将--key参数与默认编解码器一起使用。阅读有关默认编解码器的更多信息,以了解有关此参数的更多详细信息。

此过程适用于以下密码

  • broker.xml

  • login.config

  • bootstrap.xml

  • management.xml

此过程**不**适用于以下密码

  • artemis-users.properties

可以使用mask命令使用--hash命令行选项为artemis-users.properties生成掩码密码。但是,也可以使用下面描述的user命令提供的工具集来完成此操作。

2. 掩码配置

除了支持ENC()语法之外,服务器配置文件(即 broker.xml)还具有一个属性,该属性定义了整个文件范围内的默认掩码行为。

mask-password:此布尔类型属性指示是否应掩码密码。如果要掩码密码,请将其设置为true。默认值为false。如上所述,此配置参数已被ENC()语法弃用。

password-codec:此字符串类型属性标识将用于在代理中解码掩码密码的类的名称。如果未指定,则将使用默认的org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec。阅读有关使用自定义编解码器的更多信息。

2.1. artemis-users.properties

Apache ActiveMQ Artemis 的默认 JAAS 安全管理器使用纯属性文件,其中用户密码默认情况下以散列形式指定。注意,在这种情况下,密码实际上是散列而不是掩码。默认的PropertiesLoginModule不会解码artemis-users.properties中的密码,而是会散列输入并比较两个散列值以进行密码验证。

从要添加用户/密码的 Artemis *实例* 的 CLI 使用以下命令。此命令不会从用于创建实例的 Artemis 主目录工作,并且只有在代理启动后才会生效。例如

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

这将使用默认编解码器对密码执行单向散列,并使用指定的参数更改artemis-users.propertiesartemis-roles.properties文件。

artemis-users.properties中的密码会通过查找ENC(<hash>)语法自动检测为散列或非散列。mask-password参数不需要为true才能在此处使用散列密码。

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

一般来说,除了非常基本的用例之外,不建议使用属性文件和代理中心的用户信息管理。代理旨在处理消息。它不负责管理用户,尽管为了方便起见提供了有限级别的功能。建议在企业级生产用例中使用 LDAP。

2.2. cluster-password

如果在ENC()语法中指定,它将被视为掩码,或者如果mask-passwordtrue,则cluster-password将被视为掩码。

2.3. 连接器和接受器

在 broker.xml 中,connectoracceptor配置有时需要指定密码。例如,如果用户要使用sslEnabled=trueacceptor,则可以指定keyStorePasswordtrustStorePassword。由于接受器和连接器是可插入的实现,因此每种传输将具有不同的密码掩码需求。

首选方法是简单地使用ENC()语法。

如果使用传统的mask-passwordpassword-codec值,则当初始化connectoracceptor时,Apache ActiveMQ Artemis 将使用键activemq.usemaskedpasswordactivemq.passwordcodec分别将这些值添加到参数中。Netty 和 InVM 实现将根据需要使用这些值,而任何其他实现都可以访问这些值以供需要时使用。

2.4. 核心桥接

核心桥接在服务器配置文件中配置,因此其password属性的掩码遵循与cluster-password相同的规则。它支持ENC()语法。

对于使用mask-password属性,下表总结了上述属性之间的关系

mask-password cluster-password 接受器/连接器密码 桥接密码

不存在

纯文本

纯文本

纯文本

false

纯文本

纯文本

纯文本

true

掩码

掩码

掩码

建议您在新的应用程序/部署中使用ENC()语法。

2.4.1. 示例

在以下示例中,如果相关属性或属性不存在,则意味着它们未在配置文件中指定。
  • 未掩码

    <cluster-password>bbc</cluster-password>

    这表示集群密码是纯文本值bbc

  • 掩码 1

    <cluster-password>ENC(80cf731af62c290)</cluster-password>

    这表示集群密码是掩码值80cf731af62c290

  • 掩码 2

    <mask-password>true</mask-password>
    <cluster-password>80cf731af62c290</cluster-password>

    这表示集群密码是掩码值,Apache ActiveMQ Artemis 将使用默认编解码器来解码它。配置文件、连接器、接受器和桥接中的所有其他密码也将使用掩码密码。

2.5. bootstrap.xml

代理嵌入一个 Web 服务器,用于托管某些 Web 应用程序,例如管理控制台。它在bootstrap.xml中作为 Web 组件配置。可以使用https协议来保护 Web 服务器,并且可以使用密钥库密码和/或信任库密码来配置它,这些密码默认情况下以明文形式指定。

要掩码这些密码,您需要使用ENC()语法。这里不支持mask-password布尔值。

您还可以设置passwordCodec属性,如果您要使用除默认编解码器之外的其他密码编解码器。例如

<web path="web">
    <binding uri="https://127.0.0.1:8443"
             keyStorePassword="ENC(-5a2376c61c668aaf)"
             trustStorePassword="ENC(3d617352d12839eb71208edf41d66b34)">
        <app url="activemq-branding" war="activemq-branding.war"/>
    </binding>
</web>

2.6. management.xml

代理嵌入一个 JMX 连接器,用于管理。可以使用 SSL 来保护连接器,并且可以使用密钥库密码和/或信任库密码来配置它,这些密码默认情况下以明文形式指定。

要掩码这些密码,您需要使用ENC()语法。这里不支持mask-password布尔值。

您还可以设置password-codec属性,如果您要使用除默认编解码器之外的其他密码编解码器。例如

<connector
      connector-port="1099"
      connector-host="localhost"
      secured="true"
      key-store-path="myKeystore.jks"
      key-store-password="ENC(3a34fd21b82bf2a822fa49a8d8fa115d"
      trust-store-path="myTruststore.jks"
      trust-store-password="ENC(3a34fd21b82bf2a822fa49a8d8fa115d)"/>

使用此配置,ra.xml 中的所有密码及其所有 MDB 都必须以掩码形式存在。

2.7. PropertiesLoginModule

Artemis 支持在 JAAS 配置文件(默认名称为login.config)中配置 Properties 登录模块。默认情况下,用户的密码以明文形式存在,或者使用默认编解码器进行掩码。

要使用自定义编解码器类,请将org.apache.activemq.jaas.properties.password.codec属性设置为类名,例如,要使用com.example.MySensitiveDataCodecImpl编解码器类

PropertiesLoginWithPasswordCodec {
    org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule required
        debug=true
        org.apache.activemq.jaas.properties.user="users.properties"
        org.apache.activemq.jaas.properties.role="roles.properties"
        org.apache.activemq.jaas.properties.password.codec="com.example.MySensitiveDataCodecImpl";
};

2.8. LDAPLoginModule

Artemis 支持在 JAAS 配置文件(默认名称为login.config)中配置 LDAP 登录模块。连接到 LDAP 服务器时,通常需要在配置文件中提供连接密码。默认情况下,此密码以明文形式存在。

要掩码它,您需要使用ENC()语法在登录模块中配置密码。要使用以下属性指定编解码器

passwordCodec - 密码编解码器类名。(如果不存在,将使用默认编解码器

例如

LDAPLoginExternalPasswordCodec {
    org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
        debug=true
        initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
        connectionURL="ldap://127.0.0.1:1024"
        connectionUsername="uid=admin,ou=system"
        connectionPassword="ENC(-170b9ef34d79ed12)"
        passwordCodec="org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;key=helloworld"
        connectionProtocol=s
        authentication=simple
        userBase="ou=system"
        userSearchMatching="(uid={0})"
        userSearchSubtree=false
        roleBase="ou=system"
        roleName=dummyRoleName
        roleSearchMatching="(uid={1})"
        roleSearchSubtree=false
        ;
};

2.9. JCA 资源适配器

ra.xml 和 MDB 激活配置都具有一个password属性,可以使用ENC()语法对其进行掩码,这是一种首选方法。

或者,它可以使用 ra.xml 中的一个可选属性来指示密码已掩码

UseMaskedPassword

如果设置为“true”,则密码已掩码。默认值为false

ra.xml中还有一个属性可以指定编解码器

PasswordCodec

用于解码遮罩密码的编解码器的类名及其参数。如果UseMaskedPasswordfalse,则忽略此属性。此属性的格式是可选地后跟键/值对的完整限定类名。它与 JMS 桥梁的格式相同。示例

示例 1 使用ENC() 语法

<config-property>
  <config-property-name>password</config-property-name>
  <config-property-type>String</config-property-type>
  <config-property-value>ENC(80cf731af62c290)</config-property-value>
</config-property>
<config-property>
  <config-property-name>PasswordCodec</config-property-name>
  <config-property-type>java.lang.String</config-property-type>
  <config-property-value>com.foo.ACodec;key=helloworld</config-property-value>
</config-property>

示例 2 使用 "UseMaskedPassword" 属性

<config-property>
  <config-property-name>UseMaskedPassword</config-property-name>
  <config-property-type>boolean</config-property-type>
  <config-property-value>true</config-property-value>
</config-property>
<config-property>
  <config-property-name>password</config-property-name>
  <config-property-type>String</config-property-type>
  <config-property-value>80cf731af62c290</config-property-value>
</config-property>
<config-property>
  <config-property-name>PasswordCodec</config-property-name>
  <config-property-type>java.lang.String</config-property-type>
  <config-property-value>com.foo.ACodec;key=helloworld</config-property-value>
</config-property>

3. 选择密码掩码的编解码器

如前几节所述,所有密码掩码都需要一个编解码器。编解码器使用一种算法将掩码密码转换为其原始明文形式,以便在各种安全操作中使用。用于解码的算法必须与用于编码的算法匹配。否则,解码可能无法成功。

为了方便用户,Apache ActiveMQ Artemis 提供了一个默认编解码器。但是,如果用户愿意,他们可以实现自己的编解码器。

3.1. 默认编解码器

如果配置中未指定编解码器,则使用默认编解码器。默认编解码器的类名为org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec。它提供 2 种算法:one-waytwo-wayone-way 算法可以对字符串进行哈希运算,是 PropertiesLoginModule 使用的默认算法。two-way 算法可以使用key 对字符串进行编码/解码。two-way 算法在org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec 中有一个默认密钥,但使用默认密钥会让恶意行为者可以使用该密钥来取消掩码密码。它现在已弃用,仅为保持向后兼容性而存在,请改为使用 自定义编解码器。此处使用的key 非常重要,因为在掩码和取消掩码密码时必须使用相同的密钥。它只是编解码器提供给底层算法的一串字符。有几种方法可以提供您自己的密钥

  1. 使用key=value 语法在编解码器配置中指定密钥。具体配置会根据您尝试掩码的密码略有不同,但例如,可以在broker.xml 中使用<password-codec> 完成此操作

    <password-codec>org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;key=myKey</password-codec>

    支持密码掩码的任何文件中都可能存在类似的配置,例如boostrap.xmllogin.configmanagement.xml 等。这种方法的主要缺点是密钥将以明文形式存储在配置文件中。

  2. 设置系统属性 -Dartemis.default.sensitive.string.codec.key=myKey。

  3. 设置环境属性ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY。使用这种方法的优点是,密钥更难找到,因为它不会存在于任何配置文件中。可以在代理启动之前立即设置它,然后在代理完成启动之后立即从环境中清除它。

3.2. 使用自定义编解码器

可以使用自定义编解码器,而不是内置编解码器。只需确保编解码器位于 Apache ActiveMQ Artemis 的类路径中即可。如果编解码器的服务提供程序安装在类路径中,则自定义编解码器也可以通过服务加载,而不是通过类加载。然后,将服务器配置为使用它,如下所示

<password-codec>com.foo.SomeCodec;key1=value1;key2=value2</password-codec>

如果您的编解码器需要向其传递参数,则可以在配置时通过键/值对进行操作。例如,如果您的编解码器需要一个 "key-location" 参数,则可以这样定义

<password-codec>com.foo.NewCodec;key-location=/some/url/to/keyfile</password-codec>

然后,将您的群集密码配置为如下所示

<cluster-password>ENC(masked_password)</cluster-password>

当 Apache ActiveMQ Artemis 读取群集密码时,它将初始化NewCodec 并使用它来解码 "mask_password"。它还使用新定义的编解码器处理所有密码。

3.2.1. 实现自定义编解码器

若要使用与内置编解码器不同的编解码器,您可以从现有库中选择一个或自己实现它。所有编解码器必须实现org.apache.activemq.artemis.utils.SensitiveDataCodec<String> 接口。因此,新编解码器的定义方式如下

public class MyCodec implements SensitiveDataCodec<String> {
   @Override
   public String decode(Object mask) throws Exception {
      // Decode the mask into clear text password.
      return "the password";
   }

   @Override
   public String encode(Object secret) throws Exception {
      // Mask the clear text password.
      return "the masked password";
   }

   @Override
   public void init(Map<String, String> params) {
      // Initialization done here. It is called right after the codec has been created.
   }

   @Override
   public boolean verify(char[] value, String encodedValue) {
      // Return true if the value matches the encodedValue.
      return checkValueMatchesEncoding(value, encodedValue);
   }
}

最后但并非最不重要的一点是,获得自己的编解码器后,请 将其添加到类路径中,否则代理将无法加载它!