Openstack Keystone的Token简析

举报
周大仙人 发表于 2020/11/02 19:53:05 2020/11/02
【摘要】 这里尝试对Keystone的Token发展做个总结。 最开始的D版本就引入的UUID-Token。UUID是最简单的,但问题太多了。要持久化到数据库中,时间长了数据库性能下降,需要定时手工清理。要验证Token必须调用keystone的接口,性能差,可靠性低,虽然它的优点是体积小(32Byte),易于传输,但劣势大于优势,因此要改进。 接着上台的是G版本引入的PKI-To...

    这里尝试对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

http://wsfdl.com/openstack/2015/12/26/%E7%90%86%E8%A7%A3Keystone%E7%9A%84%E5%9B%9B%E7%A7%8DToken.html

https://adam.younglogic.com/2016/07/tokens-without-revocation/

https://blog.csdn.net/wllabs/article/details/79064094

https://gist.githubusercontent.com/dolph/ef4aa9b1e164fc6c97b7/raw/eb1ea793f6c7149966ed16e4bc6b8bc8bd72decc/formatter_unpack_output.py

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


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。