学习

如何在 Redis Enterprise 中使用 SSL/TLS

Tugdual Grall
作者
Tugdual Grall, Redis 前技术营销经理

在本文中,我将解释如何使用 SSL (安全套接字层) 保护您的 Redis 数据库。在生产环境中,使用 SSL 保护在不同计算机(客户端应用程序和 Redis 服务器)之间传输的数据是一种最佳实践。传输层安全 (TLS) 保证只有允许的应用程序/计算机才能连接到数据库,并且数据不会被中间人进程查看或更改。

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

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

在本文中,我将重点介绍双向 SSL 以及使用 Redis Enterprise。

先决条件

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

简单测试

让我们确保数据库可用

redis-cli -p 12000 -a secretdb01 INFO SERVER

这将打印服务器信息。

1- 从 Redis 集群获取证书#

如果您有权访问 Redis Enterprise 集群,您可以转到其中一个节点检索证书(默认情况下它是自生成的)。

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

您必须将其复制到每个客户端机器上;请注意,完成此操作后,您可以使用此证书使用“单向 SSL”进行连接,但这并非本文的重点。

在我的演示中,我使用 Docker 并在我的主机上使用以下命令复制证书

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

2- 生成新的客户端证书#

使用双向 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),且不使用密码。

3- 配置 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

4- 使用证书连接到数据库#

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

4.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

4.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))

4.3 使用 Node.JS#

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

import { createClient } from 'redis';
import tls from 'tls';
import fs from 'fs';

const 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;
  },
};

const client = redis.createClient({
  // replace with your connection string
  url: 'rediss://localhost:12000',
  socket: {
    tls: true,
    key: ssl.key,
    cert: ssl.cert,
    ca: ssl.ca,
  },
});

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

await client.connect();

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

4.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 集群证书。

创建一个 trust store 文件,并将 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

trustore 将在以后与 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 开头,带有 2 个 s,表示连接应该被加密
  • 第 17 行,设置数据库密码

更多信息请参见文档“使用 Java 连接 Redis”。

总结#

在这篇文章中,你学习了如何

  • 获取 Redis 服务器证书
  • 生成客户端证书
  • 通过双向身份验证保护你的数据库,以强制执行传输级安全 (TLS)
  • 从 redis-cli、Python、Node 和 Java 连接数据库
上次更新于 2024 年 2 月 23 日