Beleza, pessoal! Quero compartilhar com vocês a aventura que vivi ao lidar com a nova versão do Redis 7 e suas funcionalidades de conexão segura TLS. Fiz algumas modificações no código para torná-lo compatível com essa nova forma de comunicação.
Tudo começou quando a heroku atualizou o Redis para a versão 7, parecia que seria só alegria. Mas aí veio a bomba: a partir desse momento começamos a ter problemas de conexão, nosso código(Java 8) não suportava a tal conexão segura TLS.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
@Profile("prd")
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String redisPwd;
@Bean
public JedisConnectionFactory connectionFactory() {
final RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(this.host);
config.setPort(this.port);
config.setPassword(RedisPassword.of(this.redisPwd));
return new JedisConnectionFactory(config);
}
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
}
Parecia até que o Redis estava querendo nos fazer passar por alguns perrengues para provar que segurança é coisa séria. Foi aí que vesti minha capa de super-herói e fui em busca da solução.
Então, mergulhei de cabeça na implementação do código. Importei algumas classes importantes para lidar com a conexão segura.
import redis.clients.jedis.JedisPoolConfig;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
No método connectionFactory(), o coração da nossa conexão com o Redis. adicionei as exceções NoSuchAlgorithmException e KeyManagementException para lidar com possíveis erros durante a configuração.
public JedisConnectionFactory connectionFactory() throws NoSuchAlgorithmException, KeyManagementException {
Também criei uma instância de SSLContext e a inicializei com null, para que pudesse confiar em todos os certificados e obtive a SSLSocketFactory a partir do SSLContext recém-criado para garantir a segurança na comunicação.
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts(), null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
Em seguida, utilizei o JedisClientConfiguration para configurar a conexão do Jedis com o Redis. Defini opções como tempo limite de leitura e conexão, além de habilitar o uso do SSL.
JedisClientConfiguration jedisClientConfiguration = JedisClientConfiguration.builder()
.usePooling()
.poolConfig(poolConfig)
.and()
.readTimeout(Duration.ZERO)
.connectTimeout(Duration.ofSeconds(10))
.useSsl()
.sslSocketFactory(sslSocketFactory)
.and()
.build();
Além disso, ajustei a RedisStandaloneConfiguration, adicionando as informações de host, porta e senha do Redis. Por fim, retornei uma nova instância de JedisConnectionFactory, que agora estava configurada para utilizar o Redis com comunicação segura via TLS.
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(this.host, this.port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(this.redisPwd));
return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
Uma outra modificação importante que fiz foi o método trustAllCerts(). implementei o X509TrustManager, que é responsável por gerenciar os certificados. Com isso, pude confiar em todos os certificados durante a comunicação segura.
private TrustManager[] trustAllCerts() {
return new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
}
E assim, superamos os problemas de conexão. Agora nossos dados estão protegidos como se estivessem guardados em um cofre de alta segurança.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
import redis.clients.jedis.JedisPoolConfig;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
@Profile("prd")
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String redisPwd;
@Bean
public JedisConnectionFactory connectionFactory() throws NoSuchAlgorithmException, KeyManagementException {
final JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(20);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts(), null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
JedisClientConfiguration jedisClientConfiguration = JedisClientConfiguration.builder()
.usePooling()
.poolConfig(poolConfig)
.and()
.readTimeout(Duration.ZERO)
.connectTimeout(Duration.ofSeconds(10))
.useSsl()
.sslSocketFactory(sslSocketFactory)
.and()
.build();
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(this.host, this.port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(this.redisPwd));
return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
}
private TrustManager[] trustAllCerts() {
return new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
}
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
}
A moral dessa história é que às vezes as atualizações nos pregam peças, mas com um pouco de dedicação e conhecimento, sempre encontramos uma solução. E agora podemos aproveitar todos os benefícios da comunicação segura TLS no Redis 7.
Espero ter ajudado :)
Top comments (0)