1. 引言
OpenStack项目成立于2010年,Keystone作为身份服务组件是部署OpenStack云平台的唯一强制服务 [1]。通过创建租户、用户、角色并持久化到mysql数据库中,在客户端输入用户名密码,Keystone验证通过后返回Token作为用户身份令牌,用户获取服务时,Keystone根据令牌验证的结果来确定用户权限。
目前Keystone采用的Token有:UUID token、PKI token、PKIZ token、Fernet token。在UUID token中,用户获取Token时其余服务节点依靠Keystone确认Token的有效性,认证简单,但是若存在大量认证会造成Keystone负荷过重。在PKI token中支持其余组件在本地认证,却需要CA颁发证书,但证书过大会造成请求失败。PKIZ token虽然对证书进行了压缩,但是也存在证书过大的缺点。Fernet token为保证安全性则需要定期更换对称密钥。基于以上认证的不足本文提出一种基于用户标识的Openstack身份认证协议,利用双因子CPK技术和hash函数,支持本地认证,减轻Keystone负荷,同时利用hash函数将数据量减小解决PKI token过大的缺点。同时利用双因子CPK的安全性,解决Fernet token中需要定期更换对称密钥的不足的问题。
2. 相关工作总结
2.1. OpenStack架构
OpenStack由美国国家航天航空局(NASA)和Rackspace合作开发,Apache许可证开源,是一个旨在提供基础设施即服务的虚拟化管理平台,能够提供可靠的云部署方案 [2]。OpenStack覆盖了网络、虚拟化、操作系统、服务器等各个方面。OpenStack包含多个组件,各个组件之间既可以相互配合工作也可以独立部署完成各自的功能,在Essex版本之前,OpenStack的各个子项目如Nova、Swift均使用各自独立的认证系统,从Essex版本之后开始全面支持Keystone提供统一的身份认证服务 [3]。主要模块及功能如下。
2.1.1. 计算(Compute):Nova
控制器,用于为单个用户或使用群组管理虚拟机实例的整个生命周期,根据用户需求来提供虚拟服务。负责虚拟机创建、开机、关机、挂起、暂停、调整、迁移、重启、销毁等操作,配置CPU、内存等信息规格。
2.1.2. 对象存储(Object Storage):Swift
用于在大规模可扩展系统中通过内置冗余及高容错机制实现对象存储的系统,允许进行存储或者检索文件。可为Glance提供镜像存储,为Cinder提供卷备份服务。
2.1.3. 镜像服务(Image Service):Glance
虚拟机镜像查找及检索系统,支持多种虚拟机镜像格式(AKI、AMI、ARI、ISO、QCOW2、Raw、VDI、VHD、VMDK),有创建上传镜像、删除镜像、编辑镜像基本信息的功能。
2.1.4. 身份服务(Identity Service):Keystone
为OpenStack其他服务提供身份验证、服务规则和服务令牌的功能,管理Domains、Projects、Users、Groups、Roles。
2.1.5. 网络&地址管理(Network):Neutron
提供云计算的网络虚拟化技术,为OpenStack其他服务提供网络连接服务。为用户提供接口,可以定义Network、Subnet、Router,配置DHCP、DNS、负载均衡、L3服务,网络支持GRE、VLAN。插件架构支持许多主流的网络厂家和技术,如OpenvSwitch。
2.1.6. 块存储(Block Storage):Cinder
为运行实例提供稳定的数据块存储服务,它的插件驱动架构有利于块设备的创建和管理,如创建卷、删除卷,在实例上挂载和卸载卷。
2.1.7. UI界面(Dashboard):Horizon
OpenStack中各种服务的Web管理门户,用于简化用户对服务的操作,例如:启动实例、分配IP地址、配置访问控制等。
2.2. OpenStack的认证机制
Keystone中的User指代任何使用OpenStack的实体,可以是真正的用户,其他系统或者服务。当用户请求访问OpenStack时,Keystone会对其进行验证。主要有admin、demo两种用户。admin为OpenStack平台的超级管理员,负责OpenStack服务的管理和访问权限。demo为常规用户。除了admin和demo OpenStack也为nova,cinder,glance,nutron等服务也创建了相应的用户,admin可以对这些用户进行统一的管理。
Keystone中的Credentials是User用来证明自己身份的信息,可以是:用户名/密码、Token、API Key等其他高级方式。
Keystone中的令牌(Token)是一个字符串,每个令牌都拥有一个具体的权限范围,令牌可以确定用户能访问的资源。如果用户每次都采用用户名/密码访问OpenStack API,容易泄露用户信息,带来安全隐患,所以OpenStack要求用户访问其API前,必须先获取Token,然后Token作为用户凭据再进行访问。用户向Keystone发送验证请求,并提交证书,Keystone验证证书响应请求为用户颁发一个身份认证令牌Token。
Keystone中的Project用于将OpenStack的资源(计算、存储和网络)进行分组和隔离。根据OpenStack服务对象不同,Project可以是一个租户、部门或者项目云。在Openstack中资源的所有权属于Project而不是用户,每个用户必须挂在Project里才能访问该Project的资源。一个用户可以属于多个Project。
keystone中的Endpoint是一个网络上可以访问的地址,通常是一个URL。各个服务通过Endpoint暴露自己的API。Keystone负责管理和维护每个服务的Endpoint。
keystone中的Role表示用户角色,代表特定的租户中的用户操作权限。
Keystone用于为OpenStack中的其它组件成员提供统一的认证服务,包括身份验证、令牌的发放和校验、服务列表、用户权限的定义等等。OpenStack中所有的服务之间的授权和认证都需要经过Keystone。因此Keystone是云平台中第一个立即需要安装的服务。作为OpenStack的基础支持服务,Keystone主要用于管理用户及其权限、维护OpenStack services的endpoint (服务地址)、Authentication (认证)和Authorization (鉴权)。
OpenStack的请求服务流程如图1所示:

