1. Ceph认证回顾
上一篇ceph认证文章讲到客户端从monitor获取service ticket,然后使用tick访问service组件服务,service组件从monitor获取属于自己的service secret对ticket进行解密认证.
service secret内容比较多,值得我们用一篇文章详细介绍。
2. service secret
service secret是用来加解密service ticket的,由monitor生成,monitor会为每个service组件维护一个id和service secret的对应关系。1
2
3
4id 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创建1
2
3
4
5
6
7
8
9bool 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。
这里的过期时间由下面两个配置决定1
2auth_mon_ticket_ttl // auth 过期时长12小时
auth_service_ticket_ttl // osd,mon,mds,mgr service服务过期时长1小时
假设monitor中osd rotate secret开始如下1
2
3id=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’时,就会启动轮转更新1
2
3id=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是否过期来确认更新。1
MonClient::tick --> MonClient::_check_auth_tickets --> auth->need_tickets
这里的判断过期比较有意思。ticket里面包含有此ticket的过期时长,这是由monitor的这两个配置决定.1
2auth_mon_ticket_ttl // auth 过期时长12小时
auth_service_ticket_ttl // osd,mon,mds,mgr service服务过期时长1小时
利用此过期时长,然后基于客户端节点本机时间,计算出过期时间点。判断过期用的客户端时间和此过期时间点。1
客户端本机当前时间 + 过期时长 = 客户端过期时间点
可以看出客户端service ticket的过期时间和客户端本机时间紧密相关。如果和monitor时间不一致,则可能存在问题。
前面’auth_mon_ticket_ttl’是用于一个auth的rotate secret,客户端更新rotate service id就是用auth的ticket跟monitor进行认证。
2.5 service组件服务反馈更新
service组件服务也是通过包含的monc模块里面的周期性tick进行检测过期时间是否要更新1
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,会出现我们经常看到的错误1
cephx: verify_authorizer could not get service secret for service mds secret_id=17408
时间 | 客户端 | mon | osd |
---|---|---|---|
14点 | 2(本地12点) | 1,2,3 | 1,2,3 |
15点 | 2(本地13点) | 2,3,4 | 2,3,4 |
16点 | 2(本地14点) | 3,4,5 | 3,4,5 |
17点 | 5(本地15点) | 4,5,6 | 4,5,6 |
18点 | 6(本地16点) | 5,6,7 | 5,6,7 |
19点 | 7(本地15点) | 6,7,8 | 6,7,8 |
20点 | 8(本地15点) | 7,8,9 | 7,8,9 |
1、2、3等代表service secret id,可以看出在刚开始调整的时候比如在16点到17点,osd会认证报错,因为客户端拿了老的secret id。在17点之后,客户端开始更新,后面不会出现osd认证报错,客户端会以本地时间不同更新。
3.2 客户端时间比monitor时间快
把客户端时间调快2个小时,比如从14点调到16点,时间调快,没有影响,客户端会提前去mon更新。
时间 | 客户端 | mon | osd |
---|---|---|---|
14点 | 2(本地16点) | 1,2,3 | 1,2,3 |
15点 | 3(本地17点) | 2,3,4 | 2,3,4 |
16点 | 4(本地18点) | 3,4,5 | 3,4,5 |
17点 | 5(本地19点) | 4,5,6 | 4,5,6 |
18点 | 6(本地20点) | 5,6,7 | 5,6,7 |
19点 | 7(本地21点) | 6,7,8 | 6,7,8 |
20点 | 8(本地22点) | 7,8,9 | 7,8,9 |
3.3 serivce服务比monitor时间慢
这里service服务以osd为例,mds、mgr类似,service服务侧是接受整个rotate secret,所以它里面的过期时间是rotate secret生成服务器mon的时间,跟客户端使用本机时间不同,那如果时间调后两个小时,比如从原来的14点,调整到12点。
时间 | 客户端 | mon | osd |
---|---|---|---|
14点 | 2 | 1,2,3 | 1,2,3 (本地12点) |
15点 | 3 | 2,3,4 | 1,2,3 (本地13点) |
16点 | 4 | 3,4,5 | 1,2,3(本地14点) |
17点 | 5 | 4,5,6 | 4,5,6 (本地15点) |
18点 | 6 | 5,6,7 | 4,5,6 (本地16点) |
19点 | 7 | 6,7,8 | 4,5,6 (本地17点) |
20点 | 8 | 7,8,9 | 7,8,9 (本地18点) |
可以看出16点到17点,19点到20点,osd拥有的rotate secret偏旧,导致客户端认证失败。
3.4 service服务比monitor时间快
把service服务调快2个小时,比如从14点调到16点,时间调快,没有影响,service服务会提前去mon更新,
时间 | 客户端 | mon | osd |
---|---|---|---|
14点 | 2 | 1,2,3 | 1,2,3 (本地16点) |
15点 | 3 | 2,3,4 | 2,3,4 (本地17点) |
16点 | 4 | 3,4,5 | 3,4,5(本地18点) |
17点 | 5 | 4,5,6 | 4,5,6 (本地19点) |
18点 | 6 | 5,6,7 | 5,6,7 (本地20点) |
19点 | 7 | 6,7,8 | 6,7,8 (本地21点) |
20点 | 8 | 7,8,9 | 7,8,9 (本地22点) |
虽然提前更新但是还是按mon的节奏来更新。
4. ‘部分关闭’Cephx
有时候由于时间偏差或者其他原因导致客户端和service组件的连接认证失败问题,经常想关闭cephx,但又想使用用户认证,那能否部分关闭cephx。这里有两种想法:部分关auth三配置、延长过期时间
4.1 部分关auth三配置
Ceph认证可以部分关闭吗,我们配置文件中经常会配这三个1
2
3auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
比如把auth_cluster_required设置成none,答案是绝对不能,这三个配置要么都设置为none,要么有设置为cephx。这三个配置总结一下1
2
3auth_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配置1
auth_service_ticket_ttl = 31536000 // 1年
这个配置需要对所有monitor进行修改,而客户端和service服务不需要修改,因为客户端的ticket只返回过期时长,这个时长就是从monitor的auth_service_ticket_ttl获取。而service组件服务在判断需要是否过期时,最多超过current rotate secret过期时间30s就更新,对auth_service_ticket_ttl大于120s都一样。1
2
3
4
5
6
7
8
9
10
11
12int 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过期时间有跳变1
2
32022-05-25 11:36:26 // pre
2022-05-25 12:36:26 // current
2022-05-25 13:36:26 // next
默认一个小时,如果过期修改成1年,则会在当前时间超过current时修改成如下1
2
32022-05-25 12:36:26 // pre
2022-05-25 13:36:26 // current
2024-05-24 13:36:26 // next
next是新增的rotate secret,这里过期增加了2年, 主要是如下导致1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16int 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,观察日志如下1
2
3
4
5
6
7
8
9
10
11
122022-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次tick1
2第一个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认证讨论告一段落。