Spring Boot2.7.4+Java11连接RabbitMQ SSL报Connection reset错误
Spring Boot 2.7.4 + Java 11 连接 RabbitMQ SSL 报错:Connection reset by peer: socket write error
环境与配置信息
应用配置
配置文件(rabbit.properties):
# RabbitMQ Server configuration file. rabbit.username=admin rabbit.password=admin rabbit.host=localhost rabbit.port=5671 rabbit.ssl=TLSv1.2 rabbit.keystore.name=client_key.p12 rabbit.keystore.password=rabbitstore rabbit.truststore=server_store.jks rabbit.truststore.password=rabbitstore
client_key.p12 和 server_store.jks 已放置在类路径下。
配置类(RabbitConfiguration.java):
@Configuration @PropertySource("classpath:rabbit.properties") public class RabbitConfiguration { /** * Default sample channel name to respond for requests from clients. */ public static final String DEFAULT_QUEUE = "sample_queue"; /** * Environment properties file from rabbitmq configuration. */ @Autowired private Environment env; /** * Establish a connection to a rabbit mq server. * @return Rabbit connection factory for rabbitmq access. * @throws IOException If wrong parameters are used for connection. */ @Bean public RabbitConnectionFactoryBean connectionFactoryBean() throws IOException { RabbitConnectionFactoryBean connectionFactoryBean = new RabbitConnectionFactoryBean(); connectionFactoryBean.setHost(Objects.requireNonNull(env.getProperty("rabbit.host"))); connectionFactoryBean.setPort(Integer.parseInt(Objects.requireNonNull(env.getProperty("rabbit.port")))); connectionFactoryBean.setUsername(Objects.requireNonNull(env.getProperty("rabbit.username"))); connectionFactoryBean.setPassword(Objects.requireNonNull(env.getProperty("rabbit.password"))); // SSL-Configuration if set if(env.getProperty("rabbit.ssl") != null) { connectionFactoryBean.setUseSSL(true); connectionFactoryBean.setSslAlgorithm(Objects.requireNonNull(env.getProperty("rabbit.ssl"))); // This information should be stored safely !!! connectionFactoryBean.setKeyStore(Objects.requireNonNull(env.getProperty("rabbit.keystore.name"))); connectionFactoryBean.setKeyStorePassphrase(Objects.requireNonNull(env.getProperty("rabbit.keystore.password"))); connectionFactoryBean.setTrustStore(Objects.requireNonNull(env.getProperty("rabbit.truststore"))); connectionFactoryBean.setTrustStorePassphrase(Objects.requireNonNull(env.getProperty("rabbit.truststore.password"))); } return connectionFactoryBean; } /** * Connection factory which established a rabbitmq connection used from a connection factory * @param connectionFactoryBean Connection factory bean to create connection. * @return A connection factory to create connections. * @throws Exception If wrong parameters are used for connection. */ @Bean(name = "GEO_RABBIT_CONNECTION") public ConnectionFactory connectionFactory(RabbitConnectionFactoryBean connectionFactoryBean) throws Exception { return new CachingConnectionFactory(Objects.requireNonNull(connectionFactoryBean.getObject())); } /** * Queue initialization from rabbitmq to listen a queue. * @return An queue to listen for listen receiver. */ @Bean public Queue queue() { // Create an new queue to handle incoming responds return new Queue(DEFAULT_QUEUE, false, false, false, null); } /** * Generates a simple message listener container. * @param connectionFactory Established connection to rabbitmq server. * @param listenerAdapter Listener event adapter to listen for messages. * @return A simple message container for listening for requests. */ @Bean public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(DEFAULT_QUEUE); container.setMessageListener(listenerAdapter); container.setAcknowledgeMode(AcknowledgeMode.AUTO); return container; } /** * Message listener adapter to generate a message listener. * @param deviceMonitoringReceiver Device receive to for listening. * @return A message listener adapter to receive messages. */ @Bean public MessageListenerAdapter listenerAdapter(DeviceMonitoringReceiver deviceMonitoringReceiver) { return new MessageListenerAdapter(deviceMonitoringReceiver, "receiveMessage"); } }
RabbitMQ 配置
[ {rabbit, [ {ssl_listeners, [5671]}, {ssl_options, [{cacertfile, "D:\\tls-gen\\basic\\result\\ca_certificate.pem"}, {certfile, "D:\\tls-gen\\basic\\result\\server_seliiwvdec53152_certificate.pem"}, {keyfile, "D:\\tls-gen\\basic\\result\\server_seliiwvdec53152_key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, true}]} ]} ].
报错信息
Caused by: java.net.SocketException: Connection reset by peer: socket write error
排查与解决方案
1. 证书链与信任验证问题
RabbitMQ 配置了verify_peer和fail_if_no_peer_cert=true,强制要求客户端提供合法证书,且服务端证书需被客户端信任:
- 确认
server_store.jks中是否正确导入CA根证书(ca_certificate.pem),而非仅导入服务端证书。客户端信任库必须信任签发服务端证书的CA。 - 确认
client_key.p12中的客户端证书由同一CA签发,且包含完整证书链(若存在中间CA)。
2. 证书格式与密钥库有效性验证
- 验证
client_key.p12是否包含客户端私钥与对应证书:keytool -list -v -storetype pkcs12 -keystore client_key.p12 -storepass rabbitstore - 验证
server_store.jks的有效性:keytool -list -v -keystore server_store.jks -storepass rabbitstore
3. SSL协议与加密套件兼容性检查
- 确认RabbitMQ服务端启用了TLSv1.2协议,未被禁用。可通过RabbitMQ管理控制台查看SSL配置详情。
- 检查加密套件兼容性:Java 11默认加密套件可能与RabbitMQ默认配置存在差异,可在客户端显式指定兼容套件,或在RabbitMQ的
ssl_options中添加{ciphers, [兼容套件列表]}。
4. RabbitMQ服务端证书配置正确性
- 确认
cacertfile、certfile、keyfile路径正确,文件存在且服务端进程有读取权限。 - 验证服务端证书与私钥匹配:
两个命令输出的MD5值需完全一致。openssl x509 -noout -modulus -in server_seliiwvdec53152_certificate.pem | openssl md5 openssl rsa -noout -modulus -in server_seliiwvdec53152_key.pem | openssl md5
5. 客户端连接工厂SSL配置优化
在RabbitConnectionFactoryBean配置中,手动构建SSLContext以精确控制证书加载,避免自动加载的潜在问题:
// 在SSL参数设置后添加以下代码 connectionFactoryBean.setSslContext(SSLContexts.custom() .loadKeyMaterial(ResourceUtils.getFile("classpath:" + env.getProperty("rabbit.keystore.name")), env.getProperty("rabbit.keystore.password").toCharArray(), env.getProperty("rabbit.keystore.password").toCharArray()) .loadTrustMaterial(ResourceUtils.getFile("classpath:" + env.getProperty("rabbit.truststore")), env.getProperty("rabbit.truststore.password").toCharArray()) .build());
6. 网络与防火墙检查
- 确认5671端口未被占用,RabbitMQ服务正常监听该端口:
netstat -ano | findstr :5671 - 检查本地防火墙是否允许客户端与RabbitMQ服务端的5671端口通信。
内容的提问来源于stack exchange,提问作者Mohamed Nagy
相关产品推荐
相关产品推荐

