openstack之:keystone 学习总结记录

在了解 keystone 之前,我们来简单介绍下用户身份校验大概有几种方式

广义认证方式简介

广义上讲,用户身份认证并不仅限于领域。广义上的身份识别技术有如下几种:静态密码、动态密码(短信密码、动态口令牌)、令牌、USB KEY、数字证书、生物识别技术。

在以上几种认证方式中,我们IT人员在数据中心通常能够遇到的是:静态密码、动态口令牌、数字证书、令牌认证(token)。

静态密码

在四种认证方式中,最常见的就是静态密码。如果要加强动态密码的安全性,通常是通过增加密码的复杂度,设置密码过期时间的方法。大多数linux操作系统默认也是禁止root用户的ssh或telnet权限的。

如下图,在Linux中设置密码策略(/etc/login.defs)

在这里插入图片描述

动态口令牌

动态口令牌也是一种认证方式,如最著名的RSA就是一种,通过输入个人的PIN Code,生成随机密码。

数字证书

数字证书认证方式也是我们常见的。“数字证书就是互联网通讯中标志通讯各方身份信息的一串数字,提供了一种在Internet上验证通信实体身份的方式,数字证书不是数字身份证,而是身份认证机构盖在数字身份证上的一个章或印(或者说加在数字身份证上的一个签名)。它是由权威机构——CA机构,又称为证书授权(CertificateAuthority)中心发行的,人们可以在网上用它来识别对方的身份。”

如果想了解证书认证,就需要了解两种加密方式:

对称加密和非对称加密。对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。

在这里插入图片描述

非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。

在这里插入图片描述

我们经常用到的ssh就是非对称加密。

本小节提到的数字证书(又称数字签名)通常是基于对称对加密的。由此,我们引入一个新的名词,CA。

数字证书认证中心(CertficateAuthority,CA)是整个网上电子交易安全的关键环节。它主要负责产生、分配并管理所有参与网上交易的实体所需的身份认证数字证书。每一份数字证书都与上一级的数字签名证书相关联,最终通过安全链追溯到一个已知的并被广泛认为是安全、权威、足以信赖的机构。CA必须是各行业各部门及公众共同信任的、认可的、权威的、不参与交易的第三方网上身份认证机构。

CA服务器可以是第三方权威机构的,也可以是企业内部自行搭建的。比如:VeriSign公司,就是著名的CA权威机构。另外一个著名的证书认证机构就是—微软,通过Windows AD域实现。AD的功能十分强大,有三个功能:AD = Ldap + kerberos + CA。

如果一个企业的证书,想被权威机构认证,是需要支付一定费用的。被认证的好处是,当客户通过网页访问该金融机构时,该网址是可信的。否则,在互联网应用中,如何确认彼此的身份?

在这里插入图片描述

在数据中心内部,我们通常采取自签名的方式,也就是自己认证自己。

数字证书的颁发原理:

用户首先产生自己的密钥对,并将公共密钥及部分个人身份信息传送给认证中心。认证中心在核实身份后,将执行一些必要的步骤,以确信请求确实由用户发送而来,然后,认证中心将发给用户一个数字证书,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。用户就可以使用自己的数字证书进行相关的各种活动。同时,这个被认证中心认证的公钥信息,通常被主流浏览器默认加载,这样一般客户上网访问这个网址的时候,就不会被提示为不被信任的网站。

我们可以查看IE默认信任的证书:

在这里插入图片描述

所以从中我们也可以看出,正是由于微软在操作系统领域中占有垄断地位,因此,在浏览器市场也处于垄断地位。与浏览器先关的互联网应用,想被认证,就必须要得到IE的认可。

新装好的vcenter,我们通过webclient访问:

在这里插入图片描述

如果想继续访问,我们必须要选择添加例外,然后获取证书,再确认安全例外:

在这里插入图片描述

这个过程,实际上我们就把vcenter的根证书下载到本地,并装在到浏览器中,然后,就可以正常访问了:

在这里插入图片描述

而在这个过程中,我们导入的就是VC的公钥。

谈到这个问题,我举个很有意思的例子:大家一定有过通过12306网站买票的经历,那么下面的图片就一定不会陌生:

在这里插入图片描述

首页提示“为了保障您的顺畅购票,请下载安装根证书”。

然后,我们会点击安装:

在这里插入图片描述

然后导入证书:

在这里插入图片描述

那么大家有没有想过,为什么访问12306需要倒入其根证书,而访问ICBC的网页不会呢?

原因就在于,12306的根证书没有被CA权威机构所认证,当用户通过终端访问该网站时,如果不倒入该证书,那么这个网站将会被标示成不被信任的网站。

而对于金融机构的网站,如果被标示该网址不会信任,请问大家还敢访问并进行金融交易么?

令牌认证

令牌是一种能够控制站点占有媒体的特殊帧,以区别数据帧及其他控制帧。token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。

接下来,我看看看Openstack的内部组件的认证方式。

先看一下OpenStack的架构:

在这里插入图片描述

在这个架构中“keystone”就是负责用户认证的。可以说是Openstack的灵魂。手工用命令行安装过openstack组件(不是用packstack自动应答脚本)的朋友一定知道:在安装单独安装openstack所有组件的时候,都需keystone创建对应组件的用户,每个模块都必须与keystone进行通讯。

例如,安装openstack中neutron的部分步骤如下:

keystone user-create --name neutron --pass xxxx

keystone user-role-add --user neutron --role admin–tenant services

yum install openvswitch openstack-neutronopenstack-neutron-ml2 openstack-neutron-openvswitch

Openstack每个组件的认证,默认是通过token认证的(当然也可以通过密码)。因此,手工安装keystone的步骤中,会有这么一步:

export SERVICE_TOKEN=$(openssl rand -hex 10)

exportSERVICE_ENDPOINT=http://${HOSTNAME}:35357/v2.0

echo$SERVICE_TOKEN > /root/ks_admin_token

# cat /root/ks_admin_token

6f438ff88435dab284a9

而“6f438ff88435dab284a9“这串数字,实际上就是token,它用于认证admin用户。我们可以把它添加到keystonerc_admin配置文件中,这样我们souce这个配置文件,就可以访问keystone的服务了:

source /root/keystonerc_admin

在openstack中,还有一个非常重要的概念:AMQP, AdvancedMessageQueuingProtocol,即高级消息队列协议.Openstack各个组件之间的通讯,是通过AMQP实现的。这样做的好处,可以使各个组件之间是松耦合的关系。比如说,搭建一个openstack,只搭建必要的keystone,nova等,不搭建swift,这是没问题的。

而AMQP与各个组件(各个组件作为AMQP的client),之间的认证,是通过CA进行认证的,也就是自签名认证。目前AMQP使用的数据库是rabbit MQ,下面截取部分命令:

产生证书数据库(AMQP Server):

# certutil -N -d/etc/pki/tls/qpid/ -f /etc/qpid/qpid.pass

# certutil -S -d /etc/pki/tls/qpid/ -n H O S T N A M E − s " C N = HOSTNAME -s"CN= HOSTNAMEs"CN=HOSTNAME" -t “CT,” -x -f /etc/qpid/qpid.pass -z/usr/bin/certutil

S:签发证书 -d 证书文件目录

-s subject -t 设置信任证书的属性

-x 自签发证书

下面几条命令是获取CA配置文件并进行签名:

#wget openssl.cnf ## CA configrationfile

#openssl req -x509 -config openssl.cnf -newkey rsa:2048-days 365 -out cacert.pem -outform PEM -subj /CN=MyTestCA/ -nodes ## CA 'spublic key and private key

#openssl x509 -in cacert.pem -out cacert.cer -outformDER

该证书被签发以后,就可以分发给AMQP client,用于组件之间的通讯了。

Keystone 简介

Keystone 基本概念和理解

Keystone(OpenStack Identity Service)是 OpenStack 框架中负责管理身份验证、服务访问规则和服务令牌功能的组件。用户访问资源需要验证用户的身份与权限,服务执行操作也需要进行权限检测,这些都需要通过 Keystone 来处理。Keystone 类似一个服务总线, 或者说是整个 Openstack 框架的注册表,OpenStack 服务通过 Keystone 来注册其 Endpoint(服务访问的URL),任何服务之间的相互调用,都需要先经过 Keystone 的身份验证,获得目标服务的 Endpoint ,然后再调用。

Keystone 的主要功能如下:

  • 管理用户及其权限;
  • 维护 OpenStack 服务的 Endpoint;
  • Authentication(认证)和 Authorization(鉴权)

keystone的相关概念可以以一个城市的酒店服务来举例说明:

​ 酒店就类似于project项目,酒店提供住宿的服务service,user相当于客人,endpoint相当于客人住酒店时的询问的酒店的地址,role为角色,如客人定了个豪华套房,name他就是贵宾,定了标间,他就是普通客人,credentials相当于入住酒店时提供的身份证,酒店前台利用身份证获取身份信息并提供房间,这个过程相当于authentication,办理入住后拿到的房卡相当于token,利用token就可以刷开房间门进行住宿这项service。

先看下 keystone 在 openstack 中基本位置,以创建虚拟机为例:

在这里插入图片描述

Keystone 的结构如下:

在这里插入图片描述

学习之前,我们先理解一下下面的几个概念:

1. User

User 指代任何使用 OpenStack 的实体,可以是真正的用户,其他系统或者服务。当 User 请求访问 OpenStack 时,Keystone 会对其进行验证。

Horizon 在 “身份管理->用户” 管理 User:

​ admin:openstack平台的超级管理员,负责openstack服务的管理和访问权限

除了 admin 和 demo,OpenStack 也为 nova、cinder、glance、neutron 等服务创建了相应的 User。 admin 也可以管理这些 User。

2. Credentials

Credentials 是 User 用来证明自己身份的信息,可以是:

用户名/密码

Token

API Key

其他高级方式

3. Authentication

Authentication 是 Keystone 验证 User 身份的过程。User 访问 OpenStack 时向 Keystone 提交用户名和密码形式的 Credentials,Keystone 验证通过后会给 User 签发一个 Token 作为后续访问的 Credential。

4. Token

Token 是由数字和字母组成的字符串,User 成功 Authentication 后由 Keystone 分配给 User。Token 用做访问 Service 的 Credential,Service 会通过 Keystone 验证 Token 的有效性。Token 还有 scope 的概念,表明这个 Token 作用在什么范围内的资源,例如某个 Project 范围或者某个 Domain 范围,Token 只能用于认证用户对指定范围内资源的操作。Token 的有效期默认是 24 小时。

Keystone 提供如下几种 Token,可以根据需要配置使用某种 Token:

UUID token:服务 API 收到带有 UUID token 的请求时,必须到 Keystone 进行验证token 的合法性,验证通过之后才能响应用户请求。随着集群规模的扩大,Keystone 需处理大量验证 UUID token 的请求,在高并发下容易出现性能问题。