Figure 1. Keystone’s authentication and request service process
图1. Keystone的认证及请求服务流程
用户通过Horizon可视化界面提供Credentials给Keystone,其中Credentials为用户用来证明自己身份的信息,可以是用户名/密码、Token、API Key或者其他高级方式。Keystone验证通过后返还给用户令牌(Token),用户使用分配的Token进行对其他服务的访问,提供Token和访问请求到目标地址,其他服务请求Keystone验证Token并返回结果来判断用户是否有该权限,从而选择是否给用户提供服务。
2.3. Keystone现有的认证方式及缺陷
2.3.1. UUID认证方式
用户在登陆时通过HorizonWEB前端的管理界面服务输入自己的用户名/密码或者用户名密码环境变量。Keystone验证用户名密码,并且生成Token。
客户端存储UUID token然后发送具体的执行请求给服务节点,服务节点发送Token给keystone请求keystone辅助验证,Keystone从http请求中获取Token,并检查Token有效性并返回结果给服务节点。若token有效则处理结果并返回客户端结果,若Token失败则拒绝客户但请求,并返回401。
UUID token简单易用,且长度仅为32Byte,此外,Token的生命周期很短,默认是24 h,这意味着用户在Token过期后需要重新进行身份认证 [4]。同时这种认证方式也容易给Keystone带来性能问题,因为UUID token不携带其它信息,OpenStack API收到该Token后,既不能判断该Token是否有效,更无法得知该Token携带的用户信息。每当OpenStack API收到用户请求,都需要向Keystone验证该Token是否有效。随着集群规模的扩大,Keystone需处理大量验证Token的请求,在高并发下容易出现性能问题。UUID认证方式如图2所示:
2.3.2. PKI认证
Keystone相当于一个权威的认证中心,他用自己和的私钥对用户的Token进行签名。OpenStack服务中的每一个API节点都有一份Keystone签发的证书,失效列表和根证书。API不用在直接去Keystone认证Token是否合法,只需要根据Keystone的证书和失效列表就可以确定Token是否合法。但是这里还是会有每次都需要请求Keystone去获取失效列表的操作,不可避免。与UUID相比,PKI token携带更多用户信息的同时还附上了数字签名,以支持本地认证。但是因为PKI token携带了更多的信息,这些信息就包括service catalog,随着OpenStack的Region数增多,service catalog携带的endpoint数量越多,很容易超出HTTP协议允许的最大HTTP请求头大小(默认为8 KB),导致HTTP请求失败。PKI认证方式如图3所示:
2.3.3. PKIZ认证
PLIZ与PKI基本一致,但是PKIZ在PKI的基础上做了压缩处理,但是压缩的效果极其有限,一般情况下,压缩后的大小为PKI token的90%左右,所以PKIZ也不能友好的解决Token太大问题。
2.3.4. Fernet认证
Fernet是专为API token设计的一种轻量级安全消息格式,它采用cryptography对称加密库加密Token,具体由AES-CBC加密和散列函数SHA256签名,Token只能通过对称密钥读取和更改,不需要持久化Token,且fernet token只加密必要的信息,长度一般不超过255字节,避免了PKI token过大的问题。同时fernet token不需要存储于数据库,减少了磁盘的IO,解决了Keystone数据库由于存储了大量的Token导致性能变差,需要经常清理Token的问题。但为了提高安全性,需要采用需要定时更换对称密钥。Fernet认证方式如图4所示:

Figure 4. Fernet authentication method
图4. Fernet认证方式
Token类型的选择涉及多个因素,包括Keystone服务器的负载、安全因素、维护成本以及Token本身的成熟度。从安全的角度上看,UUID方式中每个请求都带着一个Token,Token不管到哪个服务,该服务都会先去验证Token的合法性,然后再去执行用户请求的操作 [5],但无需维护密钥,PKI token需要妥善保管Keystone服务器上的私钥,Fernet token需要周期性的更换密钥,均有不同的优势和不足,因此从安全、维护成本和成熟度上看,UUID token > PKI token/PKIZ token > Fernet token,所以综合比较Keystone选择的默认认证方式为UUID。因为原有的认证方式均无法同时兼顾效率和安全性,这里我们利用组合公钥(CPK)技术提出一种全新的基于用户标识的身份认证协议,来改善认证系统。
3. 基于用户标识的身份认证协议
3.1. 认证流程
在组合公钥(CPK)体制中,组合密钥由标识密钥、系统密钥、更新密钥组成。标识密钥(Identity-Key)由实体的标识通过组合矩阵生成。系统密钥(System-Key)是由中心为各个体定义的随机序列,与标识密钥复合产生一阶组合密钥。更新密钥由个人自行定义,与一阶组合密钥再次复合,形成二阶组合密钥。
以此为基础我们引出了基于用户标识的身份认证协议。在本协议中用户私钥由两部分组成,第一部分为Keystone生成的标识私钥,第二部分私钥为用户自己生的伴随密钥,两者结合成为用户私钥。同理,公钥也由两部分组成,一部分为通过公钥矩阵生成为的标识公钥,另一部分为用户生的伴随私钥,两者结合为用户公钥。组合矩阵分为私钥矩阵和公钥矩阵。私钥矩阵仅存在于Keyetone中,公钥矩阵存在于用户客户端和各个服务节点。公钥矩阵和私钥矩阵均为32行32列,标识到矩阵坐标的映射是通过标识的HASH 变换实现的,将HASH输出结果调整成190比特的映射序列,每5比特决定一个列坐标或行坐标,具体生成过程参考文献 [6]。
本协议在生成过程中默认用户和Keystone已经协商有共享密钥,协议中用到的符号及描述如表1所示:

