Make Redis to use SSL in SpringBoot
  March 11, 2024
 
 Redis in SpringBoot
The post assume you are use spring-boot-starter-data-redis to use Redis in SpringBoot Application.
There has two lib to implements redis in SpringBoot, which are Lettuce (default) and Jedis.
The first thing you need to do is set spring.redis.ssl to true in application.yaml. (or properties).
WARN
 You also need set custom keystore path and password if you want to fully follow the below lib configuration in next section.
The post will use PKCS12-formatted keystore, JKS-formatted keystore also can work fine.
spring.redis.keyStore = "classpath:server.p12"
spring.redis.keyStorePass = "password of pkcs12"
spring.redis.keyStorePass = "PKCS12"plaintext
Then follow the right section to see how to config SSL in 3rd party library.
Lettuce
RedisConfig.java
@Configuration
public class RedisConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.ssl}")
    private boolean ssl;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.database}")
    private int database;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.keyStore}")
    private String keyStorePath;
    @Value("${spring.redis.keyStorePass}")
    private String keyStorePass;
    @Resource
    private ResourceLoader resourceLoader;
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(password);
        redisStandaloneConfiguration.setDatabase(database);
        LettuceClientConfiguration.LettuceClientConfigurationBuilder lettuceClientConfigurationBuilder = LettuceClientConfiguration.builder();
        if (ssl) {
            File keyStore = resourceLoader.getResource(keyStorePath).getFile();
            SslOptions sslOptions = SslOptions.builder()
                    .jdkSslProvider()
                    .keystore(keyStore, keyStorePass.toCharArray())
                    .truststore(keyStore, keyStorePass)
                    .build();
            ClientOptions clientOptions = ClientOptions
                    .builder()
                    .sslOptions(sslOptions)
                    .protocolVersion(ProtocolVersion.RESP3)
                    .build();
            lettuceClientConfigurationBuilder
                    .clientOptions(clientOptions)`
                    .useSsl()
                    .disablePeerVerification(); 
        }
        LettuceClientConfiguration lettuceClientConfiguration = lettuceClientConfigurationBuilder.build();
        return new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
    }java
Jedis
If you don't want to use default Lettuce implementation, you can update POM to use Jedis.
pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.0.0</version>
</dependency>xml
RedisConfig.java
@Configuration
public class RedisConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.ssl}")
    private boolean ssl;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.database}")
    private int database;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.keyStore}")
    private String keyStorePath;
    @Value("${spring.redis.keyStorePass}")
    private String keyStorePass;
    @Value("${spring.redis.keyStoreType}")
    private String keyStoreType;
    
    
    
    
    
    
    
    
    @Resource
    private ResourceLoader resourceLoader;
    @Bean
    public JedisConnectionFactory redisConnectionFactory() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(password);
        redisStandaloneConfiguration.setDatabase(database);
        JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
        if (ssl) {
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            File keyStoreFile = resourceLoader.getResource(keyStorePath).getFile();
            keyStore.load(new FileInputStream(keyStoreFile), keyStorePass.toCharArray());
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, keyStorePass.toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
            jedisClientConfigurationBuilder
                    .connectTimeout(Duration.ofMillis(timeout))
                    .useSsl()
                    .sslSocketFactory(sslContext.getSocketFactory());
        }
        JedisClientConfiguration jedisClientConfiguration = jedisClientConfigurationBuilder.build();
        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    }
}java