如何在JMX应用中配置SSL证书连接ActiveMQ Artemis?
配置JMX连接ActiveMQ Artemis的SSL证书
问题背景
已完成ActiveMQ Artemis broker端的SSL配置,现有JMX连接代码未启用SSL,需修改代码引入密钥库以建立SSL连接。
Broker端SSL配置(broker.xml)
<acceptor name="main-connector">tcp://localhost:61617?tcpSendBufferSize=1048576;amqpMinLargeMessageSize=102400;tcpReceiveBufferSize=1048576;sslEnabled=true;keyStorePath=keystore_server.jks;trustStorePath=truststore_server.jks;keyStorePassword=qwerty;trustStorePassword=qwerty;needClientAuth=true;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;enabledCipherSuites=TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA;enabledProtocols=TLSv1.3,TLSv1.2</acceptor>
Broker文件夹结构

当前未启用SSL的JMX连接代码
public static MBeanServerConnection connectBroker(String brokerUrl, String login, String password) { MBeanServerConnection mBeanServerConnection = null; try { Map<String, String[]> env = new HashMap(); String[] creds = {login, password}; env.put(JMXConnector.CREDENTIALS, creds); JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + brokerUrl + "/jmxrmi"), env); mBeanServerConnection = connector.getMBeanServerConnection(); DialogsAlert.brokerJmxRmiConnectionSuccess.showAndWait(); LOGGER.log(Level.INFO,"success" + brokerUrl); } catch (Exception e) { LOGGER.log(Level.WARNING,"fail", e); } return mBeanServerConnection; }
解决方案
由于你的broker配置了needClientAuth=true,客户端必须提供合法证书才能建立SSL连接,以下是两种可行的配置方式:
方式一:系统属性快速配置
直接在代码中设置JVM系统属性,指定客户端密钥库、信任库及密码,操作简单:
public static MBeanServerConnection connectBroker(String brokerUrl, String login, String password) { MBeanServerConnection mBeanServerConnection = null; try { // 配置SSL核心属性 System.setProperty("javax.net.ssl.keyStore", "path/to/client_keystore.jks"); // 客户端密钥库路径 System.setProperty("javax.net.ssl.keyStorePassword", "qwerty"); // 客户端密钥库密码 System.setProperty("javax.net.ssl.trustStore", "path/to/client_truststore.jks"); // 客户端信任库路径,需包含broker证书 System.setProperty("javax.net.ssl.trustStorePassword", "qwerty"); // 客户端信任库密码 // 可选:指定SSL协议,匹配broker的enabledProtocols配置 System.setProperty("jdk.tls.client.protocols", "TLSv1.3,TLSv1.2"); Map<String, Object> env = new HashMap<>(); String[] creds = {login, password}; env.put(JMXConnector.CREDENTIALS, creds); // 启用JMX SSL env.put("jmx.remote.ssl.enabled", "true"); JMXConnector connector = JMXConnectorFactory.connect( new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + brokerUrl + "/jmxrmi"), env); mBeanServerConnection = connector.getMBeanServerConnection(); DialogsAlert.brokerJmxRmiConnectionSuccess.showAndWait(); LOGGER.log(Level.INFO,"success" + brokerUrl); } catch (Exception e) { LOGGER.log(Level.WARNING,"fail", e); } return mBeanServerConnection; }
注意:客户端密钥库需包含被broker信任库(truststore_server.jks)认可的客户端证书;客户端信任库需包含broker的证书(可从broker的keystore_server.jks导出后导入)。
方式二:自定义SSLContext(灵活可控)
如果需要精细控制SSL配置,可手动创建SSLContext并注入到JMX连接环境:
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.security.KeyStore; public static MBeanServerConnection connectBroker(String brokerUrl, String login, String password) { MBeanServerConnection mBeanServerConnection = null; try { // 加载客户端密钥库 KeyStore keyStore = KeyStore.getInstance("JKS"); try (FileInputStream keyStoreStream = new FileInputStream("path/to/client_keystore.jks")) { keyStore.load(keyStoreStream, "qwerty".toCharArray()); } KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "qwerty".toCharArray()); // 加载客户端信任库 KeyStore trustStore = KeyStore.getInstance("JKS"); try (FileInputStream trustStoreStream = new FileInputStream("path/to/client_truststore.jks")) { trustStore.load(trustStoreStream, "qwerty".toCharArray()); } TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); // 创建匹配broker协议的SSLContext SSLContext sslContext = SSLContext.getInstance("TLSv1.3"); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); Map<String, Object> env = new HashMap<>(); String[] creds = {login, password}; env.put(JMXConnector.CREDENTIALS, creds); env.put("jmx.remote.ssl.enabled", "true"); env.put("jmx.remote.ssl.context", sslContext); // 指定RMI SSL协议提供者 env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "com.sun.jmx.remote.protocol"); JMXConnector connector = JMXConnectorFactory.connect( new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + brokerUrl + "/jmxrmi"), env); mBeanServerConnection = connector.getMBeanServerConnection(); DialogsAlert.brokerJmxRmiConnectionSuccess.showAndWait(); LOGGER.log(Level.INFO,"success" + brokerUrl); } catch (Exception e) { LOGGER.log(Level.WARNING,"fail", e); } return mBeanServerConnection; }
关键注意事项
- 客户端密钥库必须包含客户端证书,且该证书已被broker的
truststore_server.jks信任(可通过将客户端证书导入broker信任库实现)。 - 客户端信任库必须包含broker的证书(可从broker的
keystore_server.jks导出证书后导入客户端信任库)。 - 确保客户端配置的SSL协议、加密套件与broker的
enabledProtocols、enabledCipherSuites一致,避免握手失败。
内容的提问来源于stack exchange,提问作者user21871375
相关产品推荐
相关产品推荐

