前言
本文分享如何在 OceanBase 里开启加密连接(SSL)。
以前的文章有介绍应用连接 OceanBase 时会通过一个反向代理 OBProxy。所以跟 OceanBase 建立加密连接,实际是跟 OBProxy 建立加密连接,然后 OBProxy 跟 OBServer 再建立加密连接。相比传统数据库简单的 CS 模式,分布式数据库的加密连接细节会更复杂一些,或者更有趣一些。
OBProxy 可以有多个,每个 OBProxy 可以独立设置是否接受加密连接以及是否跟 OBServer 发起加密连接。OBProxy 的位置也不固定。可以在 OBServer 上,也可以在应用服务器上,或者在应用服务器跟 OB 服务器网络之间任意服务器上。如果 OBProxy 都在应用服务器,自然 OBProxy 没必要开启客户端 SSL 连接;如果 OBProxy 都在 OBServer 服务器上,也没必要开启服务端服务端 SSL 连接(后面会发现这句不完全对!);如果 OBProxy 服务器位置不可靠,则 OBProxy 可能要同时开启客户端 SSL 连接和服务端 SSL 连接。
下面中间过程比较复杂,也可以直接跳转到文章末尾处的结论。
加密的原因和技术
客户端和服务端普通的 TCP 连接可能在网络上被拦截或篡改进而不安全。对称加密连接里,客户端和服务端使用相同的密钥对来回通信的内容进行加密和解密,大大提升了安全性。但是密钥如何分发到客户端是一个问题。
非对称加密连接里,客户端使用服务端公钥对自己的随机字符串加密发送给服务端,服务端使用私钥解密得到客户端的随机字符串并作为后面对称加密连接的密钥使用。非对称加密算法解决了对称加密算法的密钥发送问题,但有一个问题就是客户端如何确信拿到的公钥是服务端的公钥。
客户端和服务端都会认同一个第三方权威机构( CA),保存有 CA 的公钥。服务端把公钥发给 CA ,CA用私钥进行加密再还给服务端,服务端得到自己公钥的密文(签名),然后发给客户端。客户端验证服务端的公钥和CA签名的一致。
所以加密技术会牵扯到 CA、公钥和私钥。
创建 CA 、证书和密钥。
- 创建 RSA 私钥
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -outform PEM -out cakey.pem
说明:
genpkey : 生成私钥参数。
-algorithm alg—— 使用公钥算法如RSA,DSA或DH。如果使用此选项,则必须位于任何-pkeyopt选项之前。-paramfile和-algorithm选项是互斥的。
-pkeyopt opt:value——设置公钥算法选项选择值。
-outform PEM|DER——输出格式
-out filename——输出文件名。
- 生成 CA 证书
openssl req -new -x509 -nodes -days 3600 -key cakey.pem -keyform PEM -out ca.pem
说明:
req 命令:主要创建证书请求(可以新生成私钥),查看证书请求。它可以创建自签名证书,以作为root CA使用。但不能读取证书。
-new ——本选项产生一个新的证书请求,它会要用户输入创建证书请求的一些必须的信息。
-x509 —— 此选项输出自签名证书。这通常用于生成测试证书或自签名根证书。添加到证书的扩展项(如果有)在配置文件中指定。除非使用set_serial选项,否则将使用较大的随机数作为序列号。
-days n —— 当使用-x509选项时,指定证书的有效期。默认为30天。
-key filename —— 指定从中读取私钥的文件。它也读取PEM格式的PKCS#8私钥
-keyform PEM|DER ——在-key参数中指定的读入的私钥文件的格式。默认 PEM
- 生成服务端证书
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey cakey.pem -set_serial 01 -out server-cert.pem
说明:
req命令 :主要创建证书请求(可以新生成私钥),查看证书请求。它可以创建自签名证书,以作为root CA使用。但不能读取证书。
-newkey arg——用于生成新的私钥以及证书请求。arg 可以是下列:
rsa:nbits ——其中nbits是比特数,指明生成一个RSA密钥的长度。
-nodes——如果指定了此选项,创建私钥时则不会对其进行加密
-set_serial n—— 输出自签名证书时使用的序列号。
rsa 命令: RSA密钥管理。处理RSA密钥、格式转换和打印信息
x509 命令:本指令是一个功能很丰富的证书处理工具。可以用来显示证书的内容,转换证书格式,给证书请求签名,也可自签根证书等等
- 生成客户端证书
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey cakey.pem -set_serial 01 -out client-cert.pem
注意这里录入客户端名字信息时写入的是 OBPROXY。即把 OBPROXY 当做 OB 集群的客户端。应用连接 OB 集群是通过 OBPROXY 间接实现的。这里就不考虑直连 OBSERVER 的客户端了(指连接 2881 端口)。
- 验证服务端证书和客户端证书有效性
openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
这一步是关键。如果证书验证不过,就是前面生成证书的时候一些信息填写不对。注意服务端和客户端证书中的证书适用的机器名称不要重复。
分发证书
再看看生成的所有证书和密钥文件。
- 查看客户端证书
openssl x509 -in client-cert.pem -noout -text
其中 SUBJECT 的内容(Subject: C=CN, ST=ZJ, L=HZ, O=OB, OU=SA, CN=OBPROXY
)后面有用到。
- 测试服务器规划
- 将服务端证书复制到 OBServer 机器的工作目录
observer 的证书默认放在工作目录 /home/admin/oceanbase/wallet
中。
OBS="observer01
observer02
observer03
"
for ob in $OBS;do echo $ob; scp ca.pem server-cert.pem server-key.pem admin@$ob:~/oceanbase/wallet/ ; done
- 将客户端证书复制到 OBProxy 的工作目录
客户端证书文件放在 OBProxy 的工作目录下的 wallet 里,跟 bin 文件夹同级。
OBPROXYS="172.30.118.66
172.26.154.55
"
for obp in $OBPROXYS;do echo $obp; ssh admin@$obp "mkdir -p /opt/taobao/install/obproxy/wallet/"; \
scp ca.pem client-cert.pem client-key.pem admin@$obp:/opt/taobao/install/obproxy/wallet/ ; \
ssh admin@$obp "ls -lrth /opt/taobao/install/obproxy/wallet/"; done
- 将客户端证书复制到纯客户端机器任意目录。比如说 /home/admin/client/
scp ca.pem client-cert.pem client-key.pem admin@172.26.154.54:~/client/
创建数据库账户
使用加密连接还需要在 OB 里创建用户并指定用户的 SSL 认证机制。OceanBase 支持下面三种认证机制:
- SSL 单向认证
服务器端需要 CA 证书, 客户端不需要提供 CA 证书。客户端单向校验服务器端证书的有效性。
- X509 双向认证
服务器端和客户端都需要 CA 证书, 服务器端和客户端双向校验证书的有效性。
- 特殊的双向认证
(可组合):
指定加密算法认证:基于 X509 双向认证, 同时限定 SSL 加密算法。
指定发行方认证:基于 X509 双向认证, 同时限定客户端 CA 证书发行方。
指定 SSL 主题认证:基于 X509 双向认证, 同时限定客户端 CA 证书主题。
create user tpcc identified by 123456;
grant connect,resource to tpcc;
-- SSL单向认证
create user tpcc_ssl identified by 123456 require ssl ;
grant connect,resource to tpcc_ssl;
-- X509双向认证
create user tpcc_x509 identified by 123456 require x509 ;
grant connect,resource to tpcc_x509;
create user tpcc_cs identified by 123456 require CIPHER 'DHE-RSA-AES128-GCM-SHA256'
SUBJECT '/C=CN/ST=ZJ/L=HZ/O=OB/OU=SA/CN=OBPROXY';
grant connect,resource to tpcc_cs;
-- 查看用户属性
select user_name, ssl_type,ssl_cipher, x509_issuer, x509_subject
from SYS.ALL_VIRTUAL_USER_AGENT
where user_name like 'TPCC%';
开启 OBPROXY 客户端 SSL 认证
默认情况下 OBPROXY 只接受普通的连接,以及跟 OBSERVER 连接的时候也只发起普通连接。OBPROXY 有参数 enable_client_ssl
和 enable_server_ssl
分别开启客户端和服务端 SSL 连接。
mysql -h172.30.118.67 -uroot@proxysys -P2883 -p -e "alter proxyconfig set enable_client_ssl=true; show proxyconfig like 'enable_client_ssl'; "
mysql -h172.26.154.55 -uroot@proxysys -P2883 -p -e "alter proxyconfig set enable_client_ssl=true; show proxyconfig like 'enable_client_ssl'; "
当 OBPROXY 开启客户端 SSL 认证时,就可以接收客户端连接时传入的 SSL 相关认证信息。
测试 01 :只开启客户端 SSL 认证,看用户连接情况
obclient -h172.30.118.67 -P2883 -u tpcc@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.30.118.67 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.30.118.67 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
结论:
单纯的开启 OBPROXY 的客户端 SSL 连接,普通的用户还是能连接。需要 SSL 认证的用户不能连接。原因有多个。首先服务端 OBSERVER 要能接受客户端 SSL 认证。
开启 OB 集群的客户端 SSL 认证
参数 ssl_client_authentication
在 OB 集群里,默认接受的普通的连接。通过集群参数 ssl_client_authentication
控制是否打开客户端 SSL 认证。这个参数的修改是需要重启整个 OB 集群的。
ALTER SYSTEM SET ssl_client_authentication=true;
-- 等 3 秒
SHOW parameters LIKE '%ssl_client_authentication%';
alter system set _ob_ssl_invited_nodes='ALL';
重启集群的办法有很多。一个是挨个的杀掉每个节点的 observer 进程并重新拉起,或者在 OCP 里重启。
为减少重启集群后节点的恢复时间,建议先对集群发起一个大合并操作。在 root@sys
下操作。
- 验证集群以 SSL 运行
select svr_ip, svr_port,zone, ssl_key_expired_time, from_unixtime(ssl_key_expired_time/1000000) expired_time
from oceanbase.__all_virtual_server_stat;
集群重启好后,再次重跑 测试案例 001,结果不变。可见还有别的原因跟 SSL 认证有关。
参数 ob_ssl_invited_common_names
除了开启参数 ssl_client_authentication
外,还需要设置 SSL 白名单。这个是通过参数 ob_ssl_invited_common_names
。其值是前面生成证书时用的Subject 里的名称。
这个参数是租户级别的,需要在要连接的租户里设置,立即生效,不需要重启实例或者集群。
用业务租户的管理员账户登录业务租户里设置。
ALTER SYSTEM SET ob_ssl_invited_common_names='OBPROXY';
--等 1 秒
SHOW parameters LIKE 'ob_ssl_invited_common_names';
在客户端 obclient 命令里加上 SSL 认证参数试试。
obclient -h172.30.118.67 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
obclient -h172.30.118.67 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
提示:ERROR 2026 (HY000): SSL connection error: SSL is required but the server doesn't support it .
结论:
客户端 obclient 带上 SSL 认证信息连接 OBPROXY 时失败了,原因是 OBPROXY 没有开启服务端 SSL 认证,不能跟 OBSERVER 进行 SSL 通信。
开启 OBPROXY 服务端 SSL 认证
OBPROXY 参数enable_server_ssl
用于开启服务端 SSL 认证。
下面对服务器 66 和 55 开启服务端 SSL 认证。
mysql -h172.30.118.66 -uroot@proxysys -P2883 -p -e "alter proxyconfig set enable_server_ssl=true; show proxyconfig like '%ssl%'; "
mysql -h172.26.154.55 -uroot@proxysys -P2883 -p -e "alter proxyconfig set enable_server_ssl=true; show proxyconfig like '%ssl%'; "
对 OBPROXY 除了开启参数 enable_server_ssl
外,还需要更新内部元数据,指定 SSL 认证相关信息。(这个方法太不方便,估计以后会改进)
update proxyconfig.security_config
set CONFIG_VAL= '{"sourceType" : "FILE", "CA" : "wallet/ca.pem", "publicKey" : "wallet/client-cert.pem", "privateKey" : "wallet/client-key.pem"}'
where APP_NAME = 'obproxy_poc' and VERSION = '1';
select * from proxyconfig.security_config
where APP_NAME = 'obproxy_poc';
测试02:开启 OBPROXY 服务端 SSL 认证
- 连接只开启服务端 SSL 认证的OBPROXY
obclient -h172.30.118.66 -P2883 -u tpcc@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.30.118.66 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.30.118.66 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.30.118.66 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
obclient -h172.30.118.66 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
结论:
普通的用户正常登录。
SSL 单向或者双向认证的用户走 OBPROXY 连接 OB 集群正常登录。
SSL 单向或者 X509 双向认证的用户走 OBPROXY 并提供 SSL 认证信息,连接 OB 集群失败。因为该 OBPROXY 不支持客户端 SSL 认证。
查看客户端 SSL 信息,在 OBPROXY 里使用 \s
命令
obclient -h172.30.118.66 -P2883 -u tpcc@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.30.118.66 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.30.118.66 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.26.154.55 -P2883 -u tpcc@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.26.154.55 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.26.154.55 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;"
obclient -h172.26.154.55 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
obclient -h172.26.154.55 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
obclient -h172.26.154.55 -P2883 -u tpcc_cs@obbmsql#obdemo -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
结论: 所有情形都正常登录。
查看客户端 SSL 信息,在 OBPROXY 里使用 \s
命令
obclient -h172.26.154.55 -P2883 -u tpcc@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.26.154.55 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.26.154.55 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -s -e "\s" |egrep "SSL|Connection" -B4
obclient -h172.26.154.55 -P2883 -u tpcc_ssl@obbmsql#obdemo -p123456 -c -s -e "\s" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem \
| egrep "SSL|Connection" -B4
obclient -h172.26.154.55 -P2883 -u tpcc_x509@obbmsql#obdemo -p123456 -c -s -e "\s" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem \
| egrep "SSL|Connection" -B4
结论:
当 OBPROXY 开启客户端和服务端 SSL 认证时,不管客户端 obclient 是否提供 SSL 认证,OBPROXY 都会建立连接的时候带上 SSL 认证信息。
OB集群里查看客户端 SSL 连接信息
OB 集群的 sys 租户可以集中查看所有租户的连接的 SSL 信息。
select id,USER,tenant,host,db,command,time,state,info,svr_ip,user_client_ip,ssl_cipher
from oceanbase.__all_virtual_processlist
WHERE tenant='obbmsql'
ORDER BY USER, time ;
直连 OB 集群
测试 03:指定 SSL 认证信息直连 OB 集群后端节点。
obclient -h172.23.152.221 -P2881 -u tpcc@obbmsql -p123456 -c -e "select sysdate from dual;"
obclient -h172.23.152.221 -P2881 -u tpcc_ssl@obbmsql -p123456 -c -e "select sysdate from dual;"
obclient -h172.23.152.221 -P2881 -u tpcc_x509@obbmsql -p123456 -c -e "select sysdate from dual;"
obclient -h172.23.152.221 -P2881 -u tpcc_ssl@obbmsql -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
obclient -h172.23.152.221 -P2881 -u tpcc_x509@obbmsql -p123456 -c -e "select sysdate from dual;" \
--ssl-ca=client/ca.pem --ssl-cert=client/client-cert.pem --ssl-key=client/client-key.pem
结论:
普通用户和 SSL 单向认证的用户建立连接都正常。
SSL 单向认证的用户建立连接时,提供客户端 SSL 相关信息也能够连接。
X509 双向认证的用户建立连接时,必须提供客户端 SSL 相关信息才能连接。
结论
客户端连接 OB 实例时,实际是通过 OBPROXY 连接。
要建立一个 SSL 连接首先要服务端 OB 集群开启 SSL 客户端认证(需要重启集群),然后在业务租户上创建 SSL 认证用户。大部分加密数据库连接场景只需要创建单向 SSL 认证用户即可。然后业务实例设置一个 SSL 认证白名单(实时生效)。该白名单跟所有客户端证书中 Subject 中 CN 值有关。注意,普通的用户连接不受 SSL 认证限制。
OBPROXY 作为客户端和服务端链路中间重要的一环,是客户端的“服务端”,也是 OB 服务端的“客户端”。所以需要同时开启“客户端 SSL 认证”和“服务端 SSL 认证”。如果只开了一边,使用效果就不对了。推而广之,如果应用客户端到 OBPROXY 中间还有其他软硬件产品(比如说 F5 或者 LVS 等),则 F5 或 LVS 也要开启 SSL 认证才能保证整个 SSL 认证和加密连接畅通。
下面是结论图。