Keystone/Middleware
- Launchpad Entry: NovaSpec:openstack-authn
- 创建: 10-29-2010
OpenStack 中的身份验证
Jorge L Williams < jorge.williams@rackspace.com >
Khaled Hussein < khaled.hussein@rackspace.com >
Ziad N Sawalha < ziad.sawalha@rackspace.com >
摘要
本蓝图的目的是为 OpenStack 中的身份验证定义一个标准,使服务能够以可插拔的方式支持多种身份验证协议。通过提供对通过可插拔身份验证组件进行身份验证的支持,该标准允许 OpenStack 服务轻松集成到现有的部署环境中。它还提供了一种途径来实现对新兴身份验证标准(如 OpenID)的支持。该标准本身不是一个身份验证系统,而是一个协议,通过该协议可以将身份验证系统与 OpenStack 服务集成。
目录
原理和目标
目前,OpenStack 不支持其存储和计算服务的统一身份验证机制。这使得在单个环境中部署这些服务变得复杂,并阻止 OpenStack 轻松与现有的身份验证和身份管理系统集成。为了解决这个问题,我们提出一个身份验证标准,该标准允许通过可插拔的身份验证组件支持多种身份验证协议。
在本蓝图中,我们定义了身份验证组件的职责。我们描述了它们如何与底层的 OpenStack 服务交互,以及如何修改现有服务以利用可插拔的身份验证。我们的目标是允许 OpenStack 服务轻松集成到现有的部署环境中,并提供一种途径来实现对新兴身份验证标准(如 OpenID)的支持。
规范概述
身份验证是确定用户就是他们所声称的身份的过程。通常,身份验证协议(如 HTTP Basic Auth、Digest Access、公钥、令牌等)用于验证用户的身份。在本蓝图中,我们将身份验证组件定义为实现 OpenStack 服务身份验证协议的软件模块。
从高层来看,身份验证组件只是一个反向代理,它拦截来自客户端的 HTTP 调用。一旦它验证了用户的身份,身份验证组件就会将有关当前用户的的信息扩展到调用中,并将请求转发到 OpenStack 服务。否则,如果用户的身份未经验证,则在到达服务之前拒绝该消息。这在 图 1 中说明。
图 1. 身份验证组件
身份验证组件可以以委托模式运行。在这种模式下,拒绝未经验证客户端的决定委托给 OpenStack 服务。委托模式在 图 2 中说明。在这里,请求会连同身份状态消息一起转发到 OpenStack 服务,该消息指示客户端的身份是否已确认或不确定。OpenStack 服务决定是否向客户端发送拒绝消息。请注意,始终由身份验证组件负责将拒绝消息传输到客户端。
图 2. 身份验证组件(委托模式)
在本蓝图中,我们定义了身份验证组件与 OpenStack 服务之间的交互。客户端与身份验证组件之间的交互仅针对特殊情况进行定义。例如,我们定义了在 OpenStack 服务关闭时应返回的消息。但是,其他交互由底层的身份验证协议和 OpenStack 服务定义,并且被认为超出范围。
部署策略
身份验证组件可以直接集成到服务实现中,或者可以作为 HTTP 反向代理单独部署。这在 图 3 中说明,显示了两种方法,分别标记为选项 (a) 和选项 (b)。
图 3. 身份验证组件部署选项
在选项 (a) 中,该组件集成到服务实现中。在这种情况下,身份验证组件和服务的通信可以通过方法调用有效地实现。在选项 (b) 中,该组件单独部署,服务和组件之间的通信涉及 HTTP 请求。在两种情况下,未经身份验证的请求都会在到达服务之前被过滤掉。
每种方法都提供一些好处。选项 (a) 提供低延迟和易于初始实现,使其可能最适合简单的配置的起点。选项 (b) 提供了一些关键优势,这些优势在复杂和动态的配置中可能特别有价值。它能够在身份验证计算成本高昂的情况下(例如,验证数字签名时)实现水平扩展。选项 (b) 还允许使用不同的编程语言编写身份验证组件。最后,选项 (b) 允许将多个身份验证组件部署在同一服务的前面。
OpenStack 服务必须支持嵌入式(选项 (a))和外部(选项 (b))部署策略。单个身份验证组件可以支持任一策略,或者可以同时支持两种策略。为了支持选项 (a),用 Python 编程语言编写的身份验证组件必须按照 Web Server Gateway Interface (WSGI) 标准 [pep0333] 编写为中间件组件。此外,服务必须支持通过配置选项在不同的嵌入式或外部身份验证组件之间进行切换。
交换用户信息
如果请求成功通过身份验证,身份验证组件必须通过添加 `X-Authorization` 标头来扩展请求。标头必须按照 示例 1 所示的格式进行格式化。
示例 1. X-Authorization 标头
X-Authorization: Proxy JoeUser
在这里,`Proxy` 表示身份验证是通过代理(在本例中为身份验证组件)发生的,JoeUser 是发出请求的用户的名称。
#!wiki note '''Note''' We are considering using an `Authorization` header rather than an `X-Authorization`, thereby following normal HTTP semantics. There are some cases, however, where multiple `Authorization` headers need to be transmitted in a single request. We want to assure ourselves that this will not break common clients before we recommend the approach.
身份验证组件可以通过附加信息扩展请求。例如,身份验证系统可以添加额外的标头或修改目标 URI 以将身份验证信息传递给后端服务。此外,身份验证组件可以从请求中删除敏感信息——例如,纯文本密码。也就是说,身份验证组件应该传递大部分未修改的请求。
反向代理身份验证
OpenStack 服务应该验证它是否正在从受信任的身份验证组件接收请求。这在身份验证组件和 OpenStack 服务单独部署的情况下尤其重要。为了信任传入的请求,OpenStack 服务因此应该对身份验证组件进行身份验证。为了避免混淆,我们将此称为反向代理身份验证,因为在这种情况下,身份验证组件充当 HTTP 反向代理。
可以使用任何基于 HTTP 的身份验证方案进行反向代理身份验证;但是,所有 OpenStack 服务和所有身份验证组件必须支持 RFC 2617 [rfc2617] 中定义的 HTTP Basic Authentication。
是否需要反向代理身份验证完全是一个部署问题。例如,操作团队可以选择使用防火墙规则而不是身份验证协议来验证传入请求的完整性。因此,OpenStack 服务和身份验证组件必须也允许未经身份验证的通信。
在使用了反向代理身份验证的情况下,身份验证组件可能会收到 HTTP 401 身份验证错误或 HTTP 403 授权错误。这些错误表明该组件无权访问底层的 OpenStack 服务。身份验证组件不得将这些错误返回给客户端应用程序。相反,该组件必须返回 500 内部错误。这在 图 4 和 5 中说明。该组件应该以不会破坏 OpenStack 服务定义的服务合同的方式格式化这些错误。 图 5 说明了委托模式下的代理授权。
图 4. 反向代理身份验证
委托模式
在某些情况下,拒绝未经验证请求的决定应该委托给 OpenStack 服务。未经验证的请求可能适用于允许匿名访问的情况。为了支持这些情况,身份验证组件可以放置在委托模式下。在这种模式下,该组件会将请求转发到 OpenStack 服务,当客户端的身份已确认或不确定时——也就是说,当缺少凭据时。身份验证组件直接拒绝具有无效凭据的请求。身份验证组件必须通过添加 `X-Identity-Status` 标头来扩展请求。身份状态标头必须包含以下值之一
身份状态值
- 已确认
-
- “已确认”值表示已发送有效的凭据并且身份已确认。服务可以信任请求是代表 `X-Authorization` 标头中指定的用户的请求。
- 不确定
-
- “不确定”值表示未发送凭据并且身份未确认。在这种情况下,服务将收到一个 `X-Authorization` 标头,其中没有用户条目,如 示例 2 所示。
示例 2. 不确定身份标头
X-Identity-Status: Indeterminate X-Authorization: Proxy
服务可以通过发出 HTTP 401 身份验证错误或 HTTP 403 授权错误来拒绝委托请求。这些响应必须包含一个 `WWW-Authenticate` 标头,其值为 `Delegated`,如 示例 3 所示。
示例 3. 委托 WWW-Authenticate 标头
WWW-Authenticate: Delegated
重要的是要注意,实际的拒绝消息可能会被身份验证组件修改,以便符合其正在实施的身份验证方案。这在 图 6 和 7 中说明。
图 6. 委托拒绝 Basic Auth
图 7. 委托拒绝 OAuth
具有 `WWW-Authenticate` 值 `Delegated` 的 `WWW-Authenticate` 标头存在与组件故障区分客户端身份验证/授权故障。例如,比较 图 8 与 图 5。在 图 8 中,客户端无权访问 OpenStack 服务。在 图 5 中,是身份验证组件本身未被授权。
图 8. 委托拒绝 Forbidden
身份验证组件必须支持委托和非委托(标准)模式。委托模式应该通过配置选项进行配置。委托模式应该默认禁用。
OpenStack 服务不需要支持委托模式。如果服务不支持委托模式,它必须使用 501 not implemented 错误以及 `WWW-Authenticate` 标头(其值为 `Delegated`)进行响应。身份验证组件不得将该错误返回给客户端应用程序。相反,该组件必须返回 500 内部错误;这在 图 9 中说明。该组件应该以不会破坏 OpenStack 服务定义的服务合同的方式格式化该错误。该组件还应该记录该错误,以便告知操作员配置错误。
图 9. 未实现委托模式
处理直接客户端连接
身份验证组件到 OpenStack 服务的请求必须包含 `X-Authorization` 标头。如果缺少标头,并且反向代理身份验证失败或被关闭,OpenStack 服务可以假定请求直接来自客户端应用程序。在这种情况下,OpenStack 服务必须通过发出 HTTP 305 User Proxy 重定向将请求重定向到身份验证组件。这在 图 10 中说明。请注意,重定向响应必须包含一个 `Location` 标头,该标头指定身份验证组件的 URL,如 示例 4 所示。
图 10. 身份验证组件重定向
示例 4. 身份验证组件重定向响应
HTTP/1.1 305 Use Proxy Date: Thu, 28 Oct 2010 07:41:16 GMT Location: http://sample.auth.openstack.com/path/to/resource
使用多个身份验证组件
在某些用例中,服务提供商可能希望为不同的目的使用多个身份验证组件。例如,服务提供商可能有一个身份验证方案来验证服务的用户,而另一个方案来验证维护服务的管理员或运维人员。对于此类场景,我们建议使用如图 图 11 所示的映射器。
图 11. 多个身份验证组件
从高层来看,映射器是一个简单的反向代理,它拦截来自客户端的 HTTP 调用,并将请求路由到适当的身份验证组件。映射器可以根据将资源映射到特定身份验证组件的若干路由规则做出路由决策。例如,请求 URI 可以确定调用应该通过哪个身份验证组件进行身份验证。
请注意,身份验证组件和 OpenStack 服务都不需要知道映射器的存在。任何外部身份验证组件都可以与其他组件一起使用。映射器可以提供一种支持对服务资源子集进行匿名或访客访问的方式。映射器可以通过传统的反向代理服务器(如 Pound 或 Zeus)来实现。
默认组件
各个服务必须默认分发一个简单的集成身份验证组件。提供这样的组件可以降低单个服务部署的障碍。这对于可能希望在自己的机器上部署 OpenStack 服务的开发人员尤其重要。此外,由于没有直接依赖于外部身份验证系统,OpenStack 服务可以单独部署,而无需启动和配置额外的服务。最后,所有服务共享的标准身份验证组件可以促进关注点分离。也就是说,作为社区,我们明确声明服务不应开发自己的身份验证机制。当然,可以开发额外的身份验证组件,但这些组件不应与任何特定服务紧密耦合。
如 “部署策略” 中所述,身份验证组件可以直接集成到服务实现中(选项 (a)),或者可以作为 HTTP 反向代理单独部署(选项 (b))。默认组件应实现以支持选项 (a),并且服务应维护对选项 (b) 的支持。实现此的一种方法是通过配置提供一种禁用默认身份验证组件的方法。如图 图 12 所示。在这里,当禁用默认身份验证组件时,请求将直接发送到 OpenStack 服务。
我们将在单独的蓝图文档中讨论默认组件的设计。
图 12. 禁用的嵌入式组件
问题与解答
- 为什么身份验证组件发送拒绝消息?为什么不让 OpenStack 服务自己拒绝请求?
- 身份验证失败消息的内容和格式由身份验证方案(或协议)确定。为了使服务能够做出适当的响应,它必须了解其参与的身份验证方案;这违背了可插拔身份验证组件的目的。
- 为什么要求支持在单独的节点中部署身份验证组件?
- 部署策略非常灵活。它允许身份验证组件进行水平扩展。它允许组件用不同的语言编写。最后,它允许同时部署不同的身份验证组件,如上所述。
参考文献
- Phillip J Eby. Python Web Server Gateway Interface v1.0. https://pythonlang.cn/dev/peps/pep-0333/。
- J Franks. P Hallam-Baker. J Hostetler. S Lawrence. P Leach. A Luotonen. L Stewart. HTTP Authentication: Basic and Digest Access Authentication. http://tools.ietf.org/html/rfc2617。