Openstack Keystone的Token简析
这里尝试对Keystone的Token发展做个总结。
首先,先科普一下Keystone和Token的基础知识。Keystone是OpenStack套件中负责用户认证和权限管理的组件。管理员需要在Keystone中创建不同的User,并分配密码和权限。User使用其密码调用Keystone的认证接口,会获得一个Token,作为后续调用其他OpenStack组件(Nova/Neutron等)的临时凭据。Token一般会体现User身份,权限,以及生效范围和生效时间。可以类比的技术是OAuth2协议,会产生一个AccessToken用于API调用的认证鉴权之用。
最开始的D版本就引入的UUID-Token。UUID,人如其名,是一串字符串,是最简单的,但问题太多了。要持久化到数据库中,时间长了数据库性能下降,需要定时手工清理。要验证Token必须调用keystone的接口,性能差,可靠性低,虽然它的优点是体积小(32Byte),易于传输,但劣势大于优势,因此要改进。
接着上台的是G版本引入的PKI-Token,PKI我就不介绍了,这种Token相比UUID最大的改变是,Token是一个自解释的字符串,任何人可以根据Token的内容就可以获取Token的信息,例如用户ID,过期时间,角色信息等等,直接可以鉴权。那如何保证Token的安全性呢?其实是利用了数字签名的机制。只有keystone可以拿到私钥签发Token,而公钥是公开下载的,任何人通过公钥就可以验证Token是否keystone签发的,如果是则无条件信任。这相当于离线鉴权了,对keystone的负载要求很低,即使keystone短期挂了,只要Token生成了,任何人的业务逻辑都不会受损(但Token会过期,长期还是受损的)。这个机制本来很OK,除了私钥更新的机制不好(旧Token无法使用,导致业务断服)。但,Keystone做了过度的设计,也许是兼容性的考虑。首先,PKI Token还是要持久化到数据库中,长期数据库性能会下降的。这其实是没有必要的,Token都可以离线鉴权了,除了兼容性和乱来两个可能性,找不到持久化的必要性。接着,PKI Token包含了service catalog列表和用户的role列表,后者还好,在一般的私有云场景,单个用户的role不会太多,但service catalog就不一样了,随着业务部署的增多,service catalog会变成Token体即不可控的因素(KB起步)。除了乱来这个可能性,找不到这么设计的必要性。很明显,是想提供某种服务发现的机制,但真的没有必要。Token是一种在任何请求上下文上都会携带的信息,空间是非常宝贵的,本来Json格式都已经造成太多空间浪费了,还加入不可控的东西,这不是乱来么?
然后社区在J版本引入了PKIZ-Token,在PKI的基础上加入压缩,但本质的问题没解决,没有起太大作用。
跟着社区K版本引入了fernet-Token,什么是fernet?其实是一种利用对称加密的编码算法,特点是定义了密钥轮换的流程,具体自己去看。它跟PKI-TOken的区别是,它是对称加密的,调用方必须拿到共享密钥才能看到明文,因此在安全性上更好。同样Token是一个自解释的字符串,里面包含了用户ID,过期时间等信息。它不需要持久化,因此持久化的问题解决了。它去掉了service catalog以及role,解决了Token体积过大的问题,它提供了一套多密钥轮换的机制,有效地保证密钥在轮换周期内新旧Token均可以使用。但,它又走回头路,必须调用keystone接口来验证以及获取role信息,意味着对keystone的依赖性没有PKI Token好。
接着社区最新引入了JWS-Token,JWS是JWT Token的一种基于数字签名的实现(还有基于加解密的JWE实现)。社区有感fernet的spec太过混乱和封闭,希望有一个更开放的实现,满足和其他系统对接的愿景,同时觉得共享密钥机制,容易在不安全节点上暴露密钥,放大了安全风险,因此基于JWT标准的JWS实现来提供JWS-Token机制。标准JWS实现是可以支持多种签名算法的(例如对称密钥的HMAC,非对称密钥的RSA和ECDSA)。很明显,若使用HMAC,则还陷入和fernet一样的对称密钥的安全问题,所以Keystone选择了非对称密钥的ECDSA(就是JWS中定义的ES256)。同时JWS-Token也是不持久化的,Token中只有少量身份审计信息,也提供了一套私钥更新机制(所使用的Python库不支持多私钥签名机制,后面应该会使用,可以简化更新机制),而且也声明了不会支持公私钥常见的吊销列表能力,同时在JWT基础上扩展了Openstack的私有属性,满足身份审计要求。但,同样需要调用keystone接口获取完整鉴权信息,这也有同样的问题。
最新的Keystone版本只支持fernet和jws两种Token了,曾经的uuid和PKI Token都已经昨日黄花。个人觉得,jws Token算是一个较为可用的机制,一路走来遇到的问题都一一解决了,在工程管理上也有一个可用的手段。如果能解决高度依赖keystone的问题,那算是更可用了。如何解决呢?在Token中加入用户权限上次变更时间+本地保存用户权限关系,是否是个good idea呢?
参考文档:
https://docs.openstack.org/keystone/latest/admin/tokens-overview.html
https://docs.openstack.org/keystone/latest/admin/fernet-token-faq.html
https://specs.openstack.org/openstack/keystone-specs/specs/keystone/stein/json-web-tokens.html
https://docs.openstack.org/keystone/pike/admin/identity-tokens.html
https://adam.younglogic.com/2016/07/tokens-without-revocation/
https://blog.csdn.net/wllabs/article/details/79064094
http://www.tup.tsinghua.edu.cn/upload/books/yz/072258-01.pdf
https://www.freebuf.com/articles/web/180874.html
https://juejin.im/entry/577b7b56a3413100618c2938
https://www.cnblogs.com/Irving/p/9390588.html
https://blog.csdn.net/fw0124/article/details/8473858
- 点赞
- 收藏
- 关注作者
评论(0)