ActiveMQ权限认证与用户管理指南

587 阅读5分钟

引言

Apache ActiveMQ作为一款开源的消息中间件,支持多种消息传递模式,如点对点和发布/订阅模式。为了确保系统的安全性,ActiveMQ提供了权限认证机制,允许管理员控制谁可以访问消息系统以及他们可以执行的操作类型。

1. 安全认证基础

ActiveMQ默认不开启用户认证,任何知道Broker地址的客户端都可以无凭据访问。为了增强安全性,可以启用基于用户名和密码的认证。

2. 开启用户认证

要启用认证,需要修改ActiveMQ的配置文件conf/activemq.xml,在broker元素内添加安全配置。示例如下:

<!--activemq.xml-->
<broker ...>
  ...
  <plugins>
        <jaasAuthenticationPlugin configuration="activemq-domain" /> 
        <authorizationPlugin>
            <map>
                <authorizationMap>
                     <authorizationEntries>
                         <!-- Topic的权限配置 -->
                         <authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
                         <authorizationEntry topic=">" read="consumers" write="admins" admin="admins" />
                     </authorizationEntries>
                 </authorizationMap>
            </map>
         </authorizationPlugin>
    </plugins>
  ...
</broker>

activemq.xml配置启用JAAS安全认证并指定了activemq-domain模块。

authorizationEntry配置:

  • 所有主题(topic)的写和读权限仅限于“admins”组成员。
  • 所有主题(topic)的读权限对“consumers”组开放,写权限仅限于“admins”。
admin=admin123
yhy=123456
admins=admin
consumers=yhy

user.properties 内创建了2个用户。group.properties 内创建了2个用户组,并指定用户组内的用户。

activemq-domain {
    org.apache.activemq.jaas.PropertiesLoginModule required
        org.apache.activemq.jaas.properties.user="users.properties"
        org.apache.activemq.jaas.properties.group="groups.properties";
};

login.cofig内指定activemq-domain模块的用户和用户组配置文件。

3. 使用外部凭证存储

除了在activemq.xml中硬编码用户凭证,还可以选择将用户名和密码存储在外部文件,如credentials.properties或加密的credentials-enc.properties,以提高安全性。

4. 客户端配置

在客户端应用中,使用ActiveMQ连接工厂时,需要提供正确的用户名和密码,例如在Java客户端中:

ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
factory.setUserName("admin");
factory.setPassword("password");
Connection connection = factory.createConnection();

5. 双向认证(SSL/TLS)

在ActiveMQ服务器端配置SSL双向认证,你需要创建一个密钥库(keystore)用于存储服务端的私钥和公钥证书,以及一个信任库(truststore)用于存储你信任的客户端证书。以下是通过Java的keytool工具生成密钥库和信任库的基本步骤:

生成服务端密钥库(keystore)

首先,你需要为服务端生成一个密钥库。这将包含服务端的私钥和自签名的公钥证书(或由CA签发的证书)。

keytool -genkey -alias serverkey -keyalg RSA -keysize 2048 -keystore server.keystore -dname "CN=your.server.com, OU=IT, O=YourCompany, L=YourCity, ST=YourState, C=YourCountry" -validity 3650 -keypass serverkeypassword -storepass serverkeystorepassword
  • -alias 指定密钥的别名,例如 serverkey
  • -keyalg RSA 使用RSA算法生成密钥对。
  • -keysize 2048 密钥长度,推荐至少2048位。
  • -keystore server.keystore 指定生成的密钥库存储文件名。
  • -dname 提供X.500 Distinguished Name,用于证书的主体信息。
  • -validity 3650 证书有效期,这里设置为10年。
  • -keypass-storepass 分别指定密钥的密码和密钥库的密码。
从服务端密钥库导出公钥证书

接下来,你需要从服务端密钥库中导出公钥证书,以便客户端将其导入到他们的信任库中。

keytool -export -alias serverkey -file server.crt -keystore server.keystore -storepass serverkeystorepassword
  • -alias 与之前创建密钥时相同。
  • -file server.crt 指定导出的证书文件名。
  • -keystore-storepass 与之前创建密钥库时相同。
创建客户端信任库(truststore)

客户端需要信任服务端的证书,因此你需要将服务端的公钥证书导入到客户端的信任库中。

keytool -import -alias servertrust -file server.crt -keystore client.truststore -storepass clienttruststorepassword
  • -alias 指定导入证书到信任库中的别名。
  • -file 是之前导出的服务器证书。
  • -keystore client.truststore 客户端信任库的文件名。
  • -storepass 指定客户端信任库的密码。
配置ActiveMQ以使用SSL

