keystone令牌三種生成方式


keystone認證方式:UUID、PKI、Fernet;

知識點復習:

通俗的講,token 是用戶的一種憑證,需拿正確的用戶名/密碼向 Keystone 申請才能得到。如果用戶每次都采用用戶名/密碼訪問 OpenStack API,容易泄露用戶信息,帶來安全隱患。所以 OpenStack 要求用戶訪問其 API 前,必須先獲取 token,然后用 token 作為用戶憑據訪問 OpenStack API。 

公開密鑰加密,也稱為非對稱加密(asymmetric cryptography,加密密鑰和解密密鑰不相同),在這種密碼學方法中,需要一對密鑰,分別為公鑰(Public Key)和私鑰(Private Key),公鑰是公開的,私鑰是非公開的,需用戶妥善保管。如果把加密和解密的流程當做函數 C(x) 和 D(x),P 和 S 分別代表公鑰和私鑰,對明文 A 和密文 B 而言,數學的角度上有以下公式:

B = C(A, S)

A = D(B, P)

其中加密函數 C(x), 解密函數 D(x) 以及公鑰 P 均是公開的。采用公鑰加密的密文只能用私鑰解密,采用私鑰加密的密文只能用公鑰解密。非對稱加密廣泛運用在安全領域,諸如常見的 HTTPS,SSH 登錄等。

數字簽名又稱為公鑰數字簽名,首先采用 Hash 函數對消息生成摘要,摘要經私鑰加密后稱為數字簽名。接收方用公鑰解密該數字簽名,並與接收消息生成的摘要做對比,如果二者一致,便可以確認該消息的完整性和真實性。

(1)UUID認證原理:

當用戶需要進行操作時(比如訪問nova創建虛擬機),用戶拿着有效的用戶名/密碼先去keystone認證,keystone返回給用戶一個token(即UUID)。之后用戶進行其他操作(如訪問nova),先出示這個token給nova-api,nova收到請求后,就用這個token去向keystone進行請求驗證。keystone通過比對token,以及檢查token的有效期,判斷token的有效性,最后返回給nova結果。

缺陷:每次請求都要經過keystone進行驗證,造成性能瓶頸。

 

 

1.用戶輸入用戶名密碼,發送給keystone。

2.Keystone驗證用戶名密碼,並且生成token(UUID),發送給客戶端。

3.客戶端緩存UUID token

4.客戶端發送具體的執行請求(nova boot)和UUID給keystone。

5.Keystone從http請求中獲取token,並檢查token是否有效

6.Token有效,處理請求,並返回客戶端請求結果

7.Token失效,拒絕客戶端請求,返回401。

UUID方式源碼分析:

UUID token 是長度固定為 32 Byte 的隨機字符串,由 uuid.uuid4().hex 生成。

def _get_token_id(self, token_data):    return uuid.uuid4().hex

 

生成的樣例:144d8a99a42447379ac37f78bf0ef608

(2)PKI認證原理:

在keystone初始化時,keystone生成了CA的公鑰CA.pem和私鑰CA.key,同時keystone產生了自己的公鑰keystone.pub和私鑰keystone.key,然后將keystone.pub進行CA的簽名,生成keystone.pem。

當用戶拿着用戶名/密碼去keystone認證后,keystone將用戶的基本信息通過keystone.key進行加密,並將密文作為token返還給用戶。當用戶拿着token發送請求時(例如訪問nova),nova拿到用戶token時,通過事先拿到keystone的證書keystone.pem(這一過程只需要進行一次)進行解密,獲取用戶信息。

對於用戶的token,還需進行token的合法時間,以及token還是否存在進行判斷。所以當nova每一次拿到token后還需向keystone詢問一次token的失敗列表,檢查token是否失效。這一過程對於keystone的負載還是相當輕的,所以PKI還是有效解決了keystone性能瓶頸的問題。

小結:OpenStack服務中的每一個API Endpoint都有一份keystone簽發的證書,失效列表和根證書。API不用在直接去keystone認證token是否合法,只需要根據keystone的證書和失效列表就可以確定token是否合法。但是這里還是會有每次都需要請求keystone去獲取失效列表的操作,不可避免。

 

 

PKI的流程,首先需要使用 keystone-manage pki_setup命令生成CA及相關的令牌機制,其代碼如下所示:

    def _get_token_id(self, token_data):

        try:

            token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder)

            token_id = str(cms.cms_sign_token(token_json,

                                              CONF.signing.certfile,

                                              CONF.signing.keyfile))   #DEFAULT_TOKEN_DIGEST_ALGORITHM=sha256

