您的位置:首页 > 运维架构

Openstack之Keystone基础

2015-06-04 16:16 471 查看
Openstack之Keystone基础

Keystone是Openstack的身份管理服务(Identity Service)。在Openstack的整体框架结构中,Keystone的作用类似一个服务总线,Nova、Glance、Horizon、Swift、Cinder以及Neutron等其他服务通过Keystone来注册其服务的Endpoint,针对这些服务的任何调用都需要经过Keystone的身份认证,并获得服务的Endpoint来进行访问。

1、一些基本概念

User:用户。通过keystone访问Openstack服务的个人、系统或者是某个服务,keystone会通过认证信息(Credential,比如密码等)验证用户请求的合法性,通过验证的用户将会分配到一个特定的令牌,该令牌可以用于后续资源访问的一个通行证。

Tenant:租户。从实际情况来看,可以把租户理解成一个组织或者是一个项目。租户是各个服务中的一些可以访问的资源的集合,例如,在Nova中,可以把租户理解成一组虚拟机的拥有者,在Swift中则是一组容器的拥有者。基于此,我们需要在创建虚拟机时指定某个租户,在Cinder创建卷时也要指定具体的租户。用户默认总是绑定到某个租户上,用户访问租户的资源前,必须与该租户关联,并且指定该用户在租户下的角色。

Role:角色。一个用户所具有的角色,角色不同意味着被赋予的权限不同,只有知道用户被授予的角色才能知道该用户是否有权限访问某资源。用户可以被添加到任意一个全局的或租户内的角色中,在全局的角色中,用户可以对所有的租户执行角色所规定的权限,在租户内的角色中,用户仅可以在当前租户内执行角色规定的权限。

Service:服务,比如Nova、Swift、Glance、Cinder等。根据User、Tenant和Role一个服务可以确认当前用户是否具有访问其资源的权限。服务对外暴露一个或者多个Endpoint,用户是有通过这些Endpoint才可以访问所需资源或者执行某些操作。

Endpoint:端点。指一个可以用来访问某个具体服务的网络地址,因此我们可以将端点理解为服务的访问点,如果需要访问一个服务,就必须知道它的Endpoint。一般以一个URL地址来表示一个端点,URL具有Public、Internal和Admin三种,Public URL是为全局提供的服务端点,Internal URL相对于Public URL来说提供内部服务之间的访问,Admin URL是提供给管理员使用。

Token:令牌。用户通过Credential获取在某个租户下的令牌,以及令牌的颁发时间和有效时间。

Credentials:凭证。用户的用户名和密码,或者是用户名和API密钥,或者是身份管理服务提供的认证令牌。

Domain:Keystone V3 API中新加的概念。一个域可以包含多个项目,用户被赋予域管理员权限,那么他就可以创建属于域的用户/组,定义用户在该域内的角色。一个域的管理员权限只限定于此域。而在V2 API中管理员权限是全局的。

Group:Keystone V3 API中新加的概念。组是用户的集合,有了组之后,域管理员就无需针对单个的用户来定义其角色了,换言之,它可以直接定义一个组所对应的角色,而这个组中的所有用户都具有该角色。

2、Keystone工作流程

一次创建虚拟机的操作涉及的Keystone的工作流程如下:



第一步:用户发送自己的凭证到Keystone,Keystone认证通过后,返回给Alice一个token1以及服务目录。

第二步:用户通过token1请求Keystone查询他所拥有的Tenant,Keystone验证token1成功后,返回用户一个Tenant列表。

第三步:用户选择一个租户,发送自己的凭证给Keystone申请token,Keystone验证后,返回token2。与此同时,Keystone还将服务端点列表返回给用户。

第四步:用户选择Endpoint并发送token2至Endpoint请求创建虚拟机,此时会再次向Keystone验证token2的有效性,并验证用户是否有相应操作的权限。

第五、六、七步:通过验证后,访问Service,Service创建虚拟机并将结果返回。

