Saat menggunakan klien untuk menghubungkan ke instans Tair (Redis OSS-compatible), Anda dapat mengaktifkan enkripsi TLS (SSL) untuk meningkatkan keamanan tautan data dan memastikan integritas data. Gunakan klien apa pun yang kompatibel dengan protokol Redis. Topik ini menyediakan contoh kode untuk menghubungkan ke instans menggunakan klien umum.
Prasyarat
Enkripsi TLS (SSL) harus diaktifkan untuk instans Tair Anda. Untuk informasi lebih lanjut, lihat Aktifkan Enkripsi TLS.
Klien harus di-hosting pada Instance ECS (Elastic Compute Service) yang berada dalam virtual private cloud (VPC) yang sama dengan instans Tair.
Catatan
Jika akses tanpa kata sandi melalui VPC diaktifkan untuk instans, klien dalam VPC yang sama dapat terhubung ke instans tanpa kata sandi.
Persiapan
Tambahkan alamat IP internal dari Instance ECS yang meng-hosting klien ke daftar putih instans Tair. Untuk informasi lebih lanjut, lihat Konfigurasi Daftar Putih.
Peroleh informasi berikut untuk dikonfigurasikan dalam kode program klien Anda:
Informasi yang harus diperoleh
Cara memperoleh
Titik akhir instans
Pergi ke halaman Instans, pilih wilayah di bilah navigasi atas, lalu klik ID instans target. Di bagian Connection Information, Anda dapat melihat titik akhir dan port untuk jenis koneksi yang berbeda.
CatatanInstans mendukung beberapa jenis titik akhir. Kami sarankan Anda menggunakan titik akhir VPC untuk keamanan yang lebih tinggi dan latensi jaringan yang lebih rendah. Untuk informasi lebih lanjut, lihat Lihat titik akhir.
Port
Port default adalah 6379. Anda juga dapat menyesuaikan port. Untuk informasi lebih lanjut, lihat Ubah titik akhir atau port.
Akun instans (tidak diperlukan untuk beberapa klien)
Secara default, sebuah instans memiliki akun bernama setelah ID instans, seperti r-bp10noxlhcoim2****. Anda juga dapat membuat akun baru dan memberikan izin kepadanya. Untuk informasi lebih lanjut, lihat Buat dan kelola akun.
Kata sandi akun
Format kata sandi bervariasi berdasarkan akun yang dipilih:
Akun default (akun bernama setelah ID instans): Masukkan hanya kata sandi.
Akun yang baru dibuat: Format kata sandi adalah
<user>:<password>. Sebagai contoh, jika akun kustom adalahtestaccountdan kata sandinya adalahRp829dlwa, Anda harus memasukkantestaccount:Rp829dlwa.
CatatanJika Anda menggunakan alat manajemen database pihak ketiga, seperti RDM, untuk menghubungkan ke instans, Anda harus memasukkan kata sandi dalam format
user:passworddi bidang kata sandi.Jika Anda lupa kata sandi Anda, Anda dapat menyetel ulang. Untuk informasi lebih lanjut, lihat Ubah atau setel ulang kata sandi.
Unduh sertifikat otoritas sertifikasi (CA). Untuk informasi lebih lanjut, lihat Aktifkan Enkripsi TLS.
Proksi mode koneksi
Mode ini berlaku untuk instans yang menggunakan arsitektur standar, arsitektur kluster dengan mode proxy, atau arsitektur pemisahan baca/tulis. Perluas bagian berikut untuk melihat contoh kode.
redis-cli
Saat mengompilasi Redis, tentukan BUILD_TLS=yes untuk mengaktifkan koneksi TLS di redis-cli.
Masuk ke Instance ECS dan jalankan perintah berikut untuk mengunduh, menginstal, dan mengompilasi redis-cli.
sudo yum -y install openssl-devel gcc # Instal dependensi gcc. 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=yesTopik ini menggunakan Redis 7.2.0 sebagai contoh. Anda juga dapat menginstal versi lainnya. Proses kompilasi dan instalasi biasanya memakan waktu 2 hingga 3 menit.
Jalankan perintah berikut di jendela baris perintah untuk menghubungkan ke instans.
./src/redis-cli -h r-bp14joyeihew30****.redis.rds.aliyuncs.com -p 6379 --tls --cacert ./ApsaraDB-CA-Chain.pemSetelah parameter cacert, tentukan jalur ke sertifikat CA.
Jalankan perintah berikut untuk menyelesaikan otentikasi kata sandi.
AUTH passwordTanggapan OK menunjukkan bahwa Anda telah terhubung ke instans.
Java
Contoh ini menggunakan Jedis versi 3.6.0. Gunakan versi terbaru.
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 adalah nama file sertifikat.
final SSLSocketFactory sslSocketFactory = createTrustStoreSSLSocketFactory("ApsaraDB-CA-Chain.jks");
// Pengaturan kolam koneksi adalah titik akhir instans, nomor port, pengaturan timeout, dan kata sandi.
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
Contoh ini menggunakan klien redis-py. Gunakan versi terbaru.
Kolam koneksi
#!/bin/python
import redis
# Atur kolam koneksi. Ganti nilai host, port, dan password dengan titik akhir instans, nomor port, dan kata sandi.
# ApsaraDB-CA-Chain.pem adalah nama file sertifikat.
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")Koneksi standar
#!/bin/python
import redis
# Atur informasi koneksi. Ganti nilai host, port, dan password dengan titik akhir instans, nomor port, dan kata sandi.
# ApsaraDB-CA-Chain.pem adalah nama file sertifikat.
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
Contoh ini menggunakan klien predis. Gunakan versi terbaru. Jika Anda menggunakan klien phpredis, lihat phpredis/phpredis#1600 untuk contoh koneksi.
<?php
require __DIR__.'/predis/autoload.php';
/* Atur informasi koneksi. Ganti nilai host, port, dan password dengan titik akhir instans, nomor port, dan kata sandi.
ApsaraDB-CA-Chain.pem adalah nama file sertifikat. */
$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],
]);
/* Ganti titik akhir dan port dalam kode berikut. */
//$client = new Predis\Client('tls://r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com:6379?ssl[cafile]=ApsaraDB-CA-Chain.pem&ssl[verify_peer]=1');
$client->set("hello", "world");
print $client->get("hello")."\n";
?>C#
Contoh ini menggunakan klien StackExchange.Redis. Gunakan versi terbaru.
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)
{
// Atur informasi koneksi. Ganti nilai host, port, dan password dengan titik akhir instans, nomor port, dan kata sandi.
// ApsaraDB-CA-Chain.pem adalah nama file sertifikat.
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
Contoh ini menggunakan Spring Data Redis versi 2.7.12 (untuk Java 1.8). Gunakan versi terbaru.
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// Simpan konfigurasi sertifikat TLS dalam file properti.
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
Contoh ini menggunakan Lettuce versi 6.2.4.RELEASE. Gunakan versi terbaru.
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
Contoh ini menggunakan klien go-redis v9.5.1. Gunakan v9.0 atau lebih baru.
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, we check the cert in VerifyPeerCertificate
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// Code copy/pasted and adapted from
// https://github.com/golang/go/blob/81555cb4f3521b53f9de4ce15f64b77cc9df61b9/src/crypto/tls/handshake_client.go#L327-L344, but adapted to skip the hostname verification.
// See https://github.com/golang/go/issues/21971#issuecomment-412836078.
// If this is the first handshake on a connection, process and
// (optionally) verify the server's certificates.
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)
}Mode koneksi langsung
Mode ini hanya berlaku untuk instans yang menggunakan arsitektur kluster dengan mode koneksi langsung. Perluas bagian berikut untuk melihat contoh kode.
redis-cli
Saat mengompilasi Redis, tentukan BUILD_TLS=yes untuk mengaktifkan koneksi TLS di redis-cli.
Masuk ke Instance ECS dan jalankan perintah berikut untuk mengunduh, menginstal, dan mengompilasi redis-cli.
sudo yum -y install openssl-devel gcc # Instal dependensi gcc. 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=yesTopik ini menggunakan Redis 7.2.0 sebagai contoh. Anda juga dapat menginstal versi lainnya. Proses kompilasi dan instalasi biasanya memakan waktu 2 hingga 3 menit.
Jalankan perintah berikut di jendela baris perintah untuk menghubungkan ke instans.
./src/redis-cli -h r-bp14joyeihew30****.redis.rds.aliyuncs.com -p 6379 -c --tls --cacert ./ApsaraDB-CA-Chain.pemSetelah parameter cacert, tentukan jalur ke sertifikat CA.
Jalankan perintah berikut untuk menyelesaikan otentikasi kata sandi.
AUTH passwordTanggapan OK menunjukkan bahwa Anda telah terhubung ke instans.
Java
Contoh ini menggunakan Jedis versi 4.3.0. Gunakan versi terbaru.
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{
// Jumlah maksimum koneksi idle. Dalam mode koneksi langsung, klien terhubung langsung ke shard database. Pastikan bahwa nilai (Jumlah mesin bisnis × MaxTotal) lebih kecil dari jumlah maksimum koneksi untuk satu shard database.
jedisPoolConfig.setMaxTotal(30);
// Jumlah maksimum koneksi idle. Atur nilai ini sesuai kebutuhan.
jedisPoolConfig.setMaxIdle(30);
jedisPoolConfig.setMinIdle(15);
// Titik akhir koneksi langsung.
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(); // Saat aplikasi keluar dan sumber daya perlu dihancurkan, panggil metode ini. Metode ini memutuskan koneksi klien dan melepaskan sumber daya.
}
}Python
Contoh ini menggunakan klien redis-py versi 4.3.6 (untuk Python 3.6). Gunakan versi terbaru.
#!/usr/bin/env python
from redis.cluster import RedisCluster
# Ganti nilai host dan port dengan titik akhir instans dan nomor port.
host = 'r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com'
port = 6379
# Ganti nilai user dan pwd dengan akun instans dan kata sandi.
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")
# Setelah koneksi dibuat, Anda dapat melakukan operasi database. Kode berikut memberikan contoh penggunaan SET dan GET.
rc.set('foo', 'bar')
print(rc.get('foo'))
PHP
Contoh ini menggunakan klien phpredis versi 5.3.7. Gunakan versi terbaru.
<?php
// Titik akhir koneksi langsung dan port.
$array = ['r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com:6379'];
// Kata sandi koneksi.
$pwd = "Pas***23";
// Informasi koneksi TLS.
$tls = ["verify_peer" => false, "verify_peer_name" => false];
// Hubungkan ke kluster dengan kata sandi.
$obj_cluster = new RedisCluster(NULL, $array, 1.5, 1.5, true, $pwd, $tls);
// Keluarkan hasil koneksi.
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#
Contoh ini menggunakan klien StackExchange.Redis. Gunakan versi terbaru.
using StackExchange.Redis;
using System;
using System.Linq;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace TairClient
{
class Program
{
static void Main()
{
// Titik akhir koneksi langsung.
const string Host = "r-2zee50zxi5iiqm****.redis.rds-aliyun.rds.aliyuncs.com";
const int Port = 6379;
Console.WriteLine("menghubungkan...");
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));
// Sesuaikan logika validasi lainnya...
return isCertIssuedByTrustedCA;
};
using (var conn = ConnectionMultiplexer.Connect(config))
{
Console.WriteLine("terhubung");
var db = conn.GetDatabase();
db.StringSet("hello", "world");
Console.WriteLine(db.StringGet("hello")); // menulis: world
}
}
private static X509Certificate2 LoadCertificateFromPem(string pemFilePath)
{
// Gunakan metode statis X509Certificate2 untuk memuat sertifikat langsung dari konten PEM.
X509Certificate2 cert = X509Certificate2.CreateFromPem(File.ReadAllText(pemFilePath));
return cert;
}
}
}Spring Data Redis
Contoh ini menggunakan Spring Data Redis versi 2.7.5 (untuk Java 1.8). Gunakan versi terbaru.
Dengan Jedis (disarankan)
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();
// Jumlah maksimum koneksi idle. Dalam mode koneksi langsung, klien terhubung langsung ke shard database. Pastikan nilai dari (Jumlah mesin bisnis × MaxTotal) lebih kecil dari jumlah maksimum koneksi untuk satu shard database.
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;
}
}Dengan Lettuce
import java.io.File;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.SslOptions;
import io.lettuce.core.SslVerifyMode;
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
Contoh ini menggunakan Lettuce versi 6.3.0.RELEASE. Gunakan versi terbaru.
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 diaktifkan, dan tiga parameter dikonfigurasikan sebagai berikut:
* TCP_KEEPIDLE = 30
* TCP_KEEPINTVL = 10
* TCP_KEEPCNT = 3
*/
private static final int TCP_KEEPALIVE_IDLE = 30;
/**
* TCP_USER_TIMEOUT dapat mencegah Lettuce terus-menerus timeout dalam kasus kerusakan.
* referensi: 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)
.withVerifyPeer(SslVerifyMode.CA) // Karena sifat koneksi kluster langsung, SslVerifyMode.FULL tidak dapat digunakan. Anda harus melewati verifikasi nama host.
.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();
// Konfigurasi TCP KeepAlive
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
Contoh ini menggunakan klien go-redis v9.5.1. Gunakan v9.0 atau lebih baru.
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, we check the cert in VerifyPeerCertificate
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// Code copy/pasted and adapted from
// https://github.com/golang/go/blob/81555cb4f3521b53f9de4ce15f64b77cc9df61b9/src/crypto/tls/handshake_client.go#L327-L344, but adapted to skip the hostname verification.
// See https://github.com/golang/go/issues/21971#issuecomment-412836078.
// If this is the first handshake on a connection, process and
// (optionally) verify the server's certificates.
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)
}FAQ
Mengapa saya menerima kesalahan
No subject alternative DNS name matching xxx found?Kesalahan ini terjadi jika Anda mengubah titik akhir instans atau nomor port setelah mengaktifkan TLS. Untuk menyelesaikan masalah ini, perbarui sertifikat TLS di konsol dan coba hubungkan lagi.