keystone 認證深度研究分析
一、Keystone Token深度概述
Keystone作為OpenStack項目基礎認證模塊,目前支持的token類型分別是uuid、pkiz、pki、fernet。
首先,簡要敘述一下這四種類型的原理及其優缺點。
uuid 比較簡單,采用隨機生成的序列(128位,以16進制表示)作為id,並構造token內容,需要持久化後端數據庫支撐,比如MySQL數據庫存儲。優點,實現簡單;缺點是持久化查詢、每次訪問都需要keystone相關服務進行認證。
pki(pkiz) 基於cms算法,token格式以PKIZ_開頭,pki類的token 長度很長(pkiz只是對pki進行了一定程度的壓縮),它將所有token的內容都放在了token中,並且認證不需要與keystone服務交互,直接采用相關的證書進行本地認證,這類似與傳統的U盾技術,但是密鑰是在keystone處生成好了之後,是不能夠進行實時更新的,安全性相對較低,一旦被破解,相關的信息將被暴露,此時,如果對密鑰進行更新,將導致前面生成的token不可用。它的缺陷在於,沒有密鑰的周期性更替機制(安全性大打折扣),同時,負載太大,部分rest接口,不能處理超長請求。在生產環境中,極不推薦這種方式。
fernet 是當前主流推薦的token格式,這種方式相較於前幾種類型,是當前比較均衡的一種方式。它不需要後端持久化存儲,與pki類似,但是在認證上,仍然需要與keystone進行交互。它的token結構,采用了特定的數理結構設計(包括socoped類型、user信息等等),結合加密技術,重要的優點是它的輪詢替換算法。簡要敘述一下fernet密鑰的原理,默認的輪換長度是3,當以keystone-manage fernet-setup生成密鑰時,會看到0、1兩個索引表征,這分別是什麽意思呢?在此,需要提一下三個概念,primary key(主密鑰,用於加密、解密token)、secondary key(次次密鑰,用於解密token)、staged key(次密鑰,用於解密token),那麽上述0 表示的是staged key,1 表示的是primary key,primary key相比較另外兩種key,它的索引最高,並且可以加密、也可以解密;staged key 相較於secondary key是它更有機會變為primary key。也就是說,fernet的密鑰不是不變的,並且可以周期性輪轉,不同認證節點之間的更新頻次可以相差1。這安全性大大提高,keystone 進行認證的時候,依賴於這些密鑰進行解密,從而進一步實現認證。
在分析了上述四種token格式後,毋庸置疑,fernet是比較靠譜,且性能相對較優的格式。但是,如果僅從這些分析上,不足以保證fernet的優勢,說服力還不夠。下面兩節,將分別從認證原理、及歷史經驗數據上做探究分析。fernet是當前比較合適的方式,這並不表示fernet就是最優的token方式。在後面的分析上,盡可能提出更優的方案。
二、openstack認證
Openstack項目的認證技術,除了與keystone認證服務相關,也離不開眾多的中間件的處理,如典型的keystone/middleware。首先,任何的服務在使用之前都需要獲取token,token的生成,按照各種token的格式,uuid是存儲在持久化後端數據庫中,其他方式采用加密技術,token ID中包含了token數據的信息。有了token後,所有服務在發送請求時,需要將token ID作為請求字段,否則,直接拋出異常。而token ID的認證,主要依賴於中間件組件的處理。在下一小節中,重點說明。
在介紹認證原理之前,必須明確幾個概念,cache、revoke、service-token、user-token、expiration,其中cache就是緩存,在keystone中常用的緩存工具是memcache,它在內存中開辟一塊空間,用於存放token,優點不用多說,會大大縮短獲取token的時間,並且驗證時間也縮短了;revoke是回收機制,keystone中的token過期回收機制,會根據token的過期時間作響應或者人為主動發出的token回收請求;service-token在請求頭中用X-Service-Token表示,是M版後,keystone認證所改進的技術,它主要是區分普通的用戶的請求和服務請求,區分的原因是引入了過期token的使用,P版將會更加強化這一概念,並且過期token的使用,只發生在服務請求中;user-token就是普通用戶的請求,在請求頭中用X-Auth-Token表示;expiration,即過期時間,在keystone中有兩處過期的概念:token的過期時間、cache的過期時間。簡要敘述一下,cache的過期時間的設定,一般我們認為,cache存儲的時間越久越好,但是cache的容量有限,並且,它占據著內存的空間,因此cache內存的大小實際存在一個理論上的“極值”設定,超過了這個大小,將會影響服務的響應處理,除了這一點,另外就是過期時間,考慮到過期token,即使存儲在cache中,它也認證不通過,但是,如果cache中不存在的話,需要keystone服務去獲取並且驗證,這個開銷比存儲在cache中的開銷要大。雖然如此,考慮一種高壓情況,cache的存儲,我們希望有效的token存儲越多越好,過期的token,我們只存儲一個index值,這樣不會占據太多的空間,並且認證過程中,很快能夠檢測出過期token。在下一段的改進性能優化上,進一步說明。
正式進入openstack認證原理的介紹。openstack的項目,依賴於keystone項目進行認證,借助於中間件的處理.Token包括兩部分,分別是token ID、token Data,token Data是核心,包括用戶的信息、角色信息、服務信息、服務入口等等。Openstack認證,首先去cache中,查詢是否存在對應的Token,如果存在,則進一步驗證token是否被回收。此流程很簡單;如果cache中不存在的話,keystone服務會去獲取token的信息,並調用對應的driver去驗證token,不同格式的token處理上有些差異,pki(pkiz)直接本地認證即可;其它兩種方式都需要和keystone服務交互。如果獲取並認證通過了,則需要將token的信息加入到cache中,否則,認證不通過,返回結果。具體流程,如下圖所示。
三、結合實際探究分析
回顧歷史經驗數據,曾經做過一個壓力測試,驗證token的抗壓能力,uuid、fernet、pkiz的模式,得出的結論是fernet相對結果較好。我們的測試用例是nova list,這個結果,現在來看的話,有著它的必然性。能想到的keystone認證的瓶頸,主要是token 過期時間、cache的大小、時長、服務的worker數、數據庫的性能。
fernet的數據性能最好,原因是它不需要後端持久化操作,並且token的認證,使用的是密鑰進行解密,能夠直接得出token Data的信息,從而進行token的過期認證,它的失敗原因,只可能是token過期了,或者是token放到了cache中,但是已經被回收了。歸根到底,還是token過期了。之前做的壓測,設置的work數是8個,所以,當壓力達到3千以上的時候,進程本身有一定的負載上限,因此在處理上,會出現多數的等待,我們看到獲取token的那條命令,出錯概率相對較低,原因是生成token的流程,沒有後端數據庫的操作,因此,比較流暢。有部分出錯了,原因是由於請求等待時間過長,如果一直沒有進程在處理,那麽將會拋出獲取token時的認證異常。其它出錯,在認證時候的異常,原因是由於壓力增多,導致一條請求的處理流程被拉長,token的過期時間也設置的較短,並且也存在請求長時間沒有得到處理而拋出的認證異常。因此,當我們增加服務節點或者提高work數的時候,壓力問題會得到有效的緩解。
Pki系列的性能也不太好,原因就是token長度太長。雖然它采用的是自認證的方式,在請求傳遞過程中的負載,將會消耗很大的時間,並且采用cache的方式,會導致命中出現問題,因為cache有大小上限,因此,很容易出現之前已經存在於cache的token,會被替換出去,從而影響後續的認證流程。它的請求傳遞開銷,是它致命的缺陷。抗壓能力較弱(此處說的是只有一臺服務器的情況下)。
uuid的實現簡單,但是抗壓能力,是比較差的,因為它涉及大部分的持久化操作,數據庫的性能直接影響壓力測試的結果。常規情況下,我們不會單獨再用一臺數據庫節點,因此,數據庫性能不會很高,並且當數據庫達到一定壓力的時候,本身連接數據庫就會變得很慢。
在上述分析中,我們從歷史數據得出的部分解答。從近期的調研分析來看,openstack的服務在使用之前都需要認證,認證如果變得很快,那麽openstack整體的服務性能將大大提升。認證過程中,除了增加服務數的方法、提高服務進程數外,token的cache命中率,也是有效提高認證的方法之一。除此之外,可信認證的充分利用,比如將某些服務發送的請求,去掉部分認證的環節,尤其是過期token的引入。
四、性能提升
為了提升token的認證能力,假設我們的使用場景是抗壓能力測試,沒有其他操作幹擾,還是以nova list作為測試用例,我們以rest接口作為測試方法,沒有超時限制,fernet作為token的格式,並且將token的時長調大,理論上只要token過期時長足夠大,成功率,應該是能夠達到100%。如果針對這個測試用例,非要找出出錯的可能性,只可能出現在token過期。當我們引入過期token可再使用時,那麽成功率將更加有保障。
在上述分析中,我們得出影響性能的幾個關鍵因素:服務能力數(認證服務節點數量)、服務進程數(worker數量)、token的格式、cache的大小設置,cache策略。
服務能力數,即設置多少臺服務節點是合適的,這個問題,需要考慮實際部署的機器的性能,因此,我們只有通過測試,這個值的大小大致是可以確定的。我們可以通過rest請求的響應時間作為參考值,我們需要提前預估一下響應時間的最大時間,即用戶能夠接受的時長,這個也是分請求的,比如創建虛機的請求,它涉及多個流程,它的響應時長的設置,應該是每個子操作響應時長的總合,因此,我們只需要設計好原子操作的響應時長。當合理的原子請求不能在規定的時間內得到響應,說明服務器服務需要優化,資源需要增加。因此,rest請求的響應能力,是判定服務能力的重要的參考依據。我們可以通過壓力測試,找到服務能力的數值。
服務進程數,當服務器性能允許的情況下,這個數值越大,表示服務能力越強。但是,當進程太多,會拖慢機器的性能,這個值,在理論上也存在極值。一般情況下,我們開啟32 或者64進程。具體的檢測方法同上。也可以通過rest請求的壓力測試得出。
token的格式,從上述的幾種token的邏輯處理上,毋庸置疑,fernet的優勢非常明顯。
cache的大小設置,如果條件允許,並且token會被多次利用的概率較大,cache大小設置大一點。另外,在實際的生產環境中,獲取了token後,95%的情況下,token會需要被驗證,因此,token的改進措施,就是在生成了token後,就可以將token加入到cache中,這樣在驗證的時候,直接可以通過cache機制認證。這一點需要一定的cache大小空間的支撐,在下面的cache策略中再詳述。
cache策略,在當前keystone服務中,token認證通過了,會被加入到cache中。token過期或者達到緩存時長,將會從cache中移除。如果token被回收,存儲在cache中token會被標記為Invalid Token。Keystone發展到O版,service-token引入,並且允許過期token的使用,在私有雲環境下,尤其是內部使用的項目,在cache策略上,service-token認證的流程,應該可以簡化,甚至註釋掉。但是,前面的策略只是某些個列情況下,當前比較優化的方案是,當token生成了後,直接將token放入cache中,在正常的業務流程中,該token會被用來發送請求。這樣的話,在壓力負載較大的情況下,優勢會比較明顯。
以上僅是個人的觀點,如有問題,請及時與我探討分析。
keystone 認證深度研究分析