Ceph认证的三层含义(下)
1. Ceph认证回顾
service secret内容比较多,值得我们用一篇文章详细介绍。
2. service secret
service secret是用来加解密service ticket的,由monitor生成,monitor会为每个service组件维护一个id和service secret的对应关系。
id service secret 1 key1 2 key2 3 key3
这表示一个service服务所拥有的的service secret列表,每个service服务都会有这样一个列表。返回给客户端的ticket包含有id,这样客户端在和service组件进行连接认证时根据id来确定使用哪个service secret对ticket进行解密。
之所以会有列表主要是针对时间进行更新,所以也称service secret为rotate secrets。rotate顾名思义就是可以轮转,由monitor的authmonitor负责,我们看一下它是如何存储、创建、更新以及反馈更新。
2.1 存储形式
每一行代表一个servic服务组件的secret,任意时刻只存在三个secret,如红虚线框中。每个service的rotate secrets是由一个数组维护,同时每一个rotating secret都会包含一个过期时间。
2.2 创建
rotating secrets是在monitor启动时,由authmonitor通过start_server创建
bool KeyServer::_check_rotating_secrets() { ... added += _rotate_secret(CEPH_ENTITY_TYPE_AUTH); added += _rotate_secret(CEPH_ENTITY_TYPE_MON); added += _rotate_secret(CEPH_ENTITY_TYPE_OSD); added += _rotate_secret(CEPH_ENTITY_TYPE_MDS); added += _rotate_secret(CEPH_ENTITY_TYPE_MGR); ... }
可以看出authmonitor会为auth、mon、osd、mds、mgr生成rotate secret,secret_id从1开始,其中auth service的过期时间是12小时,其他service的过期时间是1小时,其中auth service主要是用来对monclient请求更新其他service ticket时进行认证,刚开始的时候会生成三个时刻secret,previous、current、next分别代表过去、当前、未来可用于加密的secret。
2.3 更新
authmonitor在tick的时候会周期检查rotate secret有没有过期,过期就进行相应的调整,如果current rotate secret过期时间比当前时间小就表示已经过期,需要创建一个新的rotate secret,并将原来的current变成pre,原来的next变成current,新生成的作为next,以维持只保留三个secret。
这里的过期时间由下面两个配置决定
auth_mon_ticket_ttl // auth 过期时长12小时 auth_service_ticket_ttl // osd,mon,mds,mgr service服务过期时长1小时
假设monitor中osd rotate secret开始如下
id=1 expire_time=2022-05-25 11:36:26 // pre id=2 expire_time=2022-05-25 12:36:26 // current id=3 expire_time=2022-05-25 13:36:26 // next
上面的时间就是对应rotate secret的过期时间,当monitor的时间超过’2022-05-25 12:36:26’时,就会启动轮转更新
id=2 expire_time=2022-05-25 12:36:26 // pre id=3 expire_time=2022-05-25 13:36:26 // current id=4 expire_time=2022-05-25 14:36:26 // next
此便是更新后的rotate secret。
2.4 客户端反馈更新
客户端需要rotate secret id来告知service组件服务使用的rotate secret,随着monitor更新rotate secret,客户端的rotate secret id也需要更新,也即需要更新ticket。客户端包含的monc模块有一个周期性的tick,通过检查所持有的service ticket是否过期来确认更新。
MonClient::tick --> MonClient::_check_auth_tickets --> auth->need_tickets
这里的判断过期比较有意思。ticket里面包含有此ticket的过期时长,这是由monitor的这两个配置决定.
auth_mon_ticket_ttl // auth 过期时长12小时 auth_service_ticket_ttl // osd,mon,mds,mgr service服务过期时长1小时
利用此过期时长,然后基于客户端节点本机时间,计算出过期时间点。判断过期用的客户端时间和此过期时间点。
客户端本机当前时间 + 过期时长 = 客户端过期时间点
可以看出客户端service ticket的过期时间和客户端本机时间紧密相关。如果和monitor时间不一致,则可能存在问题。
前面’auth_mon_ticket_ttl’是用于一个auth的rotate secret,客户端更新rotate service id就是用auth的ticket跟monitor进行认证。
2.5 service组件服务反馈更新
service组件服务也是通过包含的monc模块里面的周期性tick进行检测过期时间是否要更新
MonClient::tick --> MonClient::_check_auth_tickets --> MonClient::_check_auth_rotating
service服务判断过期跟客户端不一样,因为service服务是从monitor获取的rotate secret,这里面包含有在rotate secret的过期时间点,这个时间点是在monitor按monitor节点时间计算的。所以service服务判断过期用的是service服务节点时间跟monitor计算出来的过期时间点。
3. 时间不一致
客户端和service服务如果跟monitor时间存在不一致,会有什么影响。
3.1 客户端时间比monitor时间慢
把客户端时间调慢2个小时,比如从14点调到12点,原来ticket有效时间是14点到15点(默认一个小时),此时把本机时间调慢到12点,在本机时间达到13点的时候(其实真实时间是15点),此时本应向mon发送更新ticket,但是本机时间判断为未过期,而osd已经获取了新的rotate secret,如果客户端和osd连接断开,重建连接时,客户端用的老的secret id访问osd,会出现我们经常看到的错误
cephx: verify_authorizer could not get service secret for service mds secret_id=17408
时间客户端monosd14点2(本地12点)1,2,31,2,315点2(本地13点)2,3,42,3,416点2(本地14点)3,4,53,4,517点5(本地15点)4,5,64,5,618点6(本地16点)5,6,75,6,719点7(本地15点)6,7,86,7,820点8(本地15点)7,8,97,8,9
1、2、3等代表service secret id,可以看出在刚开始调整的时候比如在16点到17点,osd会认证报错,因为客户端拿了老的secret id。在17点之后,客户端开始更新,后面不会出现osd认证报错,客户端会以本地时间不同更新。
3.2 客户端时间比monitor时间快
把客户端时间调快2个小时,比如从14点调到16点,时间调快,没有影响,客户端会提前去mon更新。
时间客户端monosd14点2(本地16点)1,2,31,2,315点3(本地17点)2,3,42,3,416点4(本地18点)3,4,53,4,517点5(本地19点)4,5,64,5,618点6(本地20点)5,6,75,6,719点7(本地21点)6,7,86,7,820点8(本地22点)7,8,97,8,9
3.3 serivce服务比monitor时间慢
这里service服务以osd为例,mds、mgr类似,service服务侧是接受整个rotate secret,所以它里面的过期时间是rotate secret生成服务器mon的时间,跟客户端使用本机时间不同,那如果时间调后两个小时,比如从原来的14点,调整到12点。
时间客户端monosd14点21,2,31,2,3 (本地12点)15点32,3,41,2,3 (本地13点)16点43,4,51,2,3(本地14点)17点54,5,64,5,6 (本地15点)18点65,6,74,5,6 (本地16点)19点76,7,84,5,6 (本地17点)20点87,8,97,8,9 (本地18点)
可以看出16点到17点,19点到20点,osd拥有的rotate secret偏旧,导致客户端认证失败。
3.4 service服务比monitor时间快
把service服务调快2个小时,比如从14点调到16点,时间调快,没有影响,service服务会提前去mon更新,
时间客户端monosd14点21,2,31,2,3 (本地16点)15点32,3,42,3,4 (本地17点)16点43,4,53,4,5(本地18点)17点54,5,64,5,6 (本地19点)18点65,6,75,6,7 (本地20点)19点76,7,86,7,8 (本地21点)20点87,8,97,8,9 (本地22点)
虽然提前更新但是还是按mon的节奏来更新。
4. ‘部分关闭’Cephx
有时候由于时间偏差或者其他原因导致客户端和service组件的连接认证失败问题,经常想关闭cephx,但又想使用用户认证,那能否部分关闭cephx。这里有两种想法:部分关auth三配置、延长过期时间
4.1 部分关auth三配置
Ceph认证可以部分关闭吗,我们配置文件中经常会配这三个
auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx
比如把auth_cluster_required设置成none,答案是绝对不能,这三个配置要么都设置为none,要么有设置为cephx。这三个配置总结一下
auth_client_requested主要用于client和osd、mds、mgr组件连接认证发送端。 auth_service_requested主要用于client和osd、mds、mgr组件连接认证接收端。 auth_cluster_requester主要用于mon、mds、mgr、osd组件连接认证发送端和接收端。
这三个相互依赖,如果开启了auth_client_required,就需要auth_service_required,service组件更新rotate secret就需要auth_cluster_required。
4.2 延长过期时间
客户端和service组件的连接认证失败往往是客户端的ticket包含的rotate secret id比较老,或者service服务的rotate secret没有更新比较老,那如果把service secret过期时间延迟,比如一个rotate secret过期时长设置个1年,那1年内客户端和service组件都不需要更新。
4.2.1 配置调整
配置主要更超时时长相关的ttl配置
auth_service_ticket_ttl = 31536000 // 1年
这个配置需要对所有monitor进行修改,而客户端和service服务不需要修改,因为客户端的ticket只返回过期时长,这个时长就是从monitor的auth_service_ticket_ttl获取。而service组件服务在判断需要是否过期时,最多超过current rotate secret过期时间30s就更新,对auth_service_ticket_ttl大于120s都一样。
int MonClient::_check_auth_rotating() { ... utime_t now = ceph_clock_now(); utime_t cutoff = now; cutoff -= MIN(30.0, cct->_conf->auth_service_ticket_ttl / 4.0); // 这里使用ttl的四分之一和30s取min ... if (!rotating_secrets->need_new_secrets(cutoff)) { ... } ... }
4.2.2 过期时间跳变
rotate secret过期时间可能存在跳变,比如原来rotate secret过期时间有跳变
2022-05-25 11:36:26 // pre 2022-05-25 12:36:26 // current 2022-05-25 13:36:26 // next
默认一个小时,如果过期修改成1年,则会在当前时间超过current时修改成如下
2022-05-25 12:36:26 // pre 2022-05-25 13:36:26 // current 2024-05-24 13:36:26 // next
next是新增的rotate secret,这里过期增加了2年, 主要是如下导致
int KeyServer::_rotate_secret(uint32_t service_id) { ... while (r.need_new_secrets(now)) { ... if (r.empty()) { ek.expiration = now; } else { utime_t next_ttl = now; next_ttl += ttl; //增加第一个1年 ek.expiration = MAX(next_ttl, r.next().expiration); } ek.expiration += ttl; //增加第二个1年 uint64_t secret_id = r.add(ek); ... }
4.2.3 auth_mon_ticket_ttl可配
除了auth_service_ticket_ttl,过期配置之前还有auth_mon_ticket_ttl,默认配置是auth_mon_ticket_ttl比auth_service_ticket_ttl大,但是其实可以保持不变,它主要用于auth rotate secret的过期更新。
这里实验如下设置auth rotate secret过期时间5s,service rotate secret过期时间20s,而monc的tick是10s一次,在tick检测是不是要更新rotate secret id,观察日志如下
2022-05-25 16:21:43.039333 7f03d93c7700 10 monclient: tick 2022-05-25 16:21:43.039362 7f03d93c7700 10 cephx: validate_tickets want 38 have 6 need 32 2022-05-25 16:21:43.039379 7f03d93c7700 10 cephx: validate_tickets want 38 have 6 need 32 2022-05-25 16:21:43.040284 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 0 2022-05-25 16:21:43.040288 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 0 2022-05-25 16:21:53.039616 7f03d93c7700 10 monclient: tick 2022-05-25 16:21:53.039645 7f03d93c7700 10 cephx: validate_tickets want 38 have 6 need 38 2022-05-25 16:21:53.039665 7f03d93c7700 10 cephx: validate_tickets want 38 have 6 need 38 2022-05-25 16:21:53.040435 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 6 2022-05-25 16:21:53.040439 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 6 2022-05-25 16:21:53.040914 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 0 2022-05-25 16:21:53.040917 7f03da3c9700 10 cephx: validate_tickets want 38 have 38 need 0
一共进行了2次tick
第一个tick发现auth的rotate过期了,发送到mon获取新的auth rotate secret id 第二个tick发现auth 、osd 、mds的rotate过期了,先发送mon获取新的auth rotate secret id,然后发送mon获取新的service rotate secret id(带上获取的新的auth rotate secret id)
auth rotate secret过期小于service rotate secret的情况下,当service rotate secret过期时,auth也过期了,所以会先获取新的auth rotate secret id,因此auth rotate secret的过期时间可以改,也可以不改。
以上Ceph认证讨论告一段落。