下图也描述了创建虚拟机的过程:



文章后面会提到该方式的局限性。

3、Keystone的内部功能

在上一节创建虚拟机的过程中,Keystone是通过一系列内部服务(功能)来完成其工作的,这些内部服务(功能)包括:

Identity:The Identity service provides auth credential validation and data about Users,Groups.

Resource:The Resource service provides data about Projects and Domains.

Assignement:The Assignment service provides data about Roles and Role assignments tothe entities managed by the Identity and Resource services.

Token:The Token service validates and manages Tokens used for authenticatingrequests once a user’s credentials have already been verified.

Catalog:The Catalog service provides an endpoint registry used for endpointdiscovery.

Policy:The Policy service provides a rule-based authorization engine and theassociated rule management interface.

每个Keystone功能都支持用于集成到异构环境并展示不同功能的后端插件。更常见的一些后端包括:

Key Value Store:一个接口,支持主键查找,例如内存中的字典。

Memcached:分布式内存缓冲系统。

Structured Query Language (SQL):使用 SQLAlchemy(一个 PythonSQL工具包和
Object Relational Mapper)来永久存储数据。

Pluggable Authentication Module (PAM):使用本地系统的 PAM服务进行身份验证。

Lightweight Directory Access Protocol (LDAP):通过 LDAP连接到一个后端字典,例如
Active Directory,以便验证用户身份并获取角色信息。

 

 4、keystone的启动

在kilo版本的官方安装文档(Ubuntu14.04)中配置的keystone是随apache服务一起启动的,因此在操作系统中执行service
keystone status查看到的服务是停止的。另外如果修改了keystone的配置,需要重启apache服务。

查看下面文件的内容:

/etc/apache2/sites-available/wsgi-keystone.conf

 Listen5000

Listen35357

<VirtualHost*:5000>

    WSGIDaemonProcess keystone-publicprocesses=5 threads=1 user=keystone display

-name=%{GROUP}

    WSGIProcessGroup keystone-public

    WSGIScriptAlias //var/www/cgi-bin/keystone/main

    WSGIApplicationGroup %{GLOBAL}

    WSGIPassAuthorization On

    <IfVersion >= 2.4>

      ErrorLogFormat "%{cu}t %M"

    </IfVersion>

    LogLevel info

    ErrorLog/var/log/apache2/keystone-error.log

    CustomLog/var/log/apache2/keystone-access.log combined

</VirtualHost>

 

<VirtualHost*:35357>

    WSGIDaemonProcess keystone-adminprocesses=5 threads=1 user=keystone display-

name=%{GROUP}

    WSGIProcessGroup keystone-admin

    WSGIScriptAlias //var/www/cgi-bin/keystone/admin

    WSGIApplicationGroup %{GLOBAL}

    WSGIPassAuthorization On

    <IfVersion >= 2.4>

      ErrorLogFormat "%{cu}t %M"

    </IfVersion>

    LogLevel info

    ErrorLog/var/log/apache2/keystone-error.log

    CustomLog/var/log/apache2/keystone-access.log combined

</VirtualHost>

这里开启了两个TCP的访问端口5000和35357,分别是公用端口和管理端口。WSGIScriptAlias的第一个参数是
/,表示以“/”开头的URL路径会被映射到第二个参数指定的WSGI脚本文件中,mod_wsgi在启动的时候会调用到该WSGI脚本以获取一个应用对象(Application
Object)。

另外,在kilo之前的版本中,如juno,keytone是作为普通服务启动的。

 

5、Keystone debug信息



为了看到日志中的debug信息,需要在keystone.conf中设置debug
=True。

另外,执行命令时加上—debug选项可以看到详细输出。

在kilo版本中,Keystone日志文件为/var/log/apache2/keystone-error.log,在juno中则为/var/log/keystone/keystone-all.log。

在juno版本中执行keystone –debug user-list命令,输出如下:

