Veri bütünlüğünü korumak ve aktarım sırasındaki verileri şifrelemek için Tair (Redis OSS uyumlu) örneğine TLS (SSL) üzerinden bağlanın. Redis protokolüyle uyumlu herhangi bir istemci kullanılabilir.
Ön koşullar
Başlamadan önce aşağıdakilere sahip olduğunuzdan emin olun:
Örnek üzerinde TLS (SSL) şifrelemesi etkin olmalıdır. Bkz. TLS şifrelemesini etkinleştirme.
Tair örneği ile aynı sanal özel bulutta (VPC) bulunan bir Elastic Compute Service (ECS) örneği.
ECS dahili IP adresinin örnek izin listesine eklenmiş olması gerekir. Bkz. İzin listelerini yapılandırma.
CA sertifikasını (
ApsaraDB-CA-Chain.pemveya.jks) TLS şifreleme sayfasından indirmiş olmanız gerekir. Bkz. TLS şifrelemesini etkinleştirme.
Bağlantı ayrıntılarını toplama
Kod yazmaya başlamadan önce konsoldan aşağıdaki bilgileri toplayın:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VPC üzerinden parolasız erişim etkinse, aynı VPC'deki istemciler parola olmadan bağlanabilir.
Proxy bağlantı modu
Standart mimari, proxy modlu küme mimarisi veya okuma/yazma ayırma mimarisinde çalışan örnekler için aşağıdaki örnekleri kullanın.
openssl (Hızlı test)
SSL/TLS bağlantısının çalıştığını hızlıca doğrulamak istiyor ancak redis-cli yüklemek istemiyorsanız openssl s_client komutunu kullanabilirsiniz:
openssl s_client -connect r-bp14joyeihew30****.redis.rds.aliyuncs.com:6379 -CAfile ApsaraDB-CA-Chain.pem
Komut SSL el sıkışma bilgilerini gösteriyorsa ve bağlantı hemen kapanmıyorsa SSL/TLS bağlantısı çalışıyor demektir.
redis-cli
TLS desteğini etkinleştirmek için redis-cli'yi BUILD_TLS=yes parametresiyle derleyin.
-
ECS örneğinde oturum açın ve redis-cli'yi indirmek, derlemek ve yüklemek için aşağıdaki komutları çalıştırın. Derleme işlemi genellikle 2 ila 3 dakika sürer.
sudo yum -y install openssl-devel gcc # Install build dependencies wget https://download.redis.io/releases/redis-7.2.0.tar.gz tar xzf redis-7.2.0.tar.gz cd redis-7.2.0 && make BUILD_TLS=yesBu örnekte Redis 7.2.0 kullanılmıştır. Diğer sürümler de desteklenmektedir.
-
--cacertsonrasında CA sertifika yolunu belirterek örneğe bağlanın:./src/redis-cli -h r-bp14joyeihew30****.redis.rds.aliyuncs.com -p 6379 --tls --cacert ./ApsaraDB-CA-Chain.pem -
Kimlik doğrulaması yapın:
AUTH passwordOKyanıtı, bağlantının başarılı olduğunu gösterir.
Java (Jedis)
Tüm örneklerde CA sertifikasını yüklemek için JKS formatında bir TrustStore kullanılır. SSLSocketFactory oluşturmak için bir yardımcı yöntem tanımlayın ve bunu bağlantı havuzuna veya küme istemcisine iletin.
Jedis (en son sürüm) kullanın.
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisSSLTest {
private static SSLSocketFactory createTrustStoreSSLSocketFactory(String jksFile) throws Exception {
KeyStore trustStore = KeyStore.getInstance("jks");
InputStream inputStream = null;
try {
inputStream = new FileInputStream(jksFile);
trustStore.load(inputStream, null);
} finally {
inputStream.close();
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
}
public static void main(String[] args) throws Exception {
// ApsaraDB-CA-Chain.jks is the certificate file name.
final SSLSocketFactory sslSocketFactory = createTrustStoreSSLSocketFactory("ApsaraDB-CA-Chain.jks");
// Configure the connection pool with the instance endpoint, port, timeout, and password.
JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com",
6379, 2000, "redistest:Pas***23", 0, true, sslSocketFactory, null, null);
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
System.out.println(jedis.get("key"));
}
}
}
Python (redis-py)
Hem bağlantı havuzu hem de standart bağlantı yaklaşımları ssl=True kullanır ve PEM sertifika dosyasına işaret eder.
redis-py (en son sürüm) kullanın.
Bağlantı havuzu
#!/bin/python
import redis
# ApsaraDB-CA-Chain.pem is the certificate file name.
# Replace host, port, and password with your instance values.
pool = redis.ConnectionPool(
connection_class=redis.connection.SSLConnection,
max_connections=100,
host="r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com",
port=6379,
password="redistest:Pas***23",
ssl_cert_reqs=True,
ssl_ca_certs="ApsaraDB-CA-Chain.pem"
)
client = redis.Redis(connection_pool=pool)
client.set("hi", "redis")
print(client.get("hi"))
Standart bağlantı
#!/bin/python
import redis
# ApsaraDB-CA-Chain.pem is the certificate file name.
# Replace host, port, and password with your instance values.
client = redis.Redis(
host="r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com",
port=6379,
password="redistest:Test1234",
ssl=True,
ssl_cert_reqs="required",
ssl_ca_certs="ApsaraDB-CA-Chain.pem"
)
client.set("hello", "world")
print(client.get("hello"))
PHP (predis)
predis (en son sürüm) kullanın. phpredis tercih ediyorsanız bağlantı örneği için phpredis/phpredis#1600 adresine bakın.
<?php
require __DIR__.'/predis/autoload.php';
/* ApsaraDB-CA-Chain.pem is the certificate file name.
Replace host, port, and password with your instance values. */
$client = new Predis\Client([
'scheme' => 'tls',
'host' => 'r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com',
'port' => 6379,
'password' => 'redistest:Pas***23',
'ssl' => ['cafile' => 'ApsaraDB-CA-Chain.pem', 'verify_peer' => true],
]);
$client->set("hello", "world");
print $client->get("hello")."\n";
?>
C# (StackExchange.Redis)
StackExchange.Redis (en son sürüm) kullanın.
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using StackExchange.Redis;
namespace SSLTest
{
class Program
{
private static bool CheckServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
var ca = new X509Certificate2(
"/your path/ApsaraDB-CA-Chain/ApsaraDB-CA-Chain.pem");
return chain.ChainElements
.Cast<X509ChainElement>()
.Any(x => x.Certificate.Thumbprint == ca.Thumbprint);
}
static void Main(string[] args)
{
// ApsaraDB-CA-Chain.pem is the certificate file name.
// Replace host, port, and password with your instance values.
ConfigurationOptions config = new ConfigurationOptions()
{
EndPoints = {"r-bp10q23zyfriodu*****.redis.rds.aliyuncs.com:6379"},
Password = "redistest:Pas***23",
Ssl = true,
};
config.CertificateValidation += CheckServerCertificate;
using (var conn = ConnectionMultiplexer.Connect(config))
{
Console.WriteLine("connected");
var db = conn.GetDatabase();
db.StringSet("hello", "world");
Console.WriteLine(db.StringGet("hello"));
}
}
}
}
Spring Data Redis
Spring Data Redis 2.7.12 (Java 1.8 için) veya üzerini kullanın.
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// Store TLS certificate configuration in a properties file for production use.
String host = "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com";
int port = 6379;
String password = "Pas***23";
String trustStoreFilePath = "/path/to/ApsaraDB-CA-Chain.jks";
ClientOptions clientOptions = ClientOptions.builder().sslOptions(
SslOptions.builder().jdkSslProvider().truststore(new File(trustStoreFilePath)).build()).build();
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPort(port);
config.setPassword(password);
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.clientOptions(clientOptions)
.useSsl().build();
return new LettuceConnectionFactory(config, lettuceClientConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
}
}
Lettuce
Lettuce 6.2.4.RELEASE veya üzerini kullanın.
public class SSLExample {
public static void main(String[] args) throws Exception {
String host = "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com";
int port = 6379;
String password = "Pas***23";
String trustStoreFilePath = "/path/to/ApsaraDB-CA-Chain.jks";
RedisURI uri = RedisURI.builder()
.withHost(host)
.withPort(port)
.withPassword(password.toCharArray())
.withSsl(true).build();
SslOptions sslOptions = SslOptions.builder()
.jdkSslProvider()
.truststore(new File(trustStoreFilePath)).build();
ClientOptions clientOptions = ClientOptions.builder()
.sslOptions(sslOptions).build();
RedisClient client = RedisClient.create(uri);
client.setOptions(clientOptions);
RedisCommands<String, String> sync = client.connect().sync();
System.out.println(sync.set("key", "value"));
System.out.println(sync.get("key"));
}
}
Go (go-redis)
go-redis v9.0 veya üzerini kullanın.
Go örneği, ana bilgisayar adı doğrulamasını atlayarak CA zincirini doğrulamak için özel bir VerifyPeerCertificate işlevi kullanır. Bu gereklidir çünkü Tair uç noktası ana bilgisayar adı, sertifikanın ortak adıyla eşleşmeyebilir.
package main
import (
"context"
"fmt"
"io/ioutil"
"crypto/tls"
"crypto/x509"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func main() {
caCert, err := ioutil.ReadFile("/root/ApsaraDB-CA-Chain.pem")
if err != nil {
fmt.Println("Error loading CA certificate:", err)
return
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
RootCAs: caCertPool,
InsecureSkipVerify: true, // Not actually skipping — cert is verified in VerifyPeerCertificate
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// Validate the server certificate against the CA chain,
// skipping hostname verification (not supported in direct connection mode).
// Reference: https://github.com/golang/go/issues/21971#issuecomment-412836078
certs := make([]*x509.Certificate, len(rawCerts))
for i, asn1Data := range rawCerts {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
panic(err)
}
certs[i] = cert
}
opts := x509.VerifyOptions{
Roots: caCertPool,
DNSName: "", // Skip hostname verification
Intermediates: x509.NewCertPool(),
}
for i, cert := range certs {
if i == 0 {
continue
}
opts.Intermediates.AddCert(cert)
}
_, err := certs[0].Verify(opts)
return err
},
}
rdb := redis.NewClient(&redis.Options{
Addr: "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com:6379",
Username: "default",
Password: "Pas***23",
TLSConfig: tlsConfig,
})
err = rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key:", val)
}
Doğrudan bağlantı modu
Bu örnekleri yalnızca doğrudan bağlantı modunda çalışan küme mimarisine sahip örnekler için kullanın.
Doğrudan bağlantı modunda istemci, tek tek küme parçalarına doğrudan bağlanır. Jedis ve Spring Data Redis (Jedis) için parça başına toplam bağlantı sayısını parçanın maksimum bağlantı sınırının altında tutun: uygulama sunucusu sayısı × MaxTotal < parça başına maksimum bağlantı .
redis-cli
Proxy bağlantı modundaki gibi redis-cli'yi BUILD_TLS=yes parametresiyle derleyin.
-
ECS örneğinde oturum açın ve redis-cli'yi derleyin:
sudo yum -y install openssl-devel gcc # Install build dependencies wget https://download.redis.io/releases/redis-7.2.0.tar.gz tar xzf redis-7.2.0.tar.gz cd redis-7.2.0 && make BUILD_TLS=yes -
Küme modu için gerekli olan
-cbayrağını kullanarak bağlanın:./src/redis-cli -h r-bp14joyeihew30****.redis.rds.aliyuncs.com -p 6379 -c --tls --cacert ./ApsaraDB-CA-Chain.pem -
Kimlik doğrulaması yapın:
AUTH passwordOKyanıtı, bağlantının başarılı olduğunu gösterir.
Java (JedisCluster)
Jedis (en son sürüm) kullanın.
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import redis.clients.jedis.ConnectionPoolConfig;
import redis.clients.jedis.DefaultJedisClientConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
public class JedisClusterTSL {
private static final int DEFAULT_TIMEOUT = 2000;
private static final int DEFAULT_REDIRECTIONS = 5;
private static final ConnectionPoolConfig jedisPoolConfig = new ConnectionPoolConfig();
private static SSLSocketFactory createTrustStoreSSLSocketFactory(String jksFile) throws Exception {
KeyStore trustStore = KeyStore.getInstance("jks");
InputStream inputStream = null;
try {
inputStream = new FileInputStream(jksFile);
trustStore.load(inputStream, null);
} finally {
inputStream.close();
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
}
public static void main(String args[]) throws Exception {
// In direct connection mode, keep (business machines × MaxTotal) below the per-shard connection limit.
jedisPoolConfig.setMaxTotal(30);
jedisPoolConfig.setMaxIdle(30);
jedisPoolConfig.setMinIdle(15);
int port = 6379;
String host = "r-2zee50zxi5iiq****.redis.rds-aliyun.rds.aliyuncs.com";
String user = "default";
String password = "Pas***23";
final SSLSocketFactory sslSocketFactory = createTrustStoreSSLSocketFactory("/root/ApsaraDB-CA-Chain.jks");
DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder()
.connectionTimeoutMillis(DEFAULT_TIMEOUT)
.socketTimeoutMillis(DEFAULT_TIMEOUT)
.user(user).password(password)
.ssl(true)
.sslSocketFactory(sslSocketFactory).build();
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort(host, port));
JedisCluster jc = new JedisCluster(jedisClusterNode, jedisClientConfig, DEFAULT_REDIRECTIONS, jedisPoolConfig);
System.out.println(jc.set("key", "value"));
System.out.println(jc.get("key"));
jc.close(); // Call when the application exits to release resources.
}
}
Python (redis-py)
redis-py 4.3.6 (Python 3.6 için) veya üzerini kullanın.
#!/usr/bin/env python
from redis.cluster import RedisCluster
# Replace host and port with your instance endpoint and port.
host = 'r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com'
port = 6379
# Replace user and pwd with your instance account and password.
user = 'default'
pwd = 'Pas***23'
rc = RedisCluster(host=host, port=port, username=user, password=pwd,
ssl=True, ssl_ca_certs="/root/ApsaraDB-CA-Chain.pem")
rc.set('foo', 'bar')
print(rc.get('foo'))
PHP (phpredis)
phpredis 5.3.7 veya üzerini kullanın.
<?php
// Direct connection endpoint and port.
$array = ['r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com:6379'];
// Connection password.
$pwd = "Pas***23";
// TLS settings.
$tls = ["verify_peer" => false, "verify_peer_name" => false];
// Connect to the cluster.
$obj_cluster = new RedisCluster(NULL, $array, 1.5, 1.5, true, $pwd, $tls);
var_dump($obj_cluster);
if ($obj_cluster->set("foo", "bar") == false) {
die($obj_cluster->getLastError());
}
$value = $obj_cluster->get("foo");
echo $value;
echo "\n";
?>
C# (StackExchange.Redis)
StackExchange.Redis (en son sürüm) kullanın.
using StackExchange.Redis;
using System;
using System.Linq;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace TairClient
{
class Program
{
static void Main()
{
const string Host = "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com";
const int Port = 6379;
Console.WriteLine("connecting...");
var config = new ConfigurationOptions
{
EndPoints = { { Host, Port } },
Ssl = true,
Password = "Pas***23",
};
config.CertificateValidation += (sender, cert, chain, errors) =>
{
if (errors == SslPolicyErrors.RemoteCertificateChainErrors ||
errors == SslPolicyErrors.RemoteCertificateNameMismatch)
{
return true;
}
var caCert = LoadCertificateFromPem("/root/ApsaraDB-CA-Chain.pem");
var isCertIssuedByTrustedCA = chain.ChainElements
.Cast<X509ChainElement>()
.Any(x => x.Certificate.Thumbprint.Equals(
caCert.Thumbprint, StringComparison.OrdinalIgnoreCase));
return isCertIssuedByTrustedCA;
};
using (var conn = ConnectionMultiplexer.Connect(config))
{
Console.WriteLine("connected");
var db = conn.GetDatabase();
db.StringSet("hello", "world");
Console.WriteLine(db.StringGet("hello")); // world
}
}
private static X509Certificate2 LoadCertificateFromPem(string pemFilePath)
{
X509Certificate2 cert = X509Certificate2.CreateFromPem(File.ReadAllText(pemFilePath));
return cert;
}
}
}
Spring Data Redis
Spring Data Redis 2.7.5 (Java 1.8 için) veya üzerini kullanın. Hem Jedis hem de Lettuce desteklenir.
Jedis ile (önerilir)
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisConfigJedis {
private static SSLSocketFactory createTrustStoreSSLSocketFactory(String jksFile) throws Exception {
KeyStore trustStore = KeyStore.getInstance("jks");
InputStream inputStream = null;
try {
inputStream = new FileInputStream(jksFile);
trustStore.load(inputStream, null);
} finally {
inputStream.close();
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
}
@Bean
public RedisConnectionFactory redisConnectionFactory() throws Exception {
String host = "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com:6379";
String user = "default";
String password = "Pas***23";
String trustStoreFilePath = "/root/ApsaraDB-CA-Chain.jks";
List<String> clusterNodes = Arrays.asList(host);
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
redisClusterConfiguration.setUsername(user);
redisClusterConfiguration.setPassword(password);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// In direct connection mode, keep (business machines × MaxTotal) below the per-shard connection limit.
jedisPoolConfig.setMaxTotal(30);
jedisPoolConfig.setMaxIdle(20);
jedisPoolConfig.setMinIdle(20);
final SSLSocketFactory sslSocketFactory = createTrustStoreSSLSocketFactory(trustStoreFilePath);
JedisClientConfiguration jedisClientConfiguration = JedisClientConfiguration.builder()
.useSsl().sslSocketFactory(sslSocketFactory)
.and().usePooling().poolConfig(jedisPoolConfig).build();
return new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
Lettuce ile
import java.io.File;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.SslOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
String host = "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com";
int port = 6379;
String user = "default";
String password = "Pas***23";
String trustStoreFilePath = "/root/ApsaraDB-CA-Chain.jks";
ClientOptions clientOptions = ClientOptions.builder().sslOptions(
SslOptions.builder().jdkSslProvider().truststore(new File(trustStoreFilePath)).build()).build();
RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
clusterConfiguration.clusterNode(host, port);
clusterConfiguration.setUsername(user);
clusterConfiguration.setPassword(password);
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.clientOptions(clientOptions)
.useSsl()
.disablePeerVerification()
.build();
return new LettuceConnectionFactory(clusterConfiguration, lettuceClientConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
Lettuce (küme modu)
Lettuce 6.3.0.RELEASE veya üzerini kullanın. Bu örnek, üretim güvenilirliği için TCP keepalive ve topoloji yenilemeyi etkinleştirir.
import java.io.File;
import java.time.Duration;
import io.lettuce.core.RedisURI;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.SocketOptions.KeepAliveOptions;
import io.lettuce.core.SocketOptions.TcpUserTimeoutOptions;
import io.lettuce.core.SslOptions;
import io.lettuce.core.SslVerifyMode;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
public class SSLClusterExample {
/**
* TCP keepalive settings:
* TCP_KEEPIDLE = 30s, TCP_KEEPINTVL = 10s, TCP_KEEPCNT = 3
*/
private static final int TCP_KEEPALIVE_IDLE = 30;
/**
* TCP_USER_TIMEOUT prevents Lettuce from hanging indefinitely on broken connections.
* See: https://github.com/lettuce-io/lettuce-core/issues/2082
*/
private static final int TCP_USER_TIMEOUT = 30;
public static void main(String[] args) throws Exception {
String host = "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com";
int port = 6379;
String password = "Pas***23";
String trustStoreFilePath = "/root/ApsaraDB-CA-Chain.jks";
RedisURI uri = RedisURI.builder()
.withHost(host)
.withPort(port)
.withPassword(password.toCharArray())
.withSsl(true)
// Direct cluster connections require CA-only verification; FULL mode is not supported.
.withVerifyPeer(SslVerifyMode.CA)
.build();
SslOptions sslOptions = SslOptions.builder()
.jdkSslProvider()
.truststore(new File(trustStoreFilePath)).build();
ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(15))
.dynamicRefreshSources(false)
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(15)).build();
SocketOptions socketOptions = SocketOptions.builder()
.keepAlive(KeepAliveOptions.builder()
.enable()
.idle(Duration.ofSeconds(TCP_KEEPALIVE_IDLE))
.interval(Duration.ofSeconds(TCP_KEEPALIVE_IDLE / 3))
.count(3)
.build())
.tcpUserTimeout(TcpUserTimeoutOptions.builder()
.enable()
.tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
.build())
.build();
RedisClusterClient redisClient = RedisClusterClient.create(uri);
redisClient.setOptions(ClusterClientOptions.builder()
.socketOptions(socketOptions)
.sslOptions(sslOptions)
.validateClusterNodeMembership(false)
.topologyRefreshOptions(refreshOptions).build());
StatefulRedisClusterConnection<String, String> connection = redisClient.connect();
connection.sync().set("key", "value");
System.out.println(connection.sync().get("key"));
}
}
Go (go-redis)
go-redis v9.0 veya üzerini kullanın. Küme istemcisi NewClient yerine NewClusterClient kullanır.
package main
import (
"context"
"fmt"
"io/ioutil"
"crypto/tls"
"crypto/x509"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func main() {
caCert, err := ioutil.ReadFile("/root/ApsaraDB-CA-Chain.pem")
if err != nil {
fmt.Println("Error loading CA certificate:", err)
return
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
RootCAs: caCertPool,
InsecureSkipVerify: true, // Not actually skipping — cert is verified in VerifyPeerCertificate
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// Validate the CA chain while skipping hostname verification.
// Reference: https://github.com/golang/go/issues/21971#issuecomment-412836078
certs := make([]*x509.Certificate, len(rawCerts))
for i, asn1Data := range rawCerts {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
panic(err)
}
certs[i] = cert
}
opts := x509.VerifyOptions{
Roots: caCertPool,
DNSName: "", // Skip hostname verification
Intermediates: x509.NewCertPool(),
}
for i, cert := range certs {
if i == 0 {
continue
}
opts.Intermediates.AddCert(cert)
}
_, err := certs[0].Verify(opts)
return err
},
}
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com:6379"},
Username: "default",
Password: "Pas***23",
TLSConfig: tlsConfig,
})
err = rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key:", val)
}
SSS
Neden No subject alternative DNS name matching xxx found hatası alıyorum?
Bu hata, TLS etkinleştirildikten sonra örnek uç noktasını veya bağlantı noktasını değiştirdiğinizde ortaya çıkar; mevcut sertifika yeni adresle artık eşleşmez. Konsoldaki TLS sertifikasını güncelleyin ve ardından yeniden bağlanın.