文档

客户端程序TLS(SSL)加密连接Redis

更新时间:

在使用客户端程序连接数据库时,您可以启用TLS(SSL)加密功能提高数据链路的安全性,保障数据的完整性。您可以根据自身应用特点选用任何兼容Redis协议的客户端程序。本文列举一些常见的客户端程序的代码示例,帮助您快速连接。

前提条件

  • 实例已开启TLS(SSL)加密,具体操作参见开启TLS加密

  • 客户端部署在与Redis实例相同专有网络(VPC)的ECS实例上。

注意事项

  • 实例开启TLS加密功能后,不支持申请公网连接地址、直连地址,客户端仅能通过专有网络连接实例。

  • 如果实例为集群架构读写分离架构,实例默认会提供Proxy(代理)节点的连接地址,连接方式与连接标准架构的Tair实例相同。

  • 如果实例开启了专有网络免密访问,同一专有网络下的客户端程序无需设置密码即可连接实例。

准备工作

  1. 将客户端所在的ECS内网IP地址添加至Redis实例的白名单中,具体操作请参见设置白名单

  2. 获取以下信息并设置在客户端程序的代码中:

    需获取的信息

    获取方式

    实例的连接地址

    Redis实例支持多种连接地址,推荐使用专有网络连接,可获得更高的安全性和更低的网络延迟。更多信息,请参见查看连接地址

    端口号

    端口号默认为6379,您也可以自定义端口号。具体操作,请参见修改连接地址或端口

    实例的账号(部分客户端程序无需设置)

    Redis实例默认会创建一个以实例ID命名的账号(例如r-bp10noxlhcoim2****),您也可以创建一个新的账号并赋予权限。更多信息,请参见创建与管理账号

    账号的密码

    根据选取账号的不同,密码的填写格式有一定区别:

    • 默认账号(以实例ID命名的账号):直接填写密码即可。

    • 新创建的账号:密码格式为<user>:<password>。例如自定义账号为testaccount,密码为Rp829dlwa,密码需填写为testaccount:Rp829dlwa

    说明
    • 如果通过第三方数据库管理工具(例如RDM等)连接Redis实例,请在密码框中输入user:password进行连接。

    • 如果忘记密码,您可以重置密码。具体操作,请参见修改或重置密码

  3. 下载CA证书,请参见开启TLS加密

redis-cli

您需要在编译Redis时,指定BUILD_TLS=yes,才能在redis-cli中启用TLS连接Redis实例

  1. 登录ECS实例,下载、安装redis-cli。

    1. 执行下述命令,安装相关依赖。

      yum install openssl-devel gcc
    2. 执行下述命令下载Redis源码文件。

      wget https://download.redis.io/releases/redis-7.0.0.tar.gz
      说明

      本文以redis-7.0.0版本为例演示操作流程,您也可以安装其他版本。具体操作,请参见Redis官网

    3. 执行下述命令解压Redis源码文件。

      tar xzf redis-7.0.0.tar.gz
    4. 执行下述命令进入解压后的目录,编译安装Redis源码文件并开启TLS。

      cd redis-7.0.0&&make BUILD_TLS=yes

      编译安装需要一段时间(通常为2分钟~3分钟)。

  2. 在命令行窗口执行下述命令连接实例。

    ./src/redis-cli -h r-bp14joyeihew30****.redis.rds.aliyuncs.com -p 6379 --tls --cacert ./ApsaraDB-CA-Chain.pem

    cacert后需指定CA证书的路径。

  3. 执行下述命令完成密码验证。

    AUTH password

    显示OK表示已成功连接实例。

Java

下述示例代码以Jedis 3.6.0版本为例,推荐使用最新版本。

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为证书文件名称。
        final SSLSocketFactory sslSocketFactory = createTrustStoreSSLSocketFactory("ApsaraDB-CA-Chain.jks");
        // 连接池的设置分别为实例的连接地址、端口号、超时设置、密码。
        JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com",
            6379, 2000, "redistest:Test1234", 0, true, sslSocketFactory, null, null);

        try (Jedis jedis = pool.getResource()) {
            jedis.set("key", "value");
            System.out.println(jedis.get("key"));
        }
    }
}

Python

下述示例代码以redis-py客户端为例,推荐使用最新版本。

连接池连接

#!/bin/python
import redis

# 设置连接池,分别将host、port、password的值分别替换为实例的连接地址、端口号、密码。
# ApsaraDB-CA-Chain.pem为证书文件名称。
pool = redis.ConnectionPool(connection_class=redis.connection.SSLConnection, max_connections=100,
                            host="r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com", port=6379, password="redistest:Test1234",
                            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")

普通连接

#!/bin/python
import redis

# 设置连接信息,分别将host、port、password的值分别替换为实例的连接地址、端口号、密码。
# ApsaraDB-CA-Chain.pem为证书文件名称。
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客户端为例,推荐使用最新版本。如果您使用的是phpredis客户端,连接示例请参见此issue

<?php

require __DIR__.'/predis/autoload.php';

/* 设置连接信息,分别将host、port、password的值分别替换为实例的连接地址、端口号、密码
ApsaraDB-CA-Chain.pem为证书文件名称*/
$client = new Predis\Client([
    'scheme' => 'tls',
    'host'   => 'r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com',
    'port'   => 6379,
    'password' => 'redistest:Test1234',
    'ssl'    => ['cafile' => 'ApsaraDB-CA-Chain.pem', 'verify_peer' => true],
]);
/* 依次替换下述代码中的连接地址和端口 */
//$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#

以下示例以StackExchange.Redis客户端为例,推荐使用最新版本。

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)
        {
          // 设置连接信息,分别将host、port、password的值分别替换为实例的连接地址、端口号、密码。
          // ApsaraDB-CA-Chain.pem为证书文件名称。
            ConfigurationOptions config = new ConfigurationOptions()
            {
                EndPoints = {"r-bp10q23zyfriodu*****.redis.rds.aliyuncs.com:6379"},
                Password = "redistest:Test1234",
                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版本)为例,推荐使用最新版本。

@Configuration
public class RedisConfig {
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        // 建议您将TLS证书配置存放在properties文件中。
        String host = "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com";
        int port = 6379;
        String password = "xxx";
        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版本为例,推荐使用最新版本。

public class SSLExample {
    public static void main(String[] args) throws Exception {
        String host = "r-bp1zxszhcgatnx****.redis.rds.aliyuncs.com";
        int port = 6379;
        String password = "xxxx";
        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"));

    }
}

  • 本页导读 (1)
文档反馈