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