最后,在ActiveMQ的conf/activemq.xml配置文件中,添加SSL传输连接器的配置。以下是一个示例配置:

<transportConnectors>
  <transportConnector name="ssl" uri="ssl://0.0.0.0:61617?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600&amp;needClientAuth=true&amp;transport.enabledProtocols=TLSv1.2&amp;keystore=file:${activemq.base}/server.keystore&amp;keystore.password=serverkeystorepassword&amp;truststore=file:${activemq.base}/server.keystore&amp;truststore.password=serverkeystorepassword"/>
</transportConnectors>

确保替换uri中的IP地址和端口号,以及keystore和truststore的路径及密码与你之前创建的一致。如果需要双向认证,确保设置needClientAuth=true。

完成上述步骤后,重启ActiveMQ服务,它将开始监听SSL连接,并要求客户端提供证书进行双向认证。同时,确保客户端也正确配置了信任库和密钥库(如果是双向认证的话)。

6.在SpringBoot中实现ActiveMQ的SSL连接

在Spring Boot应用中实现ActiveMQ的SSL双向认证,主要涉及配置ActiveMQ的工厂Bean以使用SSL连接,并确保客户端也具备相应的SSL配置。以下是一个简化的步骤和示例代码,用于指导如何在Spring Boot应用中实现这一功能:

准备SSL密钥和信任材料

确保你已经为服务端和客户端分别准备了密钥库(keystore)和信任库(truststore)。服务端需要客户端的证书来验证客户端身份,客户端则需要服务端的证书来建立信任连接。

配置Spring Boot应用

在Spring Boot的配置文件(如application.ymlapplication.properties)中,添加ActiveMQ和SSL相关的配置:

spring:
  activemq:
    broker-url: ssl://your-broker-host:61616
    user: yourUsername
    password: yourPassword
    pooled: true
    trust-store: classpath:client-truststore.jks
    trust-store-password: yourTruststorePassword
    key-store: classpath:client-keystore.jks
    key-store-password: yourKeystorePassword
    key-password: yourKeyPassword
    protocol: TLSv1.2
    use-ssl: true
    require-ssl-client-auth: true
配置ActiveMQConnectionFactory Bean

在Spring Boot应用中,你可能需要自定义一个ActiveMQConnectionFactory Bean来覆盖默认的SSL设置。虽然Spring Boot自动配置通常足够处理大部分情况,但在某些特定需求下,手动配置可以提供更细粒度的控制。以下是一个示例,展示了如何手动配置ActiveMQConnectionFactory:

@Configuration
public class ActiveMQConfig {

    @Value("${spring.activemq.broker-url}")
    private String brokerUrl;

    @Value("${spring.activemq.user}")
    private String username;

    @Value("${spring.activemq.password}")
    private String password;

    @Value("${spring.activemq.trust-store}")
    private Resource trustStore;

    @Value("${spring.activemq.trust-store-password}")
    private String trustStorePassword;

    @Value("${spring.activemq.key-store}")
    private Resource keyStore;

    @Value("${spring.activemq.key-store-password}")
    private String keyStorePassword;

    @Value("${spring.activemq.key-password}")
    private String keyPassword;

    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory() throws Exception {
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
        factory.setBrokerURL(brokerUrl);
        factory.setUserName(username);
        factory.setPassword(password);

        factory.setTrustStore(trustStore.getFile());
        factory.setTrustStorePassword(trustStorePassword);
        factory.setKeyStore(keyStore.getFile());
        factory.setKeyStorePassword(keyStorePassword);
        factory.setKeyPassword(keyPassword);

        // 设置SSL上下文以支持TLSv1.2和双向认证
        factory.setSSLContext(createSSLContext());
        factory.setTrustAllPackages(true); // 根据实际情况决定是否信任所有包

        return factory;
    }

    private SSLContext createSSLContext() throws Exception {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(this.trustStore.getInputStream(), trustStorePassword.toCharArray());

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(this.keyStore.getInputStream(), keyStorePassword.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, keyPassword.toCharArray());

        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        return sslContext;
    }
}

请确保你的信任库和密钥库文件已经放置在项目的类路径(classpath)下,并且配置的密码与实际密钥库文件相符。

注意事项
  • 确保服务端ActiveMQ配置允许SSL连接,并且已配置好对应的密钥库和信任库。
  • 检查所有SSL相关配置的路径和密码正确无误。
  • 考虑到安全性,不要在生产环境中硬编码敏感信息,考虑使用环境变量或安全的配置服务来管理这些值。
  • 根据需要调整SSLContext的协议版本和其他SSL相关参数。