root@controller:~#keystone --debug user-list

DEBUG:keystoneclient.auth.identity.v2:Makingauthentication request to http://controller:35357/v2.0/tokens
首先,keystoneclient生成获取tokens的http请求。

INFO:urllib3.connectionpool:Startingnew HTTP connection (1): controller

DEBUG:urllib3.connectionpool:Settingread timeout to 600.0

DEBUG:urllib3.connectionpool:"POST/v2.0/tokens HTTP/1.1" 200 1710

DEBUG:keystoneclient.session:REQ:curl -i -X GET http://controller:35357/v2.0/users -H "User-Agent:python-keystoneclient" -H "X-Auth-Token:46928e6a4d7f482aaff20b2f7f2e8bbe"

获取到token后,发出获取users的请求,并将token放在请求头部。

INFO:urllib3.connectionpool:Startingnew HTTP connection (1): controller

DEBUG:urllib3.connectionpool:Settingread timeout to 600.0

DEBUG:urllib3.connectionpool:"GET/v2.0/users HTTP/1.1" 200 631

DEBUG:keystoneclient.session:RESP:[200] {'date': 'Tue, 16 Jun 2015 06:14:38 GMT', 'vary': 'X-Auth-Token','content-length': '631', 'content-type': 'application/json', 'x-distribution':'Ubuntu'}

RESPBODY: {"users": [{"username": "neutron","name": "neutron", "enabled": true,"email": null, "id":"2e6a647673014226ba6ac07b32a04496"}, {"username": "demo","name": "demo", "id":"5eb5fee230c94fef8cffacd5d3e66a33", "enabled":
true,"email": null, "tenantId":"c13ab4febc1a4facac8370d20de12767"}, {"username":"admin", "name": "admin", "enabled":true, "email": null, "id":"8b7e62769ecc4e9c9ee272ff58de2db3"}, {"username":"glance", "name": "glance", "enabled":true, "email": null, "id":"d3c17c40c0bb4c72ab2b503f7d07ccd6"},
{"username":"nova", "name": "nova", "enabled":true, "email": null, "id":"fa1794a7d76542d9a83fbf208ddee6de"}]}

 

+----------------------------------+---------+---------+-------+

|                id                |  name  | enabled | email |

+----------------------------------+---------+---------+-------+

|8b7e62769ecc4e9c9ee272ff58de2db3 | admin  |   True |       |

|5eb5fee230c94fef8cffacd5d3e66a33 |  demo  |   True |       |

|d3c17c40c0bb4c72ab2b503f7d07ccd6 | glance |   True  |      |

|2e6a647673014226ba6ac07b32a04496 | neutron |  True  |       |

|fa1794a7d76542d9a83fbf208ddee6de |  nova  |   True |       |

+----------------------------------+---------+---------+-------+

获得应答。

keystone-all.log日志中的信息如下:

2015-06-1614:14:38.713 1926 DEBUG keystone.middleware.core [-] Auth token not in therequest header. Will not build auth context. process_request/usr/lib/python2.7/dist-packages/keystone/middleware/core.py:270

因为第一次请求头部没有token,不能创建auth context。

2015-06-1614:14:38.716 1926 DEBUG keystone.common.wsgi [-] arg_dict: {} __call__/usr/lib/python2.7/dist-packages/keystone/common/wsgi.py:191

2015-06-1614:14:38.808 1926 INFO eventlet.wsgi.server [-] 10.0.0.11 - - [16/Jun/201514:14:38] "POST /v2.0/tokens HTTP/1.1" 200 1864 0.095508

