Openstack、APIs和客户端
Tokens
1 UUID tokens
UUID tokens是Folsom和之前版本采用方案,下图显示了tokens如何在最初被Keystone生成,并如何被客户端使用,如何标记每个之后的API请求。
UUID Token基于提供的用户名及密码(图中假设用户名密码正确):
- Keystone将:
- 生成UUID Token;
- 后台保存UUID Token;
- 给客户端发送UUID Token的副本。
- 客户端将会缓存Keystone发来的Token到本地
- 客户端的每次API调用时都会传递UUID
- 用户的每次请求,API断点都会发送UUID到Keystone的后端
- Keystone将会获取UUID,并于后端的认证系统进行匹配,检验UUID字符串及其有效期
- 之后,Keystone将返回“成功”或“失败”的结果给API端点。
从上图可以看到,每个用户调用API端点时都需要执行在线验证Keystone服务,假如有上万台机器执行虚拟机列表查询、网络创建等操作时,这会对Keystone服务造成巨大拥塞,在生产环境中,从网络的角度来讲,Keystone将会是最繁忙的服务,从而成为系统瓶颈。后面,Grizzly版本利用PKI tokens取代UUID token。
2 PKI tokens
PKI tokens是Grizzly开始采用的方案,下图显示了执行PKI token验证的方法:
笼统的来讲,用上PKI tokens后,Keystone变成了一个证书认证中心(Certificate Authority ,CA),它利用签名密钥和证书去签发(并不是去加密)用户token。
如上图,每个API端点都会持有Keystone端的如下副本:
- 签名证书(Signing certificate)
- 证书吊销列表(Revocation list)
- 认证证书(CA certificate)
API端点会利用这些单元去验证用户请求,这不再需要直接请求Keystone进行在线验证。验证的过程被签发取代,Keystone只利用用户token和证书吊销列表,API端点只需要利用上面的数据就可以离线执行验证Token是否有效。
但PKI仅仅用于签名,而不是加密,并不能保证token的隐私,如果要保证安全性而不被黑客攻击,还需要利用HTTPS对API端点进行安全防护。
3 PKIZ tokens
相对于UUID tokens,PKI tokens虽然支持本地认证,但携带更多用户信息和数字签名,其中这些信息中包括service catalog,随着 OpenStack 的 Region 数目增多,service catalog 携带的 endpoint 数量就越多,PKI token数据量也相应增大,很容易超出 HTTP Server 允许的最大 HTTP Header大小(默认为 8 KB),从而导致 HTTP 请求失败。PKIZ token是 PKI token 的压缩版,它在 PKI 的基础上做了压缩处理,但是压缩的效果极其有限,一般情况下,压缩后的大小为 PKI token 的 90 % 左右,所以 PKIZ 不能友好的解决 token size 太大问题。
4 Fernet tokens
前三种 tokens 都会持久性存储于数据库,与日俱增积累的大量 token 引起数据库性能下降,所以用户需经常清理数据库的 token。为了避免该问题,社区提出了 Fernet tokens,它携带了少量的用户信息,大小约为 255 Byte,采用了cryptography对称加密,无需存于数据库中,减少了磁盘的 IO,带来了一定的性能提升。为了提高安全性,需要采用 Key Rotation 更换密钥。
以下显示了Fernet模块加密和解密的使用过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> from cryptography.fernet import Fernet >>> from cryptography.fernet import Fernet >>> key = Fernet.generate_key() >>> key '6OgCVxcIYSR0gXFjaT2o9eN6jzDVqJn_cUBC6E-jQyI=' >>> f = Fernet(key) f>>> f <cryptography.fernet.Fernet object at 0x7f167e8d7f90> >>> token = f.encrypt(b"my deep dark secret") >>> token 'gAAAAABZcga9z_C6aYb9cojSgNuRToNYBcQ-A51aNuinvJ7kkHkcnkUbzKWPHcTIq5i0DixE5JErPyXbW91MFfNXLs3yeEd6ttPGfsRKphrAuZRjvTXpxGc=' >>> f.decrypt(token) 'my deep dark secret' |
5 小节
以下是四种Tokens的比较。如果region小于3个,优先选择前三种,在根据Keystone服务器压力情况选择UUID还是PKI/PKIZ,如果region大于等于3个,考虑采用UUID和Fernet tokens。
Token 类型 | UUID | PKI | PKIZ | Fernet |
---|---|---|---|---|
大小 | 32 Byte | KB 级别 | KB 级别 | 约 255 Byte |
支持本地认证 | 不支持 | 支持 | 支持 | 不支持 |
Keystone 负载 | 大 | 小 | 小 | 大 |
存储于数据库 | 是 | 是 | 是 | 否 |
携带信息 | 无 | user, catalog 等 | user, catalog 等 | user 等 |
涉及加密方式 | 无 | 非对称加密 | 非对称加密 | 对称加密(AES) |
是否压缩 | 否 | 否 | 是 | 否 |
版本支持 | D | G | J | K |
参考文档
https://wiki.openstack.org/wiki/PKI
http://jqjiang.com/openstack/openstack_keystone/
https://www.mirantis.com/blog/understanding-openstack-authentication-keystone-pki/
code
more code
~~~~