SSL开启的GCP Redis连接失败,Spring Boot如何注入PEM证书配置?
解决方案
这个报错是JVM默认信任库中没有GCP Redis实例的SSL证书导致的握手失败,可通过以下两种方式在Spring中注入PEM证书解决:
方案1:使用Spring Boot原生SSL Bundle配置(Spring Boot 2.7及以上版本推荐,无需编码)
将GCP提供的PEM格式证书放到项目resources/ssl目录下,命名为gcp-redis.crt,直接在application配置文件中添加以下配置即可:
spring: redis: ssl: true host: xxxxxx port: 6378 ssl-bundle: gcp-redis # 配置SSL证书bundle ssl: bundle: pem: gcp-redis: truststore: certificate: "classpath:ssl/gcp-redis.crt"
方案2:自定义Lettuce连接工厂(兼容所有Spring Boot版本)
如果使用的Spring Boot版本低于2.7,不支持SSL Bundle特性,可以通过自定义Redis连接工厂的方式手动注入证书:
编写配置类,加载PEM证书构建自定义SSL上下文:
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import io.lettuce.core.SslOptions; import java.io.FileInputStream; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @Configuration public class RedisSslConfig { @Value("${spring.redis.host}") private String redisHost; @Value("${spring.redis.port}") private int redisPort; @Value("${spring.redis.ssl.cert-path}") private String certPath; // 配置为classpath:ssl/gcp-redis.crt @Bean public LettuceConnectionFactory redisConnectionFactory() throws Exception { // 加载PEM证书 CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert; try (FileInputStream fis = new FileInputStream(getClass().getResource(certPath.replace("classpath:", "")).getFile())) { cert = (X509Certificate) cf.generateCertificate(fis); } // 构建信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // 先加载默认信任库 tmf.init((java.security.KeyStore) null); // 把GCP Redis证书加入信任库 java.security.KeyStore ks = java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType()); ks.load(null); ks.setCertificateEntry("gcp-redis", cert); tmf.init(ks); // 构建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); // 配置Lettuce SSL选项 SslOptions sslOptions = SslOptions.builder() .sslContext(sslContext) .build(); LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .useSsl() .sslOptions(sslOptions) .build(); RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration(redisHost, redisPort); return new LettuceConnectionFactory(standaloneConfig, clientConfig); } }
对应的application配置添加证书路径即可:
spring.redis.ssl=true spring.redis.host=xxxxxx spring.redis.port=6378 spring.redis.ssl.cert-path=classpath:ssl/gcp-redis.crt
注意事项
- 确保PEM证书是GCP官方提供的X.509格式证书,文件内容以
-----BEGIN CERTIFICATE-----开头,-----END CERTIFICATE-----结尾 - 打包时确保证书文件被正确打包到jar包的对应路径下,不会被过滤排除
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

