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認證討論告一段落。