2015-06-1614:14:38.822 1941 DEBUG keystone.middleware.core [-] RBAC: auth_context:{'is_delegated_auth': False, 'access_token_id': None, 'user_id':u'8b7e62769ecc4e9c9ee272ff58de2db3', 'roles': [u'admin'], 'trustee_id': None,'trustor_id':
None, 'consumer_id': None, 'token': <KeystoneToken(audit_id=ox8_4ETJQReWJMcXDDrsjw, audit_chain_id=ox8_4ETJQReWJMcXDDrsjw) at0x7f89bb397618>, 'project_id': u'317f019de6ac4931a0ffc91048b792db','trust_id': None} process_request /usr/lib/python2.7/dist-packages/keystone/middleware/core.py:280

第二次请求头部包含token,创建auth context。

2015-06-1614:14:38.826 1941 DEBUG keystone.common.wsgi [-] arg_dict: {} __call__/usr/lib/python2.7/dist-packages/keystone/common/wsgi.py:191

2015-06-1614:14:38.834 1941 DEBUG keystone.policy.backends.rules [-] enforceadmin_required: {'user_id': u'8b7e62769ecc4e9c9ee272ff58de2db3', u'is_admin':0, u'roles': [u'admin'], 'tenant_id': u'317f019de6ac4931a0ffc91048b792db'}enforce
/usr/lib/python2.7/dist-packages/keystone/policy/backends/rules.py:100

Policy后端提供RBAC(基于规则的授权),规则文件为/etc/keystone/policy.json,这里的user_id对应的就是admin用户。

2015-06-1614:14:38.845 1941 INFO eventlet.wsgi.server [-] 10.0.0.11 - - [16/Jun/201514:14:38] "GET /v2.0/users HTTP/1.1" 200 784 0.033303

6.Keystone的认证方式与令牌生成方式



三种认证方式:

基于令牌:

如果令牌包含在参数auth中,则通过令牌信息来完成认证,剥离HTTP请求Header中的令牌信息,进行Hash计算并与数据库中保存的令牌值进行比对以确认是否有效。令牌在此的作用等效于用户名密码。

外部用户:

如果上下文信息(context)中包含外部用户“REMOTE_USER”信息,认证该外部用户的关联租户以及角色的合法性,并用自定义的方式进行认证,例如Kerberos。

本地认证:

默认方式,即用户名密码认证。本地认证的核心操作是通过Backend Driver去做密码的校验,就是对传入明文做一次SHA512的Hash操作,再与数据库中存放的散列之后的密码进行比对。

Keystone使用具体的Backend生成令牌,有三种方式:

UUID:调用Python库函数来生成一个随机的UUID作为令牌的ID。

PKIZ:使用OpenSSL对用户相关信息进行签名,签名后的格式为DER,并以此来生成令牌ID。

PKI:使用OpenSSL对用户相关信息进行签名,与PKIZ不同的是生成的签名格式为PEM。

默认情况使用UUID,在keystone.conf中有如下配置:

provider= keystone.token.providers.uuid.Provider

 

7、UUID的局限性与解决



使用UUID生成token时,在大规模的集群环境中,同时有大量客户端发请求的情况下,keystone的性能将会是一个大的瓶颈,因为每个请求都需要和Keystone进行交互以对令牌的合法性进行校验;另外,令牌也可能被无意泄漏或者窃取。

使用PKI系统后,keystone会利用PKI对令牌相关的数据进行签名,而每一个服务端点会保存一份签名公钥证书、CA公钥证书以及证书吊销列表,这样就可以进行本地校验而无需与keystone频繁交互。过程如下:

客户端发送用户名密码信息到keystone进行验证。Keystone校验用户名密码以及项目信息合法之后用签名私钥对令牌元数据进行签名以生成令牌。

令牌通过网络发送到客户端,令牌同时缓存在客户端。

客户端发送API请求到服务端点,服务端点提取令牌信息,用本地存放的签名公钥证书进行验签。

服务端点处理合法的请求,拒绝验证未通过的请求。

 

使用下面的命令配置PKI:

keystone-managepki_setup

并且需要在各组件的配置文件下的[keystone_authtoken]中设置相关配置。

更多的内容可以参考:http://docs.openstack.org/developer/keystone/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: