文章目录
- OpenStack认证管理
-
- Keystone简介
- Keystone架构
- Keystone对象模型
- Keystone工作原理和流程
-
- Keystone认证方式概览
- Keystone三种认证方式对比
- Keystone基于令牌的认证-UUID
- Keystone基于令牌的认证-PKI
- Keystone基于令牌的认证-PKIZ
- Keystone基于令牌的认证-Fernet
- 如何选择Keystone基于令牌的认证方式?
- OpenStack认证流程-以创建VM为例
- RBAC,基于角色的访问控制如何实现?
- RBAC:基于角色的访问控制-流程
- RBAC:基于角色的访问控制-原理
- Keystone如何实现认证和权限控制?
- [总结: Keystone如何实现认证和权限控制](#总结: Keystone如何实现认证和权限控制)
OpenStack认证管理
Keystone简介
认证服务Keystone
- KEYSTONE
- 提供身份验证,服务发现和分布式多租户授权
- 支持LDAP、Oauth、OpenID Connect、SAML和SQL
- 首次出现在OpenStack的"Essex"版本中
- 为其他OpenStack服务提供认证支持
Keystone在OpenStack中的定位
- Keystone
- OpenStack Identity,代号为Keystone,是OpenStack默认的身份管理系统
- 如图所示,Keystone属于共享服务层,为OpenStack其他项目提供认证

Keystone基本概念
| Domain | 域,Keystone中一个虚拟概念,一个域是一组User Group或Project的容器 |
|---|---|
| User | 用户,是可以通过Keystone访问OpenStack服务的个人、系统或某个服务 |
| Group | 用户组,是一组User的容器,可以向Group中添加用户,并直接给Group分配角色 |
| Project | 项目,是各个服务中一些可以访问的资源集合,项目只需在某个域下唯一即可 |
| Role | 角色,具有一组定义的用户权限和特权以执行一组特定操作,角色不同,被赋予的权限不同 |
| Service | 服务,一种OpenStack服务,服务会对外暴露一个或多个端点,用户可以通过这些端点访问资源并执行操作 |
| Endpoint | 端点,是指一个可以用来访问某个具体服务的网络地址 |
| Token | 令牌,是允许访问特定资源的凭证 |
| Credential | 凭证,确认用户身份的数据,如用户的用户名和密码 |
!tip
Domain:一个域可以对应一个大的机构、一个数据中心,并且必须全局唯一。云的终端用户可以在自己的Domain中创建多个Project、User、Group和Role。具备对多个Project进行统一管理的能力。
User:Keystone会通过认证信息(Credential,如密码等)验证用户请求的合法性,通过验证的用户将会分配到一个特定的令牌,该令牌可以被当作后续资源访问的一个通行证,并非全局唯一,只需要在域内唯一即可。
Group:用户组是一组User的容器,可以向Group中添加用户,并直接给Group分配角色,在这个Group中的所有用户就拥有了Group所拥有的角色权限。通过引入Group的概念,Keystone实现了对用户组的管理,达到了同时管理一组用户权限的目的。
Project:项目是各个服务中的一些可以访问的资源集合。我们需要在创建虚拟机时指定某个项目,在Cinder创建卷时也需要指定具体的项目。用户总是被默认绑定到某些项目上,在用户访问项目的资源前,必须具有对该项目的访问权限,或者说在特定项目下被赋予了特定的角色。项目不必全局唯一,只需要在某个域下唯一即可。
Role:一个用户所具有的角色,角色不同意味着被赋予的权限不同,只有知道用户被赋予的角色才能知道该用户是否有权限访问某资源。用户可以被赋予一个域或项目内的角色。一个用户被赋予域的角色意味着他对域内所有的项目都具有相同的角色,而特定项目的角色只具有对特定项目的访问权限。角色可以被继承,在一个项目树下,拥有父项目的访问权限也意味着同时拥有对子项目的访问权限。角色必须全局唯一。
- Service:服务,如Nova、Swift、Glance、Cinder等。一个服务可以根据User、Tenant和Role确认当前用户是否具有访问其资源的权限。服务会对外暴露一个或多个端点,用户可以通过这些端点访问资源并执行操作。
- Endpoint:端点,是指一个可以用来访问某个具体服务的网络地址,我们可以将端点理解为服务的访问点。如果我们需要访问一个服务,就必须知道它的Endpoint。一般以一个URL地址来表示一个端点。
- Token:令牌,令牌是允许访问特定资源的凭证。无论通过何种方式,Keystone的最终目的都是对外提供一个可以访问资源的令牌。
- Credential:凭证,确认用户身份的数据,如用户的用户名和密码。
基本概念之间逻辑关系

!tip
上图显示Domain、Project、Group、User和Role的逻辑关系。
Role Assignment是一个包含Role、Resource、Identity的三元组。
Resource:提供关于Domain和Project的数据。
Keystone在OpenStack中的作用
- Keystone
- Keystone在用户与OpenStack服务之间架起一座桥梁
- 用户从Keystone获取令牌及服务目录;用户在访问服务时,发送自己的令牌;相关服务向Keystone求证令牌的合法性

!tip
Keystone作为OpenStack中一个独立的提供安全认证的模块,主要负责OpenStack用户的身份认证、令牌管理、提供访问资源的服务目录,以及基于用户角色的访问控制。
用户访问系统的用户名和密码是否正确,令牌的发放,服务端点的注册,以及该用户是否具有访问特定资源的权限等都离不开Keystone服务的参与。
Identity:身份服务,提供身份验证凭证及有关用户和用户组数据。
Token:令牌,Keystone在确认用户的身份后,会给用户提供一个核实身份且可以用于后续资源请求的令牌。
Catalog:对外提供一个服务的查询目录,服务目录存储了OpenStack所有服务的Endpoint信息。
Policy:安全策略或者访问控制,一个基于规则的身份验证引擎,通过配置文件来定义各种动作与用户角色的匹配关系。
Resource:提供关于Domain和Project的数据。
Assignment:提供关于Role和Role Assignment的数据,负责角色授权。
Keystone与其他服务的交互关系
- KEYSTONE
- Keystone为其他项目提供认证
- 外部请求调用OpenStack内部的服务时,需要先从Keystone获取到相应的Token
- OpenStack内部不同项目间的调用也需要先从Keystone获取到认证后才能进行
!tip
在OpenStack的整体框架结构中,Keystone的作用类似于一个服务总线,Nova、Glance、Horizon、Swift、Cinder及Neutron等其他服务都通过Keystone来注册其服务的Endpoint,针对这些服务的任何调用都需要经过Keystone的身份认证,并获得服务的Endpoint来进行访问。
Keystone架构
Keystone架构

!tip
Keystone Middleware是Keystone提供的对令牌合法性进行验证的中间件。
比如,在客户端访问Keystone提供的资源时提供了PKI类型的令牌,为了不必每次都通过Keystone服务的直接介入来验证令牌的合法性,通常可以在中间件上进行验证,前提是中间件上已经缓存了相关的证书与密钥以对令牌进行签名认证。
如果不是PKI类型的令牌,则需要通过keystoneauth获得一个与Keystone服务连接的session,并通过调用Keystone服务提供的API来验证令牌的合法性。
对于Keystone项目本身,除了后台的数据库,主要包括一个处理RESTful请求的API服务进程。这些API涵盖了Identity、Token、Catalog和Policy等Keystone提供的各种服务,这些不同服务所能提供的功能则分别由相应的后端Driver(Backend Driver)实现。
Keystone各组件作用
| 组件 | 作用 |
|---|---|
| Keystone API | 接收外部请求 |
| Keystone Middleware | 缓存Token等,减轻Keystone Services压力 |
| Keystone Services | 不同的Service提供不同的认证或鉴权服务 |
| Keystone Backends | 实现Keystone服务,不同的Service由不同的Backend提供 |
| Keystone Plugins | 提供密码、Token等认证方式 |
Keystone对象模型
Keystone对象模型

!tip
Keystone的管理主要是针对Identity、Resource、Assignment、Token、Catalog、Service,这些对象具体由其他更小的对象实现。
同时OpenStack各种资源和服务的访问策略由Policy定义。
Keystone对象模型-Service
- Keystone是在一个或多个端点(Endpoint)上公开的一组内部服务(Service)
- Keystone内部服务包括Identity、Resource、Assignment、Token、Catalog等
- Keystone许多内部服务以组合方式使用
- 例如,身份验证时将使用认证服务(Identity)验证用户或项目凭据,并在成功时创建并返回带有令牌服务(Token)的令牌
- 除内部服务外,Keystone还负责与OpenStack其他服务(Service)进行交互,例如计算,存储或镜像,提供一个或多个端点,用户可以通过这些端点访问资源并执行操作

Keystone对象模型-Identity
- Identity服务提供身份凭据验证以及用户(User)和用户组(Group)的数据
- User是单个OpenStack服务使用者,用户本身必须属于某个特定域。所有用户名不是OpenStack全局唯一的,仅在其所属域唯一
- Groups把多个用户作为一个整体进行管理。组本身必须属于某个特定域。所有组名不是OpenStack全局唯一的,仅在其所属域唯一

!tip
通常情况下,用户和用户组数据由Identity服务管理,允许它处理与这些数据关联的所有CRUD操作。
复杂情况下,用户和用户组数据由权威后端服务管理。
例如,Identity充当LDAP的前端,LDAP服务器是权威的信息来源, Identity准确地中继LDAP信息。
Keystone的服务Service包括内部服务和外部服务,这里外部和内部是针对Keystone本身来讲,有些服务可以在Keystone内部完成,并直接返回结果。Keystone还可以负责与OpenStack其他服务,这里是指其他组件进行交互,交互完成后会提供一个或者多个端点给到用户,这些端点可以理解为访问路径或者一个链接,用户可以通过这些端点访问资源并执行操作。
Keystone对象模型-Resource
- Resource服务提供有关项目(Project)和域(Domain)的数据
- Project是OpenStack资源拥有者的基本单元,OpenStack中所有资源都属于特定项目
- Domain把项目、用户和组作为一个整体管理,每种资源都属于某个特定域。Keystone默认域名为"Default"

!tip
项目本身必须属于某个特定域。所有项目名不是OpenStack全局唯一的,仅在其所属域唯一。
创建项目时如果未指定域,则将其添加到默认域。
Keystone对象模型-Assignment
- Assignment服务提供有关角色(Role)和角色分配( Role Assignment)的数据
- Role规定最终用户可以获得的授权级别。角色可以在域或项目级别授予。可以在单个用户或组级别分配角色。角色名称在拥有该角色的域中是唯一的
- Role Assignment是一个3元组,有一个Role,一个Resource和一个Identity


Keystone对象模型-Token
- Token服务提供用户访问服务的凭证,代表着用户的账户信息
- Token一般包含User信息、Scope信息(Project、Domain或者Trust)、Role信息

Keystone对象模型-Catalog
- Catalog服务提供用于查询端点(Endpoint)的端点注册表,以便外部访问OpenStack服务
- Endpoint本质上是一个URL,提供服务的入口,有如下几种:
- Public:最终用户或其他服务用户使用,通常在公共网络接口上使用
- Internal:供最终用户使用,通常在未计量的内部网络接口上
- Admin:供管理服务的用户使用,通常是在安全的网络接口上
bash
"catalog":
"name": "Keystone",
"type": "identity",
"endpoints":
"interface": "public",
"url": "https://identity.example.com:5000/"

!tip
用户与OpenStack中的服务可以通过Catalog来获取其他服务的Endpoint,这些Endpoint是服务通过Keystone进行注册时由Keystone进行维护的,Catalog就是Endpoint的一个集合,提供用于查询端点(Endpoint)的端点注册表,以便外部访问OpenStack服务。
Endpoint本质上是一个URL,提供一个服务的入口,每个服务可以有一个或多个Endpoint,通过认证的外部请求,如果需要访问某个服务,只需要知道服务的Endpoint即可。如图所示,是一个catalog目录下显示的端点,服务名Keystone,类型是Identity,提供访问端点入口是Public,用户可以直接访问。
Endpoint分为Admin、Internal和Public,这些不同类型的Endpoint分别开放给不同的用户或服务。例如,对于Public URL,一般会对所有用户开放,允许用户通过外部网络进行访问,通常是在公共网络接口上使用;Admin URL会对一些用户或URL进行限定,只允许具有特定操作权限的用户访问,通常只提供给有管理权限的用户使用,是在安全的网络接口上使用的;Internal URL限定于那些安装有OpenStack的主机才可以访问,一般是内部组件互通,通常在未计量的内部网络接口上使用。
Keystone对象模型-Policy
- 每个OpenStack服务都在相关的策略文件中定义其资源的访问策略(Policy)
- 访问策略类似于Linux中的权限管理,不同角色的用户或用户组将会拥有不同的操作权限
- 访问策略规则以JSON格式指定,文件名为policy.json
- 策略文件的路径是/etc/SERVICE_NAME/policy.json,例如/etc/keystone/policy.json
bash
{
"admin_required": "role:admin",
"cloud_admin": "rule:admin_required and domain_id:admin_domain_id",
"default": "rule:admin_required",
"identity:get_service": "rule:admin_or_cloud_admin",
"identity:list_services": "rule:admin_or_cloud_admin",
"identity:create_service": "rule:cloud_admin"
}

Keystone对象模型分配关系示例(一)

Keystone对象模型分配关系示例(二)
- Region,Service, Endpoint:

!tip
Keystone的Catalog中包含不同Region中的不同Service(Keystone的服务),每个Service一般提供不同类型的Endpoint。
用户和Keystone中的服务,在交互过程中主要做了些什么呢,普通User主要使用Keystone来验证身份,获取相应的身份凭证Token,还可以获取需要访问使用的Service Catalog。Admin User的权限比较高,一般情况只用于管理操作。它主要可以管理Keystone中的Users、Projects、Roles,管理特定Project中用户的角色,管理不同的Services和Services中的Endpoint等。最后Keystone中的服务为用户验证Token的有效性,定位其他Service的位置并提供位置Endpoint给用户,也可以调用其他Service。
Keystone对象模型使用示例
- User:
- 获取Token
- 获取Service Catalog
- Admin User:
- 管理Users,Projects,Roles
- 管理特定Project中Users的Roles
- 管理Services,Services的Endpoints
- Service:
- 验证Token
- 定位其他Service的位置
- 调用其他Service
Keystone工作原理和流程
Keystone认证方式概览
- Keystone最重要的工作是认证,Keystone支持多种认证方式

!tip
UUID:Universal Unique Identifier。
PKI:Public Key Infrastructure。
Keystone三种认证方式对比
- 生产环境中常用的是基于令牌的认证方式,需要重点学习

Keystone基于令牌的认证-UUID

!tip
首先是UUID,Universal Unique Identifier通用唯一标识符。
UUID是一个32 Byte长的随机字符串,不携带任何其他信息,只作为Token ID,发送请求时,将这个Token ID以X-Auth-Token的方式传入。
OpenStack API在收到该令牌后,会找Keystone进行令牌校验,并获取相关用户信息。
Keystone基于令牌的认证-PKI

!tip
PKI,Public Key Infrastructure公钥基础设施。
PKI的本质是基于数字签名进行验证。Keystone私钥对令牌进行数字签名,各个OpenStack服务的API server用公钥在本地验证该令牌。
具体验证过程就像这张图上显示的,首先用户将用户名和密码发送给Keystone,Keystone使用私钥加密秘钥生成令牌返回给客户端。客户每次向OpenStack 发送调用资源和服务请求时会携带这个Token令牌,OpenStack 服务API会使用本地公钥对令牌进行验证。
和UUID相比,PKI令牌携带更多信息,同时还附上数字签名,以支持本地认证,避免多次找Keystone进行认证。
因为携带的信息较多,所以当OpenStack的规模较大时,Token所占的字节数据就超过了HTTP标准头的大小,有可能导致认证失败。
Keystone基于令牌的认证-PKIZ

!tip
为了解决PKI数据较大问题,出现了另一种验证方式PKIZ。PKIZ在PKI的基础上做了压缩处理,但是压缩效果有限。
一般情况下,压缩后的大小为PKI令牌的90%左右,所以最后发现效果也不是很明显。
在这张图上我们可以看出,验证流程与PKI基本一致。
唯一的差别是在Keystone生成Token并返回给客户端时进行了压缩。
Keystone基于令牌的认证-Fernet

!tip
UUID,PKI,PKIZ令牌都会持久存放在数据库中,累积的令牌容易导致数据库性能下降,用户需定期清理数据库中的令牌。
为避免该问题,OpenStack目前版本都默认使用Fernet令牌,携带少量的用户信息,采用对称加密,无需存于数据库中,但需定期更换秘钥。
Fernet的验证流程第一步,用户将用户名和密码发送给Keystone,Keystone使用秘钥生成临时令牌并返回给客户端。客户每次向OpenStack发送调用资源和服务请求时,会携带这个Token令牌,OpenStack服务API接收到请求后会将Token发送到Keystone进行验证,由Keystone验证其有效性和合法性。验证成功返回信息。
这个过程看似与UUID一样,但是其实是有区别的,UUID由于没有加密和解密过程,Keystone在生成token之后要本地缓存Token,方便后面验证。但是Fernet进行对等验证,无需缓存token,每次验证只需要进行解密验证即可,无需持久化存储,大小也合适,比较适合多数据中心的场景。
如何选择Keystone基于令牌的认证方式?
| Token 类型 | UUID | PKI | PKIZ | Fernet |
|---|---|---|---|---|
| 大小 | 32 Byte | KB 级别 | KB 级别 | 约 255 Byte |
| 支持本地认证 | 不支持 | 支持 | 支持 | 不支持 |
| Keystone 负载 | 大 | 小 | 小 | 大 |
| 存储于数据库 | 是 | 是 | 是 | 否 |
| 携带信息 | 无 | User,catalog 等 | User,catalog 等 | user 等 |
| 涉及加密方式 | 无 | 非对称加密 | 非对称加密 | 对称加密(AES) |
| 是否压缩 | 否 | 否 | 是 | 否 |
- 目前OpenStack新发布版本默认采用Fernet令牌
!tip
令牌类型的选择涉及多个因素,包括Keystone server的负载、region数量、安全因素、维护成本以及令牌本身的成熟度。
Region的数量影响PKI/PKIZ令牌的大小。
从安全的角度上看,UUID无需维护密钥,PKI需要妥善保管Keystone server上的私钥,Fernet需要周期性的更换密钥。
因此从安全、维护成本和成熟度上看,UUID > PKI/PKIZ > Fernet 。
如果:
Keystone server 负载低,region少于3个,采用UUID令牌。
Keystone server 负载高,region少于3个,采用PKI/PKIZ令牌。
Keystone server 负载低,region大与或等于3个,采用UUID令牌。
Keystone server 负载高,region大于或等于3个,目前OpenStack新版本默认采用Fernet令牌。
OpenStack认证流程-以创建VM为例
- Keystone只检验Token是否有效,那每个服务的操作权限控制是怎么实现的?

!tip
我们以创建VM为例,站在整个OpenStack角度来看一下,整个认证流程是怎样的。
首先用户需要使用OpenStack,第一步就要向Keystone提供用户名密码来获取Token。当用户获取Token后,需要向Nova发送创建虚拟机请求,Nova负责调用计算资源并管理虚拟机的生命周期,所以这个创建请求要发送到Nova。请求的Head中会携带Token,当Nova-api接收到请求后,会将Token传递到Keystone进行验证是否有效合法。当验证成功后返回信息给Nova,Nova才开始进行创建VM操作。这边不具体介绍Nova如何操作,但是我们知道创建一台虚拟机,不仅需要准备CPU、内存等计算资源,还要有相应的网络、存储等资源,这里以网络资源为例,Nova-api将token透传给Nova-compute,Nova-compute会向Neutron-server发送与网络相关操作请求,请求Head中也携带Token,Neutron收到请求后也会将Token传递到Keystone验证,验证成功才执行相应操作。
这个流程中我们可以看到,不同服务间的调用也要携带Token,并且Keystone只校验了Token的有效性,那么每个服务的操作权限控制是怎么实现的呢?
RBAC,基于角色的访问控制如何实现?
- 创建VM时,不同OpenStack服务需要交互,Keystone会发放和校验Token有效性,但每个服务如何检验用户的操作权限呢?
- 例如用户是否有创建VM权限,是否有更改VM规格权限?
- 请大家花5分钟,思考或讨论OpenStack中基于角色的访问控制如何实现?
- 日常生活中有哪些基于角色的访问控制?
- 本章节哪个地方有提到Keystone访问控制相关知识?
RBAC:基于角色的访问控制-流程
- Keystone提供统一的Policy模块
- policy.json一般存在于组件的配置文件目录下policy.json文件修改后实时生效,不需要重启服务
- Token认证只认证token的有效性,权限控制在各个服务组件内部实现

!tip
在OpenStack中使用RBAC进行访问控制,RBAC是基于角色访问控制(Role-Based Access Control),在RBAC中,权限与角色相关连,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理,这样管理都是层级相互依赖的,权限直接赋予给角色,而把角色又赋予给用户,这样的权限设计很清楚,管理起来也很方便。RBAC认为授权实际上是Who/What/How三元组之间的关系,Who是权限的拥有或者主体,例如User,Role。What是操作或对象,如Operation,Object。How是具体的权限,授权,Privilege。所以组合到一起就是Who对What进行了How操作。如图所示,首先客户发送请求,由Keystone的Token模块进行Token有效性认证,认证通过后,由Policy模块来验证Auth context,即认证上下文,实际上Policy.json文件是实现RBAC的关键机制,之前我们在介绍Policy的时候也提到过,该文件一般存于组件的配置目录下,该文件在修改后立即生效,不需要重启服务。整个验证过程如果成功,进行下一步反馈信息。如果失败直接反馈403禁止,表示权限认证失败。
RBAC:基于角色的访问控制-原理
- Policy模块在检测时需要三方面的数据:
- 1、policy.json策略配置文件
- 2、auth_token添加到http头部的token数据
- 3、用户的请求数据

!tip
Policy模块在检测时需要三方面的数据,第一个是policy.json策略配置文件,保存在服务配置目录下,第二个是auth_token添加到http头部的token数据,就是前面说到的基于令牌认证中的那些令牌数据。还有用户请求数据,到底请求哪些内容。
在图中实例policy.json文件中,定义了all_admin包含了哪些角色,admin和internal_admin。定义了list_project针对all_admin的具体规则,create project时需要admin角色。
在处理的过程中,验证Token有效性,根据用户的请求信息到policy.json策略配置文件验证其用户是否有对应角色和权限。
Keystone如何实现认证和权限控制?
- 用户在OpenStack控制面板上创建一个VM,Keystone如何认证该用户,如何验证该用户具有创建VM的权限?
- 用户在OpenStack CLI上创建一个VM,Keystone如何认证该用户,如何验证该用户具有创建VM的权限?
- 两种方式对Keystone有区别吗?
!tip
无论是操作界面或是CLI,Keystone的认证和权限控制原理都是一样的,发放Token,验证Token,都是通过Policy.json实现权限控制。
总结: Keystone如何实现认证和权限控制

!tip
首先用户发送基本信息给Keystone,一般是用户名和密码。Keystone经过验证后会返回一个Token给用户,用户向Nova发送创建虚拟机请求,并携带Token信息,nova接收到请求后,会拿着Token去Keystone进行验证,验证成功后开始执行创建VM操作,Nova会向Glance发送申请镜像信息并携带Token,会向Neutron发送申请网络信息也会携带Token,Glance和Neutron组件接收到请求后,都会向Keystone验证Token的有效性(图中仅用了一条线表示,请注意理解),验证通过即执行相应的操作,返回完成信息,当VM创建完成后,Nova返回创建成功信息给用户,用户即可使用虚拟机。
olicy.json实现权限控制。