Redis 开启 TLS
实验环境为 Redis 7.0。
让当前节点支持 TLS ,需要添加参数:
tls-port 6380
# 单向 TLS,客户端验证服务端,服务端不需要验证客户端
tls-auth-clients no
tls-cert-file "/etc/redis/tls/server.crt"
tls-key-file "/etc/redis/tls/server.key"
tls-ca-cert-file "/etc/redis/tls/ca.crt"
这个时候,客户端(包括 replica )可以通过 6380 端口进行 TLS 访问。
主从
稍微复杂一点,对于主从结构,需要告诉 replica 节点是否使用 TLS 连接, replica 参数修改:
# master 节点信息
replicaof {MASTER_IP}:{MASTER_TLS_PORT}
# 是否使用 TLS 协议连接 master
tls-replication yes
HA
和 redis 节点类似, sentinel 也支持同时开启非 TLS 和 TLS 端口:
tls-port 26380
tls-auth-clients no
tls-cert-file "/etc/redis/tls/server.crt"
tls-key-file "/etc/redis/tls/server.key"
tls-ca-cert-file "/etc/redis/tls/ca.crt"
同时,可以通过 tls-replication yes 控制 sentinel 访问其他服务的协议:
- 访问
redis服务使用TLS协议 - 访问
sentinel服务使用TLS协议 - 往
master/replica``channel**__sentinel__:hello****发送自身的端口号是 ****TLS**端口
Cluster
cluster 增加了 cluster port ,通过这个端口集群中的节点可以互相交换更新信息。每个节点开启自身的 TLS :
tls-port 6380
# 单向 TLS,客户端验证服务端,服务端不需要验证客户端
tls-auth-clients no
tls-cert-file "/etc/redis/tls/server.crt"
tls-key-file "/etc/redis/tls/server.key"
tls-ca-cert-file "/etc/redis/tls/ca.crt"
需要注意的是,此时可以通过非 TLS 使用集群,但是如果通过 TLS 使用的话, MOOVE 命令会返回 {IP}:{PLAINTEXT_PORT} ,也就是返回非 TLS 端口,这个时候,客户端通过 TLS 重定向到 {IP}:{PLAINTEXT_PORT} 就会出现错误,因为使用 TLS 协议访问非 TLS 端口。
解决办法是:
# cluster port 使用 TLS
tls-cluster yes
这样的话,无论客户端使用 TLS 或者非 TLS ,重定向都会正确:
# TLS 返回 6380 端口
> redis-cli -p 6380
127.0.0.1:6380> cluster nodes
cc79e30de86f3e3382189bdc9bffb871fc681f7b 192.168.3.216:6380@16379 myself,slave 6337cc0f450ecb76cf274f6cacae0058ecd082af 0 1680953046000 3 connected
2b657d5e8d7155d0d1702397142fa6d255d51d42 192.168.3.213:6380@16379 master - 0 1680953043000 2 connected 5461-10922
88ef8e929af72575465a2a16ab76f0e8b1f28778 192.168.3.214:6380@16379 slave 2b657d5e8d7155d0d1702397142fa6d255d51d42 0 1680953045002 2 connected
723e655feda26443d83468811ce714040a1f6115 192.168.3.217:6380@16379 slave ffd94f2da729711752872ff9daaa6da286017ed6 0 1680953043000 1 connected
ffd94f2da729711752872ff9daaa6da286017ed6 192.168.3.212:6380@16379 master - 0 1680953046006 1 connected 0-5460
6337cc0f450ecb76cf274f6cacae0058ecd082af 192.168.3.215:6380@16379 master - 0 1680953043997 3 connected 10923-16383
# 非 TLS 返回 6379 端口
> redis-cli -p 6379
127.0.0.1:6379> cluster nodes
cc79e30de86f3e3382189bdc9bffb871fc681f7b 192.168.3.216:6379@16379 myself,slave 6337cc0f450ecb76cf274f6cacae0058ecd082af 0 1680953061000 3 connected
2b657d5e8d7155d0d1702397142fa6d255d51d42 192.168.3.213:6379@16379 master - 0 1680953064082 2 connected 5461-10922
88ef8e929af72575465a2a16ab76f0e8b1f28778 192.168.3.214:6379@16379 slave 2b657d5e8d7155d0d1702397142fa6d255d51d42 0 1680953063000 2 connected
723e655feda26443d83468811ce714040a1f6115 192.168.3.217:6379@16379 slave ffd94f2da729711752872ff9daaa6da286017ed6 0 1680953063000 1 connected
ffd94f2da729711752872ff9daaa6da286017ed6 192.168.3.212:6379@16379 master - 0 1680953062000 1 connected 0-5460
6337cc0f450ecb76cf274f6cacae0058ecd082af 192.168.3.215:6379@16379 master - 0 1680953063078 3 connected 10923-16383
目前,就可以实现集群内部使用 TLS,外部同时支持两种协议。
主从在集群中也比较特殊,想一下:从节点如何获取主节点的端口。
其实和上面很像,如果 tls-cluster yes 返回 6380 ,否则返回 6379 。
这个时候就需要注意 tls-replication 这个配置,它决定了 replica 使用什么协议连接 master :
- 为
no,且tls-cluster yes,那么使用非 TLS 连接master的6380端口,自然连接不上。 - 为
yes,且tls-cluster yes,那么使用 TLS 连接master的6380端口,正常。
所以设置 tls-cluster yes 时,需要设置 tls-replication yes 。
一个有意思的现象:如果查看 cluster config 文件:
-
tls-cluster yes时,里面所有节点的IP显示的都是6380 -
tls-cluster no时,里面所有节点的IP显示的都是6379
那么问题来了,既然 cluster config 存的就是 cluster nodes 信息,那为什么上文执行 cluster nodes 可以根据客户端是否通过 TLS 连接返回不同的端口呢?
cluster config 中每一行对应 clusterNode 对象:
typedef struct clusterNode {
mstime_t ctime; /* Node object creation time. */
char name[CLUSTER_NAMELEN]; /* Node name, hex string, sha1-size */
int flags; /* CLUSTER_NODE_... */
uint64_t configEpoch; /* Last configEpoch observed for this node */
unsigned char slots[CLUSTER_SLOTS/8]; /* slots handled by this node */
uint16_t *slot_info_pairs; /* Slots info represented as (start/end) pair (consecutive index). */
int slot_info_pairs_count; /* Used number of slots in slot_info_pairs */
int numslots; /* Number of slots handled by this node */
int numslaves; /* Number of slave nodes, if this is a master */
struct clusterNode **slaves; /* pointers to slave nodes */
struct clusterNode *slaveof; /* pointer to the master node. Note that it
may be NULL even if the node is a slave
if we don't have the master node in our
tables. */
unsigned long long last_in_ping_gossip; /* The number of the last carried in the ping gossip section */
mstime_t ping_sent; /* Unix time we sent latest ping */
mstime_t pong_received; /* Unix time we received the pong */
mstime_t data_received; /* Unix time we received any data */
mstime_t fail_time; /* Unix time when FAIL flag was set */
mstime_t voted_time; /* Last time we voted for a slave of this master */
mstime_t repl_offset_time; /* Unix time we received offset for this node */
mstime_t orphaned_time; /* Starting time of orphaned master condition */
long long repl_offset; /* Last known repl offset for this node. */
char ip[NET_IP_STR_LEN]; /* Latest known IP address of this node */
sds hostname; /* The known hostname for this node */
int port; /* Latest known clients port (TLS or plain). */
int pport; /* Latest known clients plaintext port. Only used
if the main clients port is for TLS. */
int cport; /* Latest known cluster port of this node. */
clusterLink *link; /* TCP/IP link established toward this node */
clusterLink *inbound_link; /* TCP/IP link accepted from this node */
list *fail_reports; /* List of nodes signaling this as failing */
} clusterNode;
-
port:tls-cluster为no时保存非TLS端口,否则保存TLS端口 -
pport:tls-cluster为no时不使用,否则保存非TLS端口 -
cport:保存cluster port
cluster config 一直保存着 port 这个值,但是如果执行 cluster nodes 会根据客户端的协议以及 tls-cluster 选择返回 port 还是 pport 。