引言
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&wireFormat.maxFrameSize=104857600&needClientAuth=true&transport.enabledProtocols=TLSv1.2&keystore=file:${activemq.base}/server.keystore&keystore.password=serverkeystorepassword&truststore=file:${activemq.base}/server.keystore&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.yml或application.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相关参数。