在本文中,我将解释如何使用 SSL (安全套接字层) 保护您的 Redis 数据库。在生产环境中,使用 SSL 保护在不同计算机(客户端应用程序和 Redis 服务器)之间传输的数据是一种最佳实践。传输层安全 (TLS) 保证只有允许的应用程序/计算机才能连接到数据库,并且数据不会被中间人进程查看或更改。
您可以使用以下方法保护客户端应用程序和 Redis 集群之间的连接
在本文中,我将重点介绍双向 SSL 以及使用 Redis Enterprise。
先决条件
secretdb01
保护,并在端口 12000
上监听)redis-cli
用于运行基本命令简单测试
让我们确保数据库可用
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 库配置客户端连接:
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”。
在 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();
}
}
rediss
开头,带有 2 个 s,表示连接应该被加密更多信息请参见文档“使用 Java 连接 Redis”。
在这篇文章中,你学习了如何
redis-cli
、Python、Node 和 Java 连接数据库