Table 1. Notation of authentication protocol
表1. 认证协议符号记法
1) 用户在生成请求Token时,首先在本地生成伴随密钥(用户自定义产生的伴随私钥askA和伴随公钥APKA),并且将伴随公钥和请求信息一同发送给Keystone。
US→KS:ESK (APKA || m)
2) Keystone在返还给用户消息时,首先使用用户ID、时间戳T和权限计算散列函数值,然后再根据散列函数值(H(ID||T||AU))查找标识私钥矩阵得到标识私钥(iskA),同时成标识公钥(IPKA),然后对用户生成的伴随公钥和标识公钥进行点加运算,生成组合公钥CPKA,其中CPKA = APKA+ IPKA mod n,Keystone对伴随公钥进行签名,表示对用户该部分公钥的认可。最终Keystone将标识私钥、签名后的伴随公钥和组合公钥发送给用户。
KS→US:ESK (iskA || SIGSKS (APKA) || CPKA)
3) 用户在请求其余节点服务时,用组合私钥cskA (其中cskA = iskA + askA mod n)对自身ID、服务截止时间戳T (与第一次法送给Keystone服务的时间一致)和权限进行签名作为Token,并将Token、Keystone签名过的标识公钥,未经签名的标识公钥一同发送给服务节点。
US→S:SIGcskA (ID || T | |AU) || ID || T || AU || SIGSKS (APKA) || APKA
4) 服务节点分理出未经加密的原信息和T,先根据T验证用户申请是否过期,若失效则不提供服务。同时验证Keystone签名若通过则认可用户发送的标识公钥(APKA),若不通过则拒绝服务,若以上两步验证均通过则进行以下验证。服务节点将原信息经过散列函数处理后根据本地标识公钥矩阵查找用户标识公钥(IPKA),再将标识公钥与伴随公钥点加得到用户的组合公钥CPKA,利用公钥对签名信息进行验签。比较验签后的签名和与原信息经过散列函数是否一致,若一致则用户请求正确,若不一致则表示用户请求为伪造,拒绝提供服务。
本协议的认证流程如图5所示:
3.2. 分析总结
· 服务器无需保存用户公私钥,Keystone只需要保存私钥矩阵,各个其余服务节点只需要保存公钥矩阵即可验证用户身份和权限,由于私钥矩阵在中心,攻击者无法通过其余服务组件得到用户私钥,用户仅需保存好本次申请的私钥就能保证密钥安全性。
· 由于用户的一部分私钥由中心生成,且此部分私钥的生成与用户ID、截止时间和权限相绑定,用户无法做到伪造此部分私钥,故用户无法更改Token的有效时间和自身权限。保证了用户的权限。
· 此协议与UUID、PKI认证相比较,在验证Token有效性时无需通过Keystone辅助减少了对Keystone的压力,支持服务节点进行本地验证,验证过程简单快速。与Fernet认证相比,无需定期更换对称密钥,当用户Token过期后只需要重新申请即可得重新得到新的密钥。且此验证方法依靠组合公钥密码体制具有破密难度大、超大规模密钥管理能力、资源消耗小、管理简便、密钥本身直接证明标识的真伪而无需第三方证明的显著优点 [7]。
· 引文 [8] 采取了一种基于数字证书的身份认证方式,使用Ukey设备与用户名密码相结合,采用双层认证,用户在请求资源时,首先需要使用Ukey设备完成第一步认证,在得到证书后,还需向密码服务器发送认证,共需17次对话才能完成认证,虽然安全性大大提升,但是认证过程过于复杂。引文 [9] 采用了一种基于OpnenID的身份认证,本文与其相比,私钥中的伴随私钥为用户自己生成,并不在服务器中保存,增加了用户密钥的安全性。在引文 [10] 中身份认证协议依证书颁发机构CA颁发证书,在本文中依靠CPK组合公钥,给予用户主动设置部分私钥权力,私钥只有用户完全拥有,提升了安全性。
4. 结束语
本文重点对OpenStack云平台中的基于Keystone的身份认证机制进行了研究,介绍了OpenStack中的各个组件的作用,着重分析了Keystone身份认证方式,深入探究原有的UUID,PKI,PKIZ认证方式优缺点。分析了云平台的安全策略和威胁并在原有的UUID,PKI,PKIZ和Fornet认证的基础上结合CPK双因子进行改进,减少了在验证用户身份时对Keystone的依赖,同时也降低了对于用户Token的存储,提高了用户身份认证时的效率。
基金项目
郑州大学大学生创新创业训练计划资助项目。