其中,‘token_data’是獲取的user、role、endpoint、catlog等信息集合,而最重要的語句是cms使用簽名生成token的過程:cms_sign_token,使用默認的sha256方式加密,處理過程使用process,進行數據的讀取、處理, 

           process = subprocess.Popen(['openssl', 'cms', '-sign',

                                 '-signer', signing_cert_file_name,

                                 '-inkey', signing_key_file_name,

                                 '-outform', 'PEM',

                                 '-nosmimecap', '-nodetach',

                                 '-nocerts', '-noattr', 

                                 '-md', message_digest, ],

                                stdin=subprocess.PIPE,

                                stdout=subprocess.PIPE,

                                stderr=subprocess.PIPE,

                                close_fds=True)

最后output, err = process.communicate(data) 生成Token-id,這個過程涉及到openssl相關的加密技術。

CMS token一般都超過1600個字節,樣例:

 

 

(3)Fernet認證原理:

 

 

1.user在客戶端輸入用戶名密碼,發送給keystone。

2.Keystone驗證用戶名密碼,並且生成token(UUID),發送給客戶端。

3.客戶端緩存token(UUID)

4.客戶端發送具體的執行請求給openstack API

5、OpenStack API向 keystone請求token認證

6.Keystone從http請求中獲取token,並檢查token是否有效

7.Token有效,處理請求,並返回openstack api請求結果

8.Token失效,拒絕客戶端請求,返回401。

當集群運行較長一段時間后,訪問其 API 會變得奇慢無比,究其原因在於 Keystone 數據庫存儲了大量的 token 導致性能太差,解決的辦法是經常清理 token。為了避免上述問題,社區提出了Fernet token,fernet 是當前主流推薦的token格式,它采用 cryptography 對稱加密庫(symmetric cryptography,加密密鑰和解密密鑰相同) 加密 token,具體由 AES-CBC 加密和散列函數 SHA256 簽名。Fernet 是專為 API token 設計的一種輕量級安全消息格式,不需要存儲於數據庫,減少了磁盤的 IO,帶來了一定的性能提升。為了提高安全性,需要采用 Key Rotation 更換密鑰。

 

以上代碼表明,token 包含了 user_id,project_id,domain_id,methods,expires_at 等信息,重要的是,它沒有 service_catalog,所以 region 的數量並不影響它的大小。self.pack() 最終調用如下代碼對上述信息加密:

 

 該token 的大小一般在 200 多 Byte 左右,樣例:

gAAAAABWfX8riU57aj0tkWdoIL6UdbViV-632pv0rw4zk9igCZXgC-sKwhVuVb-wyMVC9e5TFc 7uPfKwNlT6cnzLalb3Hj0K3bc1X9ZXhde9C2ghsSfVuudMhfR8rThNBnh55RzOB8YTyBnl9MoQ XBO5UIFvC7wLTh_2klihb6hKuUqB6Sj3i_8

簡要敘述一下fernet采用 Key Rotation 更換密鑰的原理,默認的輪換長度是3,當以keystone-manage fernet-setup生成密鑰時,會看到0、1兩個索引表征,這分別是什么意思呢?

 

 

在此,需要提一下三個概念:

primary key(主密鑰)有且只有一個,名為為x,當前用於加密解密token

secondary key(次次密鑰)有x-1個,從Primary退役下來的,用於解密當初它加密過的token

staged key(次密鑰)有且只有一個,命名為0,准備下一個rotation時變為Primary key,可以解密token

那么上述0 表示的是staged key,1 表示的是primary key,

primary key相比較另外兩種key,它的索引最高,並且可以加密、也可以解密;

staged key 相較於secondary key,它更有機會變為primary key。

 AES256加密token,SHA256 HMAC驗證完整性,

只要Keystone具有訪問這些key的權限,token就不需要在keystone數據庫中存儲

fernet的數據性能最好,原因是它不需要后端持久化操作(采用 Key Rotation定期 更換密鑰,只要Keystone具有訪問這些key的權限,更新后的token就不需要在keystone數據庫中存儲,緩解了數據庫負載壓力),並且token的認證,使用的是密鑰進行解密,能夠直接得出token Data的信息,從而進行token的過期認證。它的失敗原因,只可能是token過期了,或者是token放到了cache緩存中,但是已經被回收了。歸根到底,還是token過期了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM