首页 > 代码库 > 初识keystone

初识keystone

前言

OpenStack概念不多讲了,因为讲不明白技术分享。只了解过keystone,其他服务是干什么的,怎么用的,目前还没有驱动力去了解,所以就自觉闭嘴了,只贴一张比较有意思的图。

技术分享

Openstack社区非常活跃,开发者很多,代码和文档更新也很频繁,最近几天看文档的过程中就发现过文档内容调整的情况,虽然官网上的文档非常多,但是感觉有点分散,加上V2和V3 版本并存,有些概念和设计在不断演进,新学者刚开始不太容易理出头绪,下面对这段时间学习keystone的一些心得做个总结。

“keystone"的中文意思是拱心石,就是石拱门上面最中间那块石头,将两边的石头塞住不会掉下来,如图:

技术分享技术分享

Keystone是Openstack家庭的一个成员,在2012年的Essex版本成为核心服务,它将内部的Identity, Catalog, Token和Policy服务统一对外提供给Openstack的其他服务。两个最主要的功能一是用户身份认证以及允许用户做什么,另一个功能是为服务编目,有哪些服务可用以及它们的访问点是什么。

基本概念

Keystone的核心概念主要包括:user, project(tenant), domain,token, role, service, endpoint等,V3版本将V2 版本的tenant改名为project,同时增加了domain概念。

下面是我总结的领域模型:

技术分享

  • user代表一个用户,有相关联的用户名和密码以及其他诸如email等数据
  • project包含了一些基础设施资源,记得有人举例说project(以前的tenant)就好比一个宾馆,里面有各种设施
  • domain是V3新增加的概念,类似于命名空间,在不同的domain之间,用户名、project、group名字可以相同。但是domain和role的名字必须全局唯一
  • role就是角色,比如admin,member等,名字可以随便起,叫”女王陛下“完全没问题,但是各个服务有权利自己解释角色的定义,后面会进一步说明这一点
  • group似乎也是V3新增的概念,可以将用户分组,直接给group赋予权限,有GBP(Group based policy)。group在Keystone中不是必须的
  • token就是令牌,用户认证通过后被分配给一个令牌,以后拿着这个令牌可以在规定的范围内活动,也就是说令牌不仅有身份信息,比如用户角色,还有作用范围,通常是project和domain;另外token还有有效期,过期失效;如果中间表现不好,还可能被提前吊销(revoke)

进一步说明一下上面几个概念的关系: role是相对的,一个用户在不同project里面可以有不同的role,在给user或者group授予role时必须指定domain或者project; domain是目前最大的概念,可以包含project,user等,在两个domain里面可以建立两套名称完全相同,但是功能各不相同的系统。

catalog就是目录或者注册表,它可以提供service的索引服务,告诉用户有哪些service以及如何找到这些服务(endpoint)。在云中,不同服务可能分布在各个角落,或者一个服务可能根据地域(region)不同提供就近的服务接入点。Keystone支持两种方式来注册catalog,一种是模板文件,另一种是SQL存储方式,前者参考Keystone源码目录中的etc/default_catalog.templates,后者需要在keystong启动后通过API来注册。

还有一个关键概念没讲到,就是policy,理解它花了我好几袋烟的功夫技术分享。下面的表述未必完全正确,但目前还讲得通。

Policy提供了RBAC(Role based access control)功能,policy是由每个服务自己来管理的,由一组rule组成, 每个service定义自己的rule。 用户访问服务提供的API时,要告诉service你是一个什么角色,但是service自己来解读role的含义。比如说英女王到了一个英联邦国家,人家一看元首来了,赶紧给你吃香的喝辣的,好酒好肉伺候着,基本上你想干啥就干啥,但是,如果女王到了一个阿拉伯国家,人家可能最多跟你客气一下,能干什么还要听人家的,甚至搞不好门都不让进,压根不欢迎你。

Keystone做的很灵活的一点就是所有后端的provider都是可配置的,用户也可以自定义provider。对于Policy,各个service默认采用oslo-incubator policy engine,它通过读取policy.json文件来解析action和role之间的对应关系,决定用户是否有权限进行相应操作。oslo-incubator的实现在openstack/common/policy.py中。

V3版本中,keystone提供了操作policy的API,数据保存在DB中,可能为今后集中控制权限做准备。但是目前,这个特性并没有真正使用。

Keystone中间件-auth_token

这个东东没有仔细研究过,这里一带而过了。

Keystone既然为各个service提供了认证服务,那各个服务怎么用呢?一种高大上的方式就是用auth_token,放到pipeline中,各个服务自己负责auth_token安装和配置。其实就是http拦截器,拦截每一个http请求,检查头部token信息,提取用户、角色等信息,如果验证通过,放行,否则拒绝请求。

认证流程

贴上随处可见的流程图,说实话,有一步没看懂,麻烦明白人给讲一下

技术分享

就是第4步,endpoint到keystone的过程中,里面说有“Does it allow that service usage"的过程,这个Keystone是如何判断的?其他不多说了,很好理解。

UUID&PKI

Keystone的token有两种格式:UUID和PKI。UUID是一个定长的随机字符串,PKI全称是public key Infrastructure,这个概念应该属于加密的范畴,并不是Keystone的独创的,详情请度娘或谷歌。

技术分享

两种格式各有优劣,最大的不同是UUID必须每次都经过Keystone才能认证,而PKI是自包含的,service可以自己根据标准算法来检查签名,这样的好处就是提高了验证效率,Keystone不会成为整个Openstack的瓶颈。但是PKI token也带来了一个问题,因为PKI token包含了很多元数据以及catalog等信息,会很大,不仅带来了网络开销,而且可能超出一些服务器的限制,引发异常。下面就讲一下如何验证PKI签名以及解决token过大的几种方法。

插一句,昨晚写到这里的时候已经夜里12点了,突然无法保存文章,再一刷新,CSDN直接返回500,内部升级... 还好丢掉的不多,否则白码了这么多字,岂不哭死。

PKI离线验证

在测试环境中,通过keystone-manage pki_setup生成私钥及自签署证书,关于公钥、私钥、证书等概念请参考我转发的上一篇文章《CentOS6.5下openssl加密解密及CA自签颁发证书详解》,这里不再解释了。

Keystone的PKI token实际上是将包含元数据,比如用户、角色、catalog等信息的json数据用自己的私钥和CA证书来签名,用到的命令是:

openssl cms -sign -signer /etc/keystone/ssl/certs/signing_cert.pem -inkey /etc/keystone/ssl/private/signing_key.pem -outform PEM -nosmimecap -nodetach -nocerts -noattr < metadata.json
如果不用重定向,可以用-in和-out参数生成cms格式的文件。上面命令生成的密文就是token。

验证token合法性就是拿Keystone的证书以及CA的签字证书来检查,命令是:

openssl cms -verify -certfile /etc/keystone/ssl/certs/signing_cert.pem -CAfile /etc/keystone/ssl/certs/ca.pem -inform PEM -nosmimecap -nodetach -nocerts -noattr < cms_token
如果命令返回成功就能看到原始的metadata了。

但是,从Keystone API得到的token并不符合CMS标准,不能直接调用上面的命令,需要做一下转换,参考Keystone的源码:

https://github.com/openstack/python-keystoneclient/blob/master/keystoneclient/common/cms.py

def token_to_cms(signed_text):
    copy_of_text = signed_text.replace('-', '/')

    lines = ['-----BEGIN CMS-----']
    lines += textwrap.wrap(copy_of_text, 64)
    lines.append('-----END CMS-----\n')
    return '\n'.join(lines)

也就是要将原始的token做一些字符替换,加上头尾两端CMS注释,然后将token字符串按每行64个字符折叠起来。这样再调用上面的验证命令就OK了。

Token太大

这个问题在Keystone社区也有很多讨论,给出了各种方案,这里总结一下我看到的几种,供大家参考

  • 改用UUID Token,废话了~
  • 用PKI Token的MD5值替代原始Token放到HTTP请求header的X-Auth-Token属性中。我验证过,工作没有问题,但是就丢失了原来包含的元数据。
  • 关掉catalog,给元数据减肥,验证时用这个URL:v3/auth/tokens?nocatalog
  • 使用zlib压缩token,在keystone.conf中配置Token的provider为:provider=keystone.token.providers.pkiz.Provider

Keystone在Ubuntu上的安装配置

据说Ubuntu是对Openstack支持比较好的Linux发行版本,但是直接使用apt-get install安装的Keystone版本比较老,跟Ubuntu的repository有关,我后来是直接从源码安装的。

环境Ubuntu 14.04 LTS,步骤如下:

git clone http://github.com/openstack/keystone.git
python setup.py install

有些python的依赖需要提前安装,比如python-dev, python-setuptools, python-pip

安装配置mysql,Keystone默认使用sqllite,我改用mysql,更熟悉些

sudo apt-get install python-mysqldb mysql-server

配置mysql权限

mysql> CREATE DATABASE keystone;
mysql> GRANT ALL ON keystone.* TO 'keystone'@'%' IDENTIFIED BY [YOUR_KEYSTONE_PASSWORD];  flush privileges;
将Keystone源码目录etc目录下的配置文件拷贝到/etc/keystone目录下,修改一下配置文件后缀

修改主配置keystone.conf,主要改了几个地方,数据库连接、token provider、[signing]段除第一项外全部打开

?connection=mysql://keystone:[PASSWORD]@127.0.0.1/keystone
?provider=keystone.token.providers.pki.Provider

初始化数据库,执行:keystone-manage db_sync,可能又有python依赖,安装之

初始化SSL,先创建keystone用户,然后执行pki_setup

sudo groupadd keystone
sudo useradd -g keystone keystone
sudo chown -R keystone:keystone /etc/keystone
sudo keystone-manage pki_setup --keystone-user keystone --keystone-group keystone
最后启动keystone

Keystone-all [--debug]

使用命令行

Keystone有两个客户端,一个是python-keystoneclient,一个是openstack client。前者目前不支持V3的API,官方推荐用openstack client。

安装方式:

wget http://tarballs.openstack.org/python-openstackclient/python-openstackclient-0.4.0.tar.gz
sudo python setup.py install
执行openstack客户端命令时需要带一些参数,也可以设为环境变量
export OS_IDENTITY_API_VERSION=3
export OS_AUTH_URL=http://localhost:5000/v3
export OS_TOKEN=netscreen 
export OS_URL=http://localhost:35357/v3
然后就可以执行类似于:openstack user list 这样的命令了,返回结果如图

技术分享

使用Curl

这里只举个例子,更多参考:http://docs.openstack.org/developer/keystone/api_curl_examples.html#

curl -i   -H "Content-Type: application/json"   -d '
{ "auth": {
    "identity": {
      "methods": ["password"],
      "password": {
        "user": {
          "name": "admin",
          "domain": { "id": "default" },
          "password": "secrete"
        }
      }
    },
    "scope": {
      "project": {
        "name": "demo",
        "domain": { "id": "default" }
      }
    }
  }
}'   http://localhost:5000/v3/auth/tokens ; echo
返回如图

技术分享

结束语

花了两个多星期,把Keystone翻了一遍,只为技术选型。但是如果不是基于openstack,只用keystone来做一个集群应用的RBAC是否有意义,答案恐怕偏向于否定。“云”对我而言还飘在高高的天上,遥不可及,以后如果有需要会进一步研究下去。

如果上面有理解错误或者选型建议,请不吝赐教,谢谢。



初识keystone