学习

如何在 Redis Enterprise 中使用 SSL/TLS

在这篇文章中,您将看到如何使用 SSL(安全套接字层)来保护您的 Redis 数据库。在生产环境中,始终建议使用 SSL 来保护在不同计算机(客户端应用程序和 Redis 服务器)之间移动的数据。传输层安全性 (TLS) 保证只有允许的应用程序/计算机才能连接到数据库,并且数据不会被中间人进程查看或更改。

您可以使用以下方法来保护客户端应用程序和 Redis 集群之间的连接

  • 单向 SSL:客户端(您的应用程序)从服务器(Redis 集群)获取证书,验证它,然后所有通信都被加密
  • 双向 SSL:(也称为双向 SSL)客户端和服务器都相互验证并验证两端都是可信的。

在这篇文章中,我们将重点介绍双向 SSL 以及 Redis Enterprise。

先决条件#

  • Redis Enterprise 6.0.x 数据库,(我的数据库受密码 secretdb01 保护,并监听端口 12000
  • redis-cli 用于运行基本命令
  • NodeJava 如果您想测试各种语言,则已安装。

简单测试#

步骤 1. 运行 Redis 服务器#

您可以在 Docker 容器中或直接在您的机器上运行 Redis 服务器。使用以下命令在 Mac OS 上本地设置 Redis 服务器

 brew tap redis-stack/redis-stack
 brew install --cask redis-stack
信息

Redis Stack 统一并简化了领先 Redis 模块及其提供的功能的开发者体验。除了 Redis 之外,Redis Stack 还支持以下内容:JSON、Search、Time Series、Triggers and Functions 以及概率数据结构。

让我们确保数据库可用

redis-cli -p 12000 -a secretdb01 INFO SERVER

这应该打印服务器信息。

步骤 2. 从 Redis 集群获取证书#

假设您可以访问 Redis Enterprise 集群,则需要访问节点以检索证书(默认情况下为自生成的证书)。

集群证书位于:/etc/opt/redislabs/proxy_cert.pem

接下来,将集群证书复制到每台客户端机器上;请注意,完成此操作后,您可以使用此证书使用“单向 SSL”进行连接,但这仅仅是本文的目的。

在本教程中,我们将使用 Docker 来复制证书。

docker cp redis-node1:/etc/opt/redislabs/proxy_cert.pem ./certificates

步骤 3. 生成新的客户端证书#

使用双向 SSL,您需要为客户端提供一个证书,该证书将被 Redis 数据库代理用来信任客户端。在本教程中,我们将使用 OpenSSL 生成自签名证书。我们将为名为 app_001 的应用程序创建证书。请注意,您可以根据需要创建任意数量的证书,或将此证书用于所有服务器/应用程序。

打开终端并运行以下命令

openssl req \
  -nodes \
 -newkey rsa:2048 \
 -keyout client_key_app_001.pem \
 -x509 \
 -days 36500 \
 -out client_cert_app_001.pem

此命令生成一个新的客户端密钥 (client_key_001.pem) 和证书 (client_cert_001.pem),没有密码。

步骤 4. 配置 Redis 数据库#

下一步是获取证书并将其添加到您要保护的数据库中。

让我们复制证书并将其粘贴到 Redis Enterprise Web 控制台中。

将证书复制到剪贴板

Mac

pbcopy < client_cert_app_001.pem

Linux

 xclip -sel clip < client_cert_app_001.pem

Windows

clip < client_cert_app_001.pem

转到 Redis Enterprise 管理 Web 控制台,并在您的数据库上启用 TLS

  1. 1.编辑数据库配置
  2. 2.选中 TLS
  3. 3.选择“对所有通信强制使用 TLS”
  4. 4.选中“强制执行客户端身份验证”
  5. 5.将证书粘贴到文本区域
  6. 6.单击“保存”按钮保存证书
  7. 7.单击“更新”按钮保存配置。

数据库现在受到保护,并且必须使用 SSL 证书才能连接到它。

redis-cli -p 12000 -a secretdb01 INFO SERVER
(error) ERR unencrypted connection is prohibited

步骤 5. 使用证书连接到数据库#

在所有这些示例中,您将使用“自签名”证书,因此您无需检查主机名的有效性。您应该根据您的证书配置调整连接/TLS 信息。

步骤 5.1 使用 Redis-CLI#

要使用 redis-cli 连接到受 SSL 保护的数据库,您必须使用 stunnel

创建一个 stunnel.conf 文件,内容如下

cert = /path_to/certificates/client_cert_app_001.pem
key = /path_to/certificates/client_key_app_001.pem
cafile = /path_to/certificates/proxy_cert.pem
client = yes

[redislabs]
accept = 127.0.0.1:6380
connect = 127.0.0.1:12000

使用以下命令启动 stunnel

stunnel ./stunnel.conf

这将启动一个监听端口 6380 的进程,并用作 Redis Enterprise 数据库的代理,端口为 12000

redis-cli -p 6380 -a secretdb01 INFO SERVER

步骤 5.2 使用 Python#

使用 Python,您必须设置 SSL 连接参数

#!/usr/local/bin/python3

import redis
import pprint

try:
  r = redis.StrictRedis(
    password='secretdb01',
    decode_responses=True,
    host='localhost',
    port=12000,
    ssl=True,
    ssl_keyfile='./client_key_app_001.pem',
    ssl_certfile='./client_cert_app_001.pem',
    ssl_cert_reqs='required',
    ssl_ca_certs='./proxy_cert.pem',
    )

  info = r.info()
  pprint.pprint(info)

except Exception as err:
  print("Error connecting to Redis: {}".format(err))

步骤 5.3 使用 Node.JS#

对于 Node Redis,使用 TLS 库来配置客户端连接:

var redis = require('redis');
var tls = require('tls');
var fs = require('fs');

var ssl = {
  key: fs.readFileSync(
    '../certificates/client_key_app_001.pem',
    {encoding: 'ascii'},
  ),
  cert: fs.readFileSync(
    '../certificates/client_cert_app_001.pem',
    {encoding: 'ascii'},
  ),
  ca: [fs.readFileSync('../certificates/proxy_cert.pem', {encoding: 'ascii'})],
  checkServerIdentity: () => {
    return null;
  },
};

var client = redis.createClient(12000, '127.0.0.1', {
  password: 'secretdb01',
  tls: ssl,
});

client.info('SERVER', function (err, reply) {
  console.log(reply);
});

有关更多信息,请参阅文档“使用 Redis 与 Node.js”。

步骤 5.4 使用 Java#

在 Java 中,要能够使用 SSL 连接,您必须使用 keytool 实用程序将所有证书安装到 Java 环境中。

创建一个 **keystore** 文件,用于存储您之前创建的密钥和证书

openssl pkcs12 -export \
  -in ./client_cert_app_001.pem \
  -inkey ./client_key_app_001.pem \
  -out client-keystore.p12 \
  -name "APP_01_P12"

如您所见,keystore 用于存储与您的客户端关联的凭据;它将在以后与 Java 应用程序中的 -javax.net.ssl.keyStore 系统属性一起使用。

除了密钥存储外,您还需要创建一个信任存储,用于存储其他凭据,例如本例中的 Redis 集群证书。

创建一个**信任存储**文件,并将 Redis 集群证书添加到其中。

keytool -genkey \
  -dname "cn=CLIENT_APP_01" \
  -alias truststorekey \
  -keyalg RSA \
  -keystore ./client-truststore.p12 \
  -keypass secret
  -storepass secret
  -storetype pkcs12
keytool -import \
  -keystore ./client-truststore.p12 \
  -file ./proxy_cert.pem \
  -alias redis-cluster-crt

信任存储将在 Java 应用程序中与 -javax.net.ssl.trustStore 系统属性一起使用。

现在,您可以使用以下环境变量运行 Java 应用程序。

java -Djavax.net.ssl.keyStore=/path_to/certificates/java/client-keystore.p12 \
-Djavax.net.ssl.keyStorePassword=secret \
-Djavax.net.ssl.trustStore=/path_to/certificates/java/client-truststore.p12 \
-Djavax.net.ssl.trustStorePassword=secret \
-jar MyApp.jar

为了简单起见,我将在 Java 代码中直接硬编码这些属性。


import redis.clients.jedis.Jedis;
import java.net.URI;

public class SSLTest {

    public static void main(String[] args) {

        System.setProperty("javax.net.ssl.keyStore", "/path_to/certificates/client-keystore.p12");
        System.setProperty("javax.net.ssl.keyStorePassword", "secret");

        System.setProperty("javax.net.ssl.trustStore","/path_to/certificates/client-truststore.p12");
        System.setProperty("javax.net.ssl.trustStorePassword","secret");

        URI uri = URI.create("rediss://127.0.0.1:12000");

        Jedis jedis = new Jedis(uri);
        jedis.auth("secretdb01");


        System.out.println(jedis.info("SERVER"));
        jedis.close();
    }

}
  • 第 8-12 行,系统环境变量被设置为指向密钥存储和信任存储(这应该外部化)
  • 第 14 行,Redis URL 以 rediss 开头,使用两个 "s" 表示连接应该加密
  • 第 17 行,设置数据库密码

有关更多信息,请参阅文档“使用 Java 连接 Redis”。

结论#

在本篇文章中,您学习了如何:

  • 检索 Redis 服务器证书
  • 生成客户端证书
  • 保护数据库以强制执行传输层安全 (TLS),并使用双向身份验证
  • 使用 redis-cli、Python、Node 和 Java 连接到数据库

参考资料#