在这篇文章中,您将看到如何使用 SSL(安全套接字层)来保护您的 Redis 数据库。在生产环境中,始终建议使用 SSL 来保护在不同计算机(客户端应用程序和 Redis 服务器)之间移动的数据。传输层安全性 (TLS) 保证只有允许的应用程序/计算机才能连接到数据库,并且数据不会被中间人进程查看或更改。
您可以使用以下方法来保护客户端应用程序和 Redis 集群之间的连接
在这篇文章中,我们将重点介绍双向 SSL 以及 Redis Enterprise。
您可以在 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
这应该打印服务器信息。
假设您可以访问 Redis Enterprise 集群,则需要访问节点以检索证书(默认情况下为自生成的证书)。
集群证书位于:/etc/opt/redislabs/proxy_cert.pem
。
接下来,将集群证书复制到每台客户端机器上;请注意,完成此操作后,您可以使用此证书使用“单向 SSL”进行连接,但这仅仅是本文的目的。
在本教程中,我们将使用 Docker 来复制证书。
docker cp redis-node1:/etc/opt/redislabs/proxy_cert.pem ./certificates
使用双向 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
),没有密码。
下一步是获取证书并将其添加到您要保护的数据库中。
让我们复制证书并将其粘贴到 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
数据库现在受到保护,并且必须使用 SSL 证书才能连接到它。
redis-cli -p 12000 -a secretdb01 INFO SERVER
(error) ERR unencrypted connection is prohibited
在所有这些示例中,您将使用“自签名”证书,因此您无需检查主机名的有效性。您应该根据您的证书配置调整连接/TLS 信息。
要使用 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
使用 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))
对于 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”。
在 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();
}
}
rediss
开头,使用两个 "s" 表示连接应该加密有关更多信息,请参阅文档“使用 Java 连接 Redis”。
在本篇文章中,您学习了如何: