需求
将TIKV、PD添加TLS认证,并且支持go-client添加证书访问;
主要涉及:
1.证书的生成
2.tikv、pd启动参数的修改
3.go-client带上证书访问集群
测试和遇到的问题、注意事项
证书生成
参考:https://docs.pingcap.com/zh/tidb/stable/generate-self-signed-certificates
注意:
1.如果需要给tikv和pd签发不一样的证书,需要注意设置CN(common Name)不一样;当然,也可以使用一样的证书,比如只签发一个名为 pd.crt 的证书,可以让pd和tikv都在配置文件中指定读取 pd.crt ;
2.注意SAN的编辑
官方文档中描述如下:
实际上生产中一定会用到域名(比如一个域名对应一个IP,或者有类似LB的域名),这样就需要在SAN中指定泛域名,例如
[ alt_names ]
IP.1 = 172.16.10.14
DNS.1 = *.tikv.juicefs.xxx.com
其中 172.16.10.14 为机器IP,必须配置;
其他机器证书依赖的配置例如:
[ alt_names ]
IP.1 = 172.16.10.15
DNS.1 = *.tikv.juicefs.xxx.com
正常标准就是给每个节点都颁发一个不一样的证书,即alt_names配置不同的证书
当然,可以看出来,这样很麻烦,每个节点都需要配置一个不一样的证书,所以为了简化(偷懒)可以直接将需要用到的机器的IP都列出来,即
[ alt_names ]
IP.1 = 172.16.10.14
IP.2 = 172.16.10.15
IP.3 = 172.16.10.16
DNS.1 = *.tikv.juicefs.xxx.com
这样就只需要生成一次即可,然后拷贝到其他的机器…
补充:都已经有IP了,为什么需要这个泛域名?
如果只是demo,那么直接全部上IP就搞定了,如果是生产,那么就需要考虑到机器故障、扩容等场景;
例如我们有3个pd节点,3个tikv节点,客户端连的是pd节点(2379端口),那么在pd扩容的时候只要生成新节点的证书即可,新节点的域名符合DNS.1里面的正则即可,可以不需要动老的节点;如果换机器(IP变了),那么只需要修改域名的A记录、为新的节点生成证书即可;
画了个简图,仅供参考:
pd启动配置
nohup /root/deploy/tidb-v5.0.1-linux-amd64/bin/pd-server --name=pd2 \
--data-dir=/root/deploy/tidb-v5.0.1-linux-amd64/pd2 \
--client-urls="https://xx.xx.xx.xx:2379" \
--peer-urls="https://xx.xx.xx.xx:2380" \
--advertise-client-urls="https://node1.juicefs-tikv.sys.xxx.com:2379" \
--advertise-peer-urls="https://node1.juicefs-tikv.sys.xxx.com:2380" \
--initial-cluster="pd1=https://node2.juicefs-tikv.sys.xxx.com:2380,pd2=https://node1.juicefs-tikv.sys.xxx.com:2380,pd3=https://node3.juicefs-tikv.sys.xxx.com:2380" \
--log-file=/root/deploy/tidb-v5.0.1-linux-amd64/pd-logs/pd2.log \
--config="/root/deploy/tidb-v5.0.1-linux-amd64/pd-config-domain.toml" &
pd-config-domain.toml配置文件如下:(用于指定证书位置)
[security]
## Path of file that contains list of trusted SSL CAs. if set, following four settings shouldn't be empty
cacert-path = "/root/tls-tikv/tikv-openssl/root.crt"
## Path of file that contains X509 certificate in PEM format.
cert-path = "/root/tls-tikv/tikv-openssl/pd.crt"
## Path of file that contains X509 key in PEM format.
key-path = "/root/tls-tikv/tikv-openssl/pd.key"
## A CN which must be provided by a client
# cert-allowed-cn = ["client"]
## Whether or not to enable redact log.
# redact-info-log = false
注意其中配置,特别是https
tikv启动配置
nohup /root/deploy/tidb-v5.0.1-linux-amd64/bin/tikv-server --pd-endpoints="https://node1.juicefs-tikv.sys.xxx.com:2379,https://node2.juicefs-tikv.sys.xxx.com:2379,https://node3.juicefs-tikv.sys.xxx.com:2379" \
--addr="xx.xx.xx.xx:20160" \
--advertise-addr="node1.juicefs-tikv.sys.xxx.com:20160" \
--status-addr="xx.xx.xx.xx:20180" \
--advertise-status-addr="node1.juicefs-tikv.sys.xxx.com:20180" \
--data-dir=/var/data/tikv \
--log-file=/root/deploy/tidb-v5.0.1-linux-amd64/tikv-logs/tikv2.log \
--config="/root/deploy/tidb-v5.0.1-linux-amd64/tikv-config-domain.toml" &
tikv-config-domain.toml 配置如下:
[security]
## The path for TLS certificates. Empty string means disabling secure connections.
ca-path = "/root/tls-tikv/tikv-openssl/root.crt"
cert-path = "/root/tls-tikv/tikv-openssl/pd.crt"
key-path = "/root/tls-tikv/tikv-openssl/pd.key"
# cert-allowed-cn = []
#
## Avoid outputing data (e.g. user keys) to info log. It currently does not avoid printing
## user data altogether, but greatly reduce those logs.
## Default is false.
# redact-info-log = false
注意其中配置,特别是https
go-client连接代码
首先贴一下在社区里提的问题:tikv的go-client如何配置tls证书?
关键代码:
func initStore() {
cfg := config.DefaultConfig()
cfg.Security = config.NewSecurity("root.crt", "client.crt", "client.key", []string{})
config.StoreGlobalConfig(&cfg)
client, err = tikv.NewTxnClient([]string{*pdAddr})
}
如果遇到异常:
transport: authentication handshake failed: x509: certificate is not valid for any names, but wanted to match node1.juicefs-tikv.sys.xxxx.com
则是证书的问题,之前alt_names设置泛域名测试没通过,所以临时用了IP,然后client访问pd集群的时候依然使用的域名,则被拒绝了(如上报错),换成IP则可以跑通。
按照上文方法配置好泛域名之后,client使用域名访问pd集群则可以通了。
最后
给tikv、pd增加TLS验证,测试了2天多的时间,本质还是对证书的原理不太清楚,报错信息也没什么具体的信息,导致大量的无效测试。
测试期间特别感谢tikv官方的支持~~
由于缺乏类似的文档,再此分享一下测试遇到的坑和最终的解决方案,希望能帮助到正在给tikv做TLS认证的同学~
如有不正确的理解欢迎指正~