PKI token:携带更多用户信息并附上了数字签名,服务 API收 到 PKI token 时无需再去Keystone 验证,但是 PKI token 所携带可能随着 OpenStack Region 增多而变得非常长,很容易超出 HTTP Server 允许的最大 HTTP Header(默认为 8 KB),导致 HTTP 请求失败。

PKIZ token:PKI token 的压缩版,但压缩效果有限,无法良好的处理 token 长度过大问题。

Fernet token:携带了少量的用户信息,大小约为 255 Byte,采用了对称加密,无需存于数据库中。前三种 token 都会持久性存于数据库,与日俱增积累的大量 token 引起数据库性能下降,所以用户需经常清理数据库的 token;Fernet token没有这样的需要。

注:在Ocata版本中 Fernet 成为默认的 Token Provider。 PKI 和 PKIz token provider 被移除 。

5. Project

Project 用于将 OpenStack 的资源(计算、存储和网络)进行分组和隔离。在企业私有云中,Project 可以是一个部门或者项目组,和公有云的 VPC(虚拟私有网络)概念类似。资源的所有权是属于 Project 的,而不是 User。每个 User(包括 admin)必须挂在 Project 里才能访问该 Project 的资源,一个 User 可以属于多个 Project。

Horizon 在 “身份管理->项目” 中管理 Project:
可以通过 “管理成员” 将 User 添加到 Project 中。

6. Service

OpenStack 的 Service 包括 Compute (Nova)、Block Storage (Cinder)、Object Storage (Swift)、Image Service (Glance) 、Networking Service (Neutron) 等。每个 Service 都会提供若干个 Endpoint,User 通过 Endpoint 访问资源和执行操作。

7. Endpoint

Endpoint 是一个网络上可访问的地址,通常是一个 URL。Service 通过 Endpoint 暴露自己的 API。Keystone 负责管理和维护每个 Service 的 Endpoint。

8. Role

安全包含两部分:Authentication(认证)和 Authorization(鉴权)。Authentication 解决的是“你是谁?”的问题, Authorization 解决的是“你能干什么?”的问题。Keystone 是借助 Role 来实现 Authorization 的。Role 是全局(global)的,因此在一个 keystone 管辖范围内其名称必须唯一。

Horizon 在 “身份管理->角色” 中管理 Role:
可以为 User 分配一个或多个 Role。

Service 决定每个 Role 能做什么事情。Service 通过各自的 policy.json 文件对 Role 进行访问控制。Role 的名称没有意义,其意义在于 policy.json 文件根据 role 的名称所指定的允许进行的操作。

9. Group

Group 是一个 domain 部分 user 的集合,其目的是为了方便分配 role。给一个 group 分配 role,结果会给 group 内的所有 users 分配这个 role。

Horizon 在 “身份管理->组” 中管理 Group:

10. Domain

Domain 表示 Project、Group 和 User 的集合,在公有云或者私有云中常常表示一个客户,和 VDC(虚拟机数据中心)的概念类似。Domain 可以看做一个命名空间,就像域名一样,全局唯一。在一个 Domain 内,Project、Group、User 的名称不可以重复,但是在两个不同的 Domain 内,它们的名称可以重复。因此,在确定这些元素时,需要同时使用它们的名称和它们的 Domain 的 id 或者 name。

下图表示了 Domain、Project、User、Group、Role 之间的关系:

在这里插入图片描述

下面是一个整体关系图:

在这里插入图片描述

keystone管理这些概念的方法

组件名称管理对象生成方法保存方式配置项
identityuser,以及 user group-sql, ldap.core[identity]driver = keystone.identity.backends.[sql|ldap.core].Identity
token用户的临时 tokenpki,pkiz,uuidsql, kvs,memcached[token]driver = keystone.token.persistence.backends.[sql|kvs|memcache|memcache_pool].Tokenprovider=keystone.token.providers.[pkiz|pki|uuid].Provider
credentialEC2 credentialsql[credential]driver = keystone.credential.backends.sql.Credentialprovider=keystone.token.providers.[core|fernet].Provider
catalogregion,service,endpointsql|templated[catalog]driver = keystone.catalog.backends.[sql|templated].Catalog
assignmenttenant,domain,role 以及它们与 user 之间的关系external, password, tokensql[assignment]methods = external, password, tokenpassword = keystone.auth.plugins.password.Password
trusttrustsql[trust]driver = keystone.trust.backends.[sql].Trust
policyKeystone service 的用户鉴权策略ruels|sql[default]policy_file = policy.json[policy]driver = keystone.policy.backends.[ruels|sql].Policy

keystone 与各组件交互流程

(该章节内容皆来自:https://blog.csdn.net/dylloveyou/article/details/80329732)

Keystone 与 OpenStack 其他服务交互流程如下:

在这里插入图片描述

首先用户向 Keystone 提供自己的身份验证信息,如用户名和密码。Keystone 会从数据库中读取数据对其验证,如验证通过,会向用户返回一个 token,此后用户所有的请求都会使用该 token 进行身份验证。如用户向 Nova 申请虚拟机服务,nova 会将用户提供的 token 发给 Keystone 进行验证,Keystone 会根据 token 判断用户是否拥有进行此项操作的权限,若验证通过那么 nova 会向其提供相对应的服务。其它组件和 Keystone 的交互也是如此。

下面通过 “查询可用 image” 这个实际操作示例让大家对相关概念及交互流程建立更加感性的认识。

示例 :User admin 要查看 Project 中的 image。
第一步,登陆

在这里插入图片描述

输入用户名密码后,点击“连接”按钮,OpenStack 内部发生了哪些事情?

在这里插入图片描述

返回的 token 中包含了 User 的 Role 信息。

第二步,显示操作界面。

在这里插入图片描述

请注意,顶部显示 admin 可访问的 Project 为 “admin” 和 “demo”。
其实在此之前发生了一些事情:

在这里插入图片描述

同时,admin 可以访问 “实例”, “卷”,“映像” 等服务:

在这里插入图片描述

这是因为 admin 已经从 Keystone 拿到了各 Service 的 Endpoints:

在这里插入图片描述

第三步,显示 Image 列表。
点击“映像”,会显示映像列表:

在这里插入图片描述

背后发生了这些事:
首先,admin 将请求发送到 Glance 的 Endpoint:

在这里插入图片描述

Glance 向 Keystone 询问 admin 身份的有效性:

在这里插入图片描述

接下来 Glance 会查看 /etc/glance/policy.json,判断 admin 是否有查看 image 的权限。

在这里插入图片描述

权限判定通过,Glance 将 image 列表发给 admin。

Keystone 获取 token 方式

上面的示例是在界面操作完成的,我们也可以通过调用 REST API 来实现。

要想拿到token, 必须知道用户的相关信息,其中用户名和密码是必须的,如果还想取得更多的信息,例如用户对各种服务包括glance, keystond的访问endpoint, 还需要提供用户的tenant信息。实际上,对于终端用户来说,因为用户名,密码以及tenant名更为直观,所以很少会直接用token进行操作,但对于自动化测试来说,因为要直接和相关api打交道,取得token就相当有必要了。

方法一:使用 api 获取

命令行取得用户token的命令为:

curl -X POST http://localhost:5000/v2.0/tokens -d '{"auth":{"passwordCredentials":{"username": "username", "password":"password"}}}' -H "Content-type: application/json"

# 其中localhost:5000是openstack keystone服务的endpoint, 如果没有特殊的设置,5000就是keystone服务进程的端口号。

# /v2.0/token 是openstack api里定义的取得token的URI, 请求方式为POST,这个可以从openstack.org里查到。

​ 后面json结构的数据‘auth’是提供给keystone服务用户信息,包括用户名和密码。下面看一下输出:

{
	"access": {
		"token": {
			"expires": "2013-06-04T03:06:23Z",
			"id": "5fcf748e0d5d4a02ae3465e0dd301f40"
		},
		"serviceCatalog": {},
		"user": {
			"username": "username",
			"roles_links": [],
			"id": "ce205b61760c463cb46e41909de8495f",
			"roles": [],
			"name": "username"
		}
	}
} {
	"message_id": "",
	"event_type": "user.login",
	"generated": "2021-08-21T12:22:00",
	"traits": [{
		"type": "1",
		"name": "user_id",
		"value": "653ecae8465b4e3b8988960d19f2a168"
	}, {
		"type": "1",
		"name": "project_id",
		"value": "afa072073107491b83ea511d6bb538d8"
	}, {
		"type": "1",
		"name": "browser",
		"value": "chrome"
	}, {
		"type": "1",
		"name": "site_ip",
		"value": "192.168.2.3"
	}, {
		"type": "1",
		"name": "task_result",
		"value": "success"
	}],
	"raw": "{}"
}

这是openstack/essex版本下的token输出,其中[‘token’][‘id’]就是我们得到的用户token。对于openstack/grizzly版本, 用户的token比这个要长得多,但基本结构是一样的。

下面看一下使用tenant的情况:

curl -X POST http://localhost:5000/v2.0/tokens -d '{"auth":{"passwordCredentials":{"username": "admin", "password":"crowbar"}, "tenantName":"tenantname"}}' -H "Content-type: application/json"

输出:

{
	"access": {
		"token": {
			"expires": "2013-06-04T03:14:12Z",
			"id": "fc3e38a93e95462da5028b1fb3a688c0",
			"tenant": {
				"description": "description",
				"enabled": true,
				"id": "4e14ab2a2df045f1a6f02081a46deb2c",
				"name": "tenantname"
			}
		},
		"serviceCatalog": [{
			"endpoints": [{
				"adminURL": "http://localhost:8776/v1/4e14ab2a2df045f1a6f02081a46deb2c",
				"region": "RegionOne",
				"internalURL": "http://localhost:8776/v1/4e14ab2a2df045f1a6f02081a46deb2c",
				"publicURL": "http://localhost:8776/v1/4e14ab2a2df045f1a6f02081a46deb2c"
			}],
			"endpoints_links": [],
			"type": "volume",
			"name": "nova-volume"
		}, {
			"endpoints": [{
				"adminURL": "http://localhost:9292/v1",
				"region": "RegionOne",
				"internalURL": "http://localhost:9292/v1",
				"publicURL": "http://localhost:9292/v1"
			}],
			"endpoints_links": [],
			"type": "image",
			"name": "glance"
		}, {
			"endpoints": [{
				"adminURL": "http://localhost:8774/v2/4e14ab2a2df045f1a6f02081a46deb2c",
				"region": "RegionOne",
				"internalURL": "http://localhost:8774/v2/4e14ab2a2df045f1a6f02081a46deb2c",
				"publicURL": "http://localhost:8774/v2/4e14ab2a2df045f1a6f02081a46deb2c"
			}],
			"endpoints_links": [],
			"type": "compute",
			"name": "nova"
		}, {
			"endpoints": [{
				"adminURL": "http://localhost:8773/services/Admin",
				"region": "RegionOne",
				"internalURL": "http://localhost:8773/services/Cloud",
				"publicURL": "http://localhost:8773/services/Cloud"
			}],
			"endpoints_links": [],
			"type": "ec2",
			"name": "ec2"
		}, {
			"endpoints": [{
				"adminURL": "http://localhost:35357/v2.0",
				"region": "RegionOne",
				"internalURL": "http://localhost:5000/v2.0",
				"publicURL": "http://localhost:5000/v2.0"
			}],
			"endpoints_links": [],
			"type": "identity",
			"name": "keystone"
		}],
		"user": {
			"username": "admin",
			"roles_links": [],
			"id": "ce205b61760c463cb46e41909de8495f",
			"roles": [{
				"id": "454cb6cbddaf41f2af6f87e68ce58d64",
				"name": "KeystoneAdmin"
			}, {
				"id": "5a80a5b5d4244f48ac7d3079d56555c6",
				"name": "KeystoneServiceAdmin"
			}, {
				"id": "c5a190185ea7434eb2c35bbd1bb52051",
				"name": "username"
			}],
			"name": "tenentname"
		}
	}
}

可以看到,如果在请求token的时候同时提供了tenant信息,则可以额外获取用户相关的endpoints信息。这样,有了token和相关endpoints, 就能够对openstack的api进行相关的访问和操作了。顺便说明,上述提供的tenant的信息也可以是tenant的id, 格式为"tenantId":"“。

用户每次发出一次请求,就会生成一个token, 同时会在glance数据库的token表内生成一个记录。每个token的有效时间缺省为24个小时。

使用编程实现也是可以的:

import httplib2
import json

http_obj = httplib2.Http()
headers = {}
body = {
    "auth": {
            "passwordCredentials":{
                "username": 'username',
                "password": 'password',
            },
            "tenantName": 'tenantname',
        },
    }

req_url = "http://localhost:5000/v2.0/tokens"
method = "POST"

headers['Content-Type'] = 'application/json'
headers['Accept'] = 'application/json'

resp, token = http_obj.request(req_url, method,
                               headers=headers, body=json.dumps(body))

print resp
print token

如果在body里不提供tenantName或tenantId的数据,则返回的是上述command line命令不包括endpoints的输出。

方法二:使用 openstack 命令获取

[root@controller ~]# openstack token issue
+------------+----------------------------------------------------------------------------------------+
| Field      | Value                                                                                  |
+------------+----------------------------------------------------------------------------------------+
| expires    | 2019-05-16T09:20:34.284984Z                                                            |
| id         | gAAAAABc3R1SjOCqsvEg3eem30gGaW3ogfR-                                                   |
|            | nu0sISozNnPoCZJ8a61yeNvrdtVnHzMLxD4R2bz1lhFk0ErnBMGp-k_FfRpU-v3Lwy-                    |
|            | J4htqFoTrpAdfqpYFivjrhjuHE3z3AyxZGjCi5EySJUJchVKwroxjyiekBL2uQQ6iIxvD_F8Ew4pMQN8       |
| project_id | fda820529c814812a7ab5fdcb878b291                                                       |
| user_id    | 840931be05dc4e36945bc8d1a6d0fe1c                                                       |
+------------+----------------------------------------------------------------------------------------+

其中的 id 行就是 token

token 生成之后,就可以使用该值放在请求头 X-Auth-Token 字段,访问 openstack 的其余 api 了。

Keystone 源码分析

我们从源码角度分析一下 keystone 相关的服务

在这里插入图片描述

首先给一张基本架构图,基本架构分为 Keystone Api,Router,Services,Backend Driver

Keystone Api

Keystone API与Openstack其他服务的API类似,也是基于ReSTFul HTTP实现的。

Keystone API划分为Admin API和Public API:

  • Public API不仅实现获取版本以及相应扩展信息的操作,同时包括获取Token以及Token租户信息的操作;
  • Admin API主要提供服务开发者使用,不仅可以完成Public API的操作,同时对User、Tenant、Role和Service Endpoint进行管理操作。

Router

Keystone Router主要实现上层API和底层服务的映射和转换功能,包括四种Router类型。
(1) AdminRouter
  负责将Admin API请求映射为相应的行为操作并转发至底层相应的服务执行;
(2) PublicRouter
  与AdminRouter类似;
(3) PublicVersionRouter
  对系统版本的请求API进行映射操作;
(4) AdminVersionRouter
  与PublicVersionRouter类似。

Services

Keystone Service接收上层不同Router发来的操作请求,并根据不同后端驱动完成相应操作

主要包括四种驱动类型Kvs.Token,Memcache.Token,Memcache_pool.Token,Sql.Token;

Identity Service

Identity Service提供关于用户和用户组的授权认证及相关数据,即users和groups。

Keystone-10.0.0支持ldap.core.Identity,Sql.Identity两种后端驱动,系统默认的是Sql.Identity;

Resource Service

Resouse服务提供关于projects和domains的数据

Assignment Service

Assignment Service提供role及role assignments的数据,即 roles和role assignments

Token Service

Token Service提供认证和管理令牌token的功能,用户的credentials认证通过后就得到token

Keystone-10.0.0对于Token Service
支持Kvs.Token,Memcache.Token,Memcache_pool.Token,Sql.Token四种后端驱动,系统默认的是kvs.Token

Catalog Service

Catalog Service提供service和Endpoint相关的管理操作(service即openstack所有服务,endpont即访问每个服务的url)

keystone-10.0.0对Catalog Service支持两种后端驱动:Sql.Catalog、Templated.Catalog两种后端驱动,系统默认的是templated.Catalog;

Policy Service

Policy Service提供一个基于规则的授权驱动和规则管理

keystone-10.0.0对Policy Service支持两种后端驱动:rules.Policy,sql.Policy,默认使用sql.Policy

Backend Driver

Backend Driver具有多种类型,不同的Service选择不同的Backend Driver。

Keystone 服务启动

/usr/bin/keystone-all 会启动 keystone 的两个service:admin and main,它们分别对应 /etc/keystone/keystone-paste.ini 文件中的两个composite:main 和 admin

可见 admin service 提供给administrator 使用;main 提供给 public 使用。它们分别都有 V2.0 和 V3 版本,只是目前的 keystone Cli 只支持 V2.0.比较下 admin 和 public:

名称middlewaresfactory功能区别
admin比 public 多 s3_extensionkeystone.service:public_app_factory从 factory 函数来看, admin service 比 public service 多了 identity 管理功能, 以及 assignment 的admin/public 区别:1. admin 多了对 GET /users/{user_id} 的支持,多了 get_all_projects, get_project,get_user_roles 等功能2. keystone 对 admin service 提供 admin extensions, 比如 OS-KSADM 等;对 public service 提供 public extensions。简单总结一下, public service 主要提供了身份验证和目录服务功能;admin service 增加了 tenant、user、role、user group 的管理功能。
publicsizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v2json_body ec2_extension user_crud_extensionkeystone.service:admin_app_factory从 factory 函数来看, admin service 比 public service 多了 identity 管理功能, 以及 assignment 的admin/public 区别:1. admin 多了对 GET /users/{user_id} 的支持,多了 get_all_projects, get_project,get_user_roles 等功能2. keystone 对 admin service 提供 admin extensions, 比如 OS-KSADM 等;对 public service 提供 public extensions。简单总结一下, public service 主要提供了身份验证和目录服务功能;admin service 增加了 tenant、user、role、user group 的管理功能。

/usr/bin/keystone-all 会启动 admin 和 public 两个 service,分别绑定不同 host 和 端口。默认的话,绑定host 都是 0.0.0.0; admin 的绑定端口是 35357 (admin_port), public 的绑定端口是 5000 (public_port)。因此,给 admin 使用的 OS_AUTH_URL 为 http://controller:35357/v2.0, 给 public 使用的 OS_AUTH_URL=http://controller:5000/v2.0

进程说明

WSGI server的父进程(50511号进程)开启两个socket去分别监听本环境的5000和35357号端口,
其中5000号端口是为main的WSGI server提供的,35357号端口为admin的WSGI server提供的。
即WSGI server的父进程接收到5000号端口的HTTP请求时,则将把该请求转发给为main开启的WSGI server去处理,
而WSGI server的父进程接收到35357号端口的HTTP请求时,则将把该请求转发给为admin开启的WSGI server去处理。

keystoneauth组件介绍

与openstack api交互有多种方法

  1. 可以自己开发client直接调用api
  2. 可以直接使用openstack提供的封装sdk项目 openstacksdk
  3. 可以使用python-xxxclient等项目,比如 python-novaclientpython-neutronclient
  4. 可以直接使用命令行工具 novaneutronopenstack

首先本文中client指那些与openstack api交互的项目,比如python-xxxclient或openstacksdk,这些client封装了具体的api请求过程,提供给用户更友好的操作方式, 比如nova命令来自 python-novaclieent ,neutron命令来自 python-neutronclient ,openstack命令来自 python-openstackclient

这些client的共性是他们都需要认证和发起请求,因此认证和请求这部分可以独立出来实现,各个client就不需要都自己实现一套认证请求流程了,这就是keystoneauth的作用,各个client可以专注于自己的功能实现

keystoneauth是一个相对独立的组件,它在整个openstack生态中提供统一认证和服务请求,因此client中不再需要处理token/headers/api地址这些信息,client需要做的只是import keystoneauth,提供必要的参数(region/用户凭据/api版本等)并调用keystoneauth中的接口,keystoneauth负责管理token和组装完整的api url(根据catalog和api的path)并最终发出api请求,client可以对返回值做友好处理后返回给用户

keystoneauth中实现认证和服务请求的是 keystoneauth1.session.Session 类,我们可以用它来初始化一个Session对象,此对象可以存储用户凭据(用户名密码)和连接信息(比如token),使用同一个Session对象的各个client之间会共享认证和请求信息。 我们先来看看如何初始化一个Session对象

#[root@controller openstack]# cat ses.py
#----
#!/usr/bin/env python

from keystoneauth1.identity import v3
from keystoneauth1 import session

auth = v3.Password(username='admin',
                   password='admin',
                   project_name='admin',
                   user_domain_name='Default',
                   project_domain_name='Default',
                   auth_url='http://controller:35357/v3')
sess = session.Session(auth=auth)
#----

#实例化一个Session对象    
[root@controller openstack]# python
Python 2.7.5 (default, Nov  6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from ses import sess

如上,我们初始化了一个Session类的实例对象 sess ,初始化Session需要提供必要的参数,我们在使用命令行之前需要source的环境变量( OS_PROJECT_NAME , OS_USERNAME , OS_PASSWORD ,…)其实最后也是传递给了keystoneauth。现在来看看能用这个对象做什么

获取token

>>> sess.auth
<keystoneauth1.identity.v3.password.Password object at 0x3c17750>

>>> sess.get_token()
'gAAAAABbWX72UZT-RJnHtuFXpqecNuGFIhEAke_Rira3gfUesIuyvM5w2sEV6bnXC_uyo7rOn5RmYbZwADn2eT6AuvHXkRGHVoE25A6bkkXr6vWGZAd8fXHITK751UBrg8obFBGGNWoZpPhG87qFtmZ1yuLM3uebFFB4lfCTXoJ70D0my0X1GRc'      

>>> sess.get_auth_headers()
{'X-Auth-Token': 'gAAAAABbWX72UZT-RJnHtuFXpqecNuGFIhEAke_Rira3gfUesIuyvM5w2sEV6bnXC_uyo7rOn5RmYbZwADn2eT6AuvHXkRGHVoE25A6bkkXr6vWGZAd8fXHITK751UBrg8obFBGGNWoZpPhG87qFtmZ1yuLM3uebFFB4lfCTXoJ70D0my0X1GRc'}

如上,当执行 get_token() 后,使用 sess.auth 里保存的用户凭证向keystone api提交POST请求( POST http://controller:35357/v3/auth/tokens )获取一个token

此Token可以被多个使用此sess对象的client共享,这样各个client就不需要都走一边完整的获取token流程

过滤endpoint地址

我们平常在使用openstack命令时并没有指定具体的api地址,实际上,组装出完整的api地址也是keystoneauth的责任,那么Session对象是如何知道完整的api地址呢

#指定endpoint过滤条件
>>> identity_endpoint_filter={'service_type': 'identity',
... 'interface': 'admin',
... 'region_name': 'bjff-1',
... 'min_version': '2.0',
... 'max_version': '3.4',}

#根据endpoint_filter获取对应的endpoint url
>>> sess.get_endpoint(sess.auth, **identity_endpoint_filter)
u'http://controller:35357/v3/'

#service_type改为compute,再获取endpoint url
>>> identity_endpoint_filter['service_type'] = 'compute'
>>> sess.get_endpoint(sess.auth, **identity_endpoint_filter)
u'http://controller:8774/v2.1/1987639927c94519ab8aaf3413a68df9'

openstack中的各个服务在安装时都要向endpoint注册( openstack endpoint list 可以看到当前openstack中已注册的所有服务), identity_endpoint_filter 过滤参数作用就是在openstack endpoint中找出匹配项的url,当然,我们这里是手动指定的 identity_endpoint_filter 参数,实际上的过滤参数是client根据用户输入的命令所属的服务类型以及环境变量生成的

简单说下过滤参数含义:

  • service_type: 服务类型,比如 identity , compute , volume 等(openstack endpoint list中可以看到)
  • min_version,max_version: 用于过滤在其范围内的api主版本,openstack中各个服务都有其主版本,比如目前keystone是v3版本,nova是v2版本,注意不是microversion

上面也提到,组装出完整的api地址是keystoneauth的责任,client只需要提供必要的endpoint过滤参数以及访问路径(比如 /users ),最终完整api url就是endpoint url + ‘/users’

直接发送api请求

事实上,我们可以直接用sess对象发起api请求,其它client的api请求最终也是调用的sess对象

#确认下endpoint_filter
>>> identity_endpoint_filter
{'service_type': 'identity', 'interface': 'admin', 'min_version': '2.0', 'max_version': '3.4', 'region_name': 'bjff-1'}
#获取所有user(user list)
>>> response = sess.get('/users',endpoint_filter=identity_endpoint_filter)
>>> response.json()
{u'users': [{u'password_expires_at': None, u'links': {u'self': u'http://controller:35357/v3/users/006cbddb9dde423695d00d94e68f1b19'}, u'enabled': True, u'id': u'006cbddb9dde423695d00d94e68f1b19... }

#service type改为compute
>>> compute_endpoint_filter['service_type'] = 'compute'
>>> compute_endpoint_filter
{'service_type': 'compute', 'interface': 'admin', 'min_version': '2.0', 'max_version': '3.4', 'region_name': 'bjff-1'}
#获取所有虚拟机(server list)
>>> response = sess.get('/servers',endpoint_filter=compute_endpoint_filter)
>>> response.json()
{u'servers': [{u'id': u'0a57d543-1e8f-49c3-a731-c9198dd3ecb7', u'links': [{u'href': u'http://controller:8774/v2.1/1987639927c94519ab8aaf3413a68df9/servers/0a57d543-1e8f-49c3-a731-c9198dd3ecb7', u'rel': u'self'}, {u'href': ...}

#当然还可以获取所有虚拟机详细信息  
response = sess.get('/servers/detail',endpoint_filter=compute_endpoint_filter)

简单说下 sess.get('/servers',endpoint_filter=compute_endpoint_filter) 处理过程如下:

compute_endpoint_filter
http://controller:8774/v2.1/1987639927c94519ab8aaf3413a68df9/servers

配合client

上面那种直接调用Session对象发送api还是太麻烦,client对此有更高层次的封装

比如平常使用的 nova list 命令来自 python-novaclient 项目,下面演示了 python-novaclient 中是如何使用Session对象

列出所有镜像

>>> from glanceclient import Client as gsclient
>>> glance_client = gsclient('2', session=sess)
>>> glance_client.images.list()
<generator object list at 0x32b2c80>

列出所有虚拟机

>>> from novaclient import client as noclient
>>> nova_client = noclient.Client('2', session=sess)
>>> nova_client.servers.list()
[<Server: bjff-nginx02>, <Server: bjff-nginx03>, <Server: bjff-nginx01>]

#当然,也可以创建虚拟机
>>> nova_client.servers.create('instance1',
... image='a88fe8b1-15ed-41af-898a-162447ca8d66',
... flavor='82f7cfad-d792-4d39-bde1-e89369c36244',
... nics=[{'net-id': '2bcb3404-9f7c-4bb9-9bac-521c97be19e2'}],
... min_count=1,max_count=1)
<Server: instance1>

附录:

*.ini 文件几个属性记录

vim /etc/keystone/keystone-paste.ini # 为例

(1) type = composite

这个类型的section会把URL请求分发到对应的Application,use表明具体的分发方式,比如”egg:Paste#urlmap”表示使用Paste包中的urlmap模块,这个section里的其他形式如”key = value”的行是使用urlmap进行分发时的参数。

(2) type = app

一个app就是一个具体的WSGI Application。

(3) type = filter-app

接收一个请求后,会首先调用filter-app中的use所指定的app进行过滤,如果这个请求没有被过滤,就会转发到next所指定的app进行下一步的处理。

(4) type = filter

与filter-app类型的区别只是没有next。

(5) type = pipeline

pipeline由一系列filter组成。这个filter链条的末尾是一个app。pipeline类型主要是对filter-app进行了简化,
否则,如果多个filter,就需要多个filter-app,然后使用next进行连接。OpenStack的paste的deploy的配置文件主要采用的pipeline的方式。
因为url为http://192.168.118.1:5000/v2.0/tokens,因为基本url的后面接的信息为/v2.0,所以将到public_api的section作相应操作。

Keystone V3 API 新特性

在 Keystone V3 之前,用户的权限管理以每一个用户为单位,需要对每一个用户进行角色分配,并不存在一种对一组用户进行统一管理的方案,这给系统管理员带来了额外的工作和不便。此外,Keystone V3 之前的版本中,资源分配是以 Tenant 为单位的,这不太符合现实世界中的层级关系。如一个公司在 Openstack 中拥有两个不同的项目,他需要管理两个 Tenant 来分别对应这两个项目,并对这两个 Tenant 中的用户分别分配角色。由于在 Tenant 之上并不存在一个更高层的概念,无法对 Tenant 进行统一的管理,所以这给多 Tenant 的用户带来了不便。为了解决这些问题,Keystone V3 提出了新的概念 Domain 和 Group。

Keystone V3 做出了许多变化和改进,我们选取其中较为重要的进行阐述:

  • 将 Tenant 改称为 Project
  • 引入 Domain 的概念
  • 引入 Group 的概念

将 Tenant 改为 Project 并在其上添加 Domain 的概念,这更加符合现实世界和云服务的映射。

V3 利用 Domain 实现真正的多租户(multi-tenancy)架构,Domain 担任 Project 的高层容器。云服务的客户是 Domain 的所有者,他们可以在自己的 Domain 中创建多个 Projects、Users、Groups 和 Roles。通过引入 Domain,云服务客户可以对其拥有的多个 Project 进行统一管理,而不必再向过去那样对每一个 Project 进行单独管理。

Group 是一组 Users 的容器,可以向 Group 中添加用户,并直接给 Group 分配角色,那么在这个 Group 中的所有用户就都拥有了 Group 所拥有的角色权限。通过引入 Group 的概念,Keystone V3 实现了对用户组的管理,达到了同时管理一组用户权限的目的。这与 V2 中直接向 User/Project 指定 Role 不同,使得对云服务进行管理更加便捷。

client SDK使用

1. 使用
>>> from keystoneclient.v2_0 import client
>>> keystone = client.Client(...)
>>> keystone.tenants.list() # List tenants

2. 获得权限
>>> from keystoneclient.v2_0 import client
>>> username='adminUser'
>>> password='secreetword'
>>> tenant_name='openstackDemo'
>>> auth_url='http://192.168.206.130:5000/v2.0'
>>> keystone = client.Client(username=username, password=password,
...                          tenant_name=tenant_name, auth_url=auth_url)

3. 建立租户  
>>> from keystoneclient.v2_0 import client
>>> keystone = client.Client(...)
>>> keystone.tenants.create(tenant_name="openstackDemo",
...                         description="Default Tenant", enabled=True)

4. 建立用户 
>>> from keystoneclient.v2_0 import client
>>> keystone = client.Client(...)
>>> tenants = keystone.tenants.list()
>>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0]
>>> my_user = keystone.users.create(name="adminUser",
...                                 password="secretword",
...                                 tenant_id=my_tenant.id)

5. 建立角色和增加用户
>>> from keystoneclient.v2_0 import client
>>> keystone = client.Client(...)
>>> role = keystone.roles.create('admin')
>>> my_tenant = ...
>>> my_user = ...
>>> keystone.roles.add_user_role(my_user, role, my_tenant)

6. 建立服务和endpoints
>>> from keystoneclient.v2_0 import client
>>> keystone = client.Client(...)
>>> service = keystone.services.create(name="nova", service_type="compute",
...                                    description="Nova Compute Service")
>>> keystone.endpoints.create(
...     region="RegionOne", service_id=service.id,
...     publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
...     adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
...     internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s")

参考:

https://blog.csdn.net/dylloveyou/article/details/80329732

https://www.tinymind.net.cn/articles/f439532f8b1a63

https://blog.csdn.net/jiajiastudy/article/details/9011407

https://blog.csdn.net/weixin_34268753/article/details/85847424

https://www.cnblogs.com/hustlijian/p/3603992.html

https://www.codercto.com/a/19667.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值