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
。