skip to Main Content

I am using Spring-boot-starter-redis dependency to connect to redis (below is my snippet from gradle dependency

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    compileOnly 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'
}

I am moving to GCP now and the redis in GCP is SSL Enabled and so, i configured my spring properties this way

spring.redis.ssl=true
spring.redis.host=xxxxxx
spring.redis.port=6378

It works perfectly fine when i disable the ssl. But when i enable it, i get below error.. is there any way to inject the PEM ceritificate in Spring configuration ?

[Request processing failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to xx.xx.xx.xx:6378] with root cause
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:na]
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
        at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[na:na]
        at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:276) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1334) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1231) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1174) ~[na:na]
        at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443) ~[na:na]
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074) ~[na:na]
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061) ~[na:na]
        at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008) ~[na:na]

please help

2

Answers


  1. Chosen as BEST ANSWER

    I tackled it this way

    • spring-boot-starter-data-redis dependency uses Lettuce by default
    • To connect to Redis through ssl spring.redis.ssl=true property need to be enabled.
    • If the CA of the ceritificate is unique and not part of Java's JKS, then you have two options, either import the keys to JKS or disable the SSL-Verification

    Quoting whats given in Google Docs here

    For example, Lettuce is a popular Java client for Redis. Their documentation provides an example for connecting natively with TLS (see Example 47). Given that the Java Security Manager does not allow self-signed certificates by default, an additional option needs to be specified in the Redis URI construction .withVerifyPeer(false)

    I disabled the SSL Verification . The connection will still happen through SSL, but the verification alone i disabled it by configuring a bean.

    Also am not worried about man-in-the-middle-attack as my Redis is exposed only to my GKE Cluster.. So this solution worked fine for me

    @Configuration
    public class RedisSSLConfiguration {
    
        @Bean
        @ConditionalOnProperty("spring.redis.ssl")
        public LettuceClientConfigurationBuilderCustomizer builderCustomizer() {
            return builder -> builder.useSsl().disablePeerVerification();
        }
    }
    

  2. Faced same Issue. After doing so much analysis finally I found the proper way to connect to GCP Memorystore Redis Server with SSL Enabled from my java client.

    Following the Code Snippet and Steps.

    Step 1 : Download server-ca.pem(Or any Server CA) file from GCP -> Console -> MemoryStore -> Redis -> Security Tab -> download server-ca.pem.

    Step 2 : move the downloaded file into java client(your java application) class path.

    @Configuration 
    public class CacheConfig {
        @Autowired
        ResourceLoader resourceLoader;
        @Bean
        RedisConnectionFactory redisConnectionFactory() throws IOException {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName("ipaddress_of_gcpmemorystore_redis");
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword("auth_string_from_security_tab");
        SslOptions sslOptions = SslOptions.builder().
                trustManager(resourceLoader.getResource("file:/home/<user_name>/server-ca.pem").getFile()).build();
        ClientOptions clientOptions = ClientOptions.builder().sslOptions(sslOptions).protocolVersion(ProtocolVersion.RESP3).build();
        LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
                .clientOptions(clientOptions).useSsl().build();
        LettuceConnectionFactory connectionFactory =  new LettuceConnectionFactory(redisStandaloneConfiguration,
                lettuceClientConfiguration);
        return connectionFactory;
    }
    @Bean
    public RedisTemplate<?, ?> redisTemplate() throws IOException {
        RedisTemplate<?, ?> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory());
        return template;
    }}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search