System Role Assignments¶
本文档描述了实施系统角色分配所需的更改。
问题描述¶
目前,角色分配是通过赋予一个 actor 在目标上扮演一个角色来实现的。一个 actor 可以是用户或组。目标仅限于项目或域。这对于控制映射到项目或域的事物(例如,实例所有权自然适合项目)的访问权限非常有效。对于不符合该约束的操作,这开始变得令人困惑。在超visor 上执行操作(例如 GET /os-hypervisors/)是一个不适合映射到项目的 API 的很好的例子。相反,从系统范围的角度而不是项目特定的角度来看待这些类型的操作更清晰。
系统角色分配将是一个目标为 system 而不是项目或域的分配。
全局范围与系统范围¶
关于此提案的初步讨论使用了全局范围一词,作为区分项目范围以外事物的手段。例如,对实例的操作很容易与项目关联,因为实例由项目拥有。端点或服务最初被认为是全局性质的,因为它们适用于整个部署。经过几次讨论后,很明显全局仍然不是我们想要的术语。另一个例子突出了全局一词的不足。从理论上讲,如果用户在部署中的根域或项目上具有角色分配,他们是否应该能够查看部署中的所有实例(例如,根域下的整个项目树)?这在某种程度上也是全局的,因为用户将查看整个部署中的所有实例?在理解了这一点之后,很明显全局指的是树的根,而我们真正需要的是指系统操作。
使用系统一词有助于明确哪些资源和 API 是特定于部署或整个系统的功能。例如,服务和端点是系统正常运行所必需的实体。它们显然不属于单个项目或域。nova 中的 hypervisor 管理也是一个系统级别资源,没有意义将其与单个项目关联。由于多租户,多个项目可以在单个 hypervisor 上托管实例。
提议的变更¶
列出用户的系统角色分配¶
请求: GET /v3/system/users/{user_id}/roles/
参数
user_id - 用户 ID。
响应
200 - 确定
404 - 如果用户不存在,则未找到
401 - 如果用户未被允许执行该操作
响应体
{
"links": {
"self": "http://example.com/identity/v3/system/users/cf8e3ee7115b4a88897673ee61dd2919/roles",
"previous": null,
"next": null
},
"roles": [
{
"id": "46b213b41e7344cc8078ac5e7d161f17",
"links": {
"self": "http://example.com/identity/v3/roles/46b213b41e7344cc8078ac5e7d161f17"
},
"name": "admin"
}
]
}
将系统角色分配给用户¶
请求: PUT /v3/system/users/{user_id}/roles/{role_id}
参数
user_id - 用户 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或用户不存在,则未找到
401 - 如果用户未被允许执行该操作
检查用户是否具有系统角色分配¶
请求: HEAD /v3/system/users/{user_id}/roles/{role_id}
请求: GET /v3/system/users/{user_id}/roles/{role_id}
参数
user_id - 用户 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或用户不存在,则未找到
401 - 如果用户未被允许执行该操作
从用户处取消分配系统角色¶
请求: DELETE /v3/system/users/{user_id}/roles/{role_id}
参数
user_id - 用户 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或用户不存在,则未找到
401 - 如果用户未被允许执行该操作
列出组的系统角色分配¶
请求: GET /v3/system/groups/{group_id}/roles/
参数
group_id - 组 ID。
响应
200 - 确定
404 - 如果组不存在,则未找到
401 - 如果用户未被允许执行该操作
响应体
{
"links": {
"self": "http://example.com/identity/v3/system/groups/282051ffddcf4206a954ad838c86d39f/roles",
"previous": null,
"next": null
},
"roles": [
{
"id": "46b213b41e7344cc8078ac5e7d161f17",
"links": {
"self": "http://example.com/identity/v3/roles/46b213b41e7344cc8078ac5e7d161f17"
},
"name": "admin"
}
]
}
将系统角色分配给组¶
请求: PUT /v3/system/groups/{group_id}/roles/{role_id}
参数
group_id - 组 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或组不存在,则未找到
401 - 如果用户未被允许执行该操作
检查组是否具有系统角色分配¶
请求: HEAD /v3/system/groups/{group_id}/roles/{role_id}
请求: GET /v3/system/groups/{group_id}/roles/{role_id}
参数
group_id - 组 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或组不存在,则未找到
401 - 如果用户未被允许执行该操作
从组处取消分配系统角色¶
请求: DELETE /v3/system/groups/{group_id}/roles/{role_id}
参数
group_id - 组 ID。
role_id - 角色 ID。
响应
204 - 无内容
404 - 如果角色或组不存在,则未找到
401 - 如果用户未被允许执行该操作
列出角色分配¶
现有的列出角色分配的 API 必须增强为返回系统角色分配,以及它今天返回的项目和域角色分配信息。
请求: GET /v3/role_assignments
参数
将添加一个过滤器,称为 scope.system,以按系统特定角色分配过滤角色分配。它将是一个布尔值。
响应
200 - 确定
401 - 如果用户未被允许执行该操作
响应体
{
"role_assignments": [
{
"role": {
"id": "d6c89e9121304b6f87de57b0500b0526"
},
"user": {
"id": "3f0c5f11e792494ab5de347696fa1421"
},
"scope": {
"domain": {
"id": "6bfbd79b010e4405b92731479cbbe8e7"
}
},
"links": {
"assignment": "http://example.com/identity/v3/domains/6bfbd79b010e4405b92731479cbbe8e7/users/3f0c5f11e792494ab5de347696fa1421/roles/d6c89e9121304b6f87de57b0500b0526"
}
},
{
"role": {
"id": "2fb8d689a8744a42af926ea4f8f929c7"
},
"group": {
"id": "a806d9029db7403e9869632aee082e5c"
},
"scope": {
"project": {
"id": "2fae742cb86543af825471ea6b63ccea"
}
},
"links": {
"assignment": "http://example.com/identity/v3/projects/2fae742cb86543af825471ea6b63ccea/groups/a806d9029db7403e9869632aee082e5c/roles/2fb8d689a8744a42af926ea4f8f929c7"
}
},
{
"group": {
"id": "1d8d919f37d94f308d007e72737cf10a"
},
"links": {
"assignment": "http://example.com/identity/v3/system/groups/1d8d919f37d94f308d007e72737cf10a/roles/b29d6fff51c43478b00bb16bfb771fc"
},
"role": {
"id": "ab29d6fff51c43478b00bb16bfb771fc"
},
"scope": {
"system": true
}
}
],
"links": {
"self": "http://example.com/identity/v3/role_assignments",
"previous": null,
"next": null
}
}
验证系统范围令牌¶
以下是系统范围令牌的示例请求
{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"id": "8bbca32b850a4c22b64a1b7bc2c6bd13",
"password": "my-password"
}
}
},
"scope": {
"system": {
"all": true
}
}
}
}
一个示例响应是
{
"token": {
"audit_ids": [
"doIh18J8RyW3jXF50FV26g"
],
"catalog": [
...
],
"expires_at": "2017-05-15T21:58:29.000000Z",
"issued_at": "2017-05-15T20:58:29.000000Z",
"methods": [
"password"
],
"system": {
"all": true
},
"roles": [
{
"id": "c2145c84a802413fbac71479250c9378",
"name": "observer"
},
{
"id": "fc2ec22e227941f8afd94a1587ac57d3",
"name": "admin"
}
],
"user": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "8bbca32b850a4c22b64a1b7bc2c6bd13",
"name": "bob",
"password_expires_at": null
}
}
}
系统范围可以被现有的策略消耗
"system_admin": "role:admin and system:True"
"system_reader": "role:reader and system:True"
"admin_required": "rule:system_admin"
系统令牌响应的属性也可以被 oslo.context 消耗,并通过 context.scope = ‘system’ 或其他方法暴露给服务进行范围检查。将此信息传递给消耗服务的流程将包含对 oslo.context 库的后续工作,以确保它正确处理系统范围的令牌。此规范的主要目的是允许在系统级别对角色进行范围划分,并将该能力暴露给最终用户。可以并行进行工作以在策略文件或共享库中消耗此信息。
系统角色、隐含角色和继承角色¶
Keystone 支持其他类型的角色行为。管理员可以有一个角色隐含另一个角色,或者角色可以根据项目的层次结构继承。例如,如果角色 Alpha 隐含角色 Beta,那么具有角色 Alpha 的用户将自动在目标上获得角色 Beta,因为它被隐含。另一个例子是,如果允许角色分配通过项目树继承。例如,如果 project C 是 project D 的父项目,并且用户在 project C 上具有角色 Echo,那么用户也通过角色继承在 project D 上具有角色 Echo。这些概念分别被称为隐含角色和继承角色。
引入系统范围机制的一部分是了解它如何应用于这些概念。可以将这两个概念应用于系统角色。分配给用户在系统上的角色应该能够隐含其他角色。有人讨论过将来将系统构建成层次结构。例如,如果系统实际上是区域的树。这将引入另一个允许用户在整个系统的子集上具有角色分配的范围级别。这似乎是一个强大的想法,但它需要更多的思考和讨论。目前,系统将是一个单一的实体,但构建为以后可以重构为层次结构。
总而言之,系统角色的初始实现应支持隐含角色分配。它应该足够灵活,以便在系统实体最终演变成区域或服务的树时支持继承角色。
备选方案¶
这种方法的替代方案是利用 admin_project 以实现全局范围。 admin_project 是一个特殊的项目,如果将角色分配给该项目,则允许提升权限。让我们考虑以下示例。假设有一个 observer 角色,允许用户在特定范围内执行只读操作。如果 Bob 在项目 foo 上具有 observer 角色,他应该能够查看该项目中的内容。如果 Alice 在 admin_project 上具有 observer 角色,她应该能够查看部署中的所有内容,例如服务和端点。
在这个模型中,系统范围由一个特定的项目及其角色分配决定。部署中需要任何类型的系统角色(即,管理员、观察者、支持等)的所有用户都需要在 admin_project 上具有角色分配。
优势
重用现有的项目范围机制/令牌
利用令牌的 is_admin_project 属性
大部分工作已经完成
不需要更改范围的存储方式
缺点
自动化工具可能需要单独处理此项目(即,绕过策略提升的实现细节),以确保不会发生任何事情到 admin_project
操作员可能会发现为了获得提升的权限而需要在超级特殊项目上拥有角色,这似乎是一种反模式
所有需要某种类型的系统角色的用户都必须在 admin_project 上具有角色分配,这可能会导致 admin_project 上的大量角色分配
如果意外删除了 admin_project,则需要制定某种恢复计划
某些资源今天不能属于系统范围(例如,实例必须绑定到项目),这种方法不会阻止用户在 admin_project 中创建资源,这将等同于系统范围的实例
admin_project 如何符合项目层次结构?它应该保存在默认域下的自己的子树中,还是可以在其下方拥有子项目?
路线图¶
is_admin_project 实现今天存在于 OpenStack 中,通过 keystone API 传递,并存在于一些服务策略文件中。在未来,同时支持这两种方法是有意义的。在 Queens PTG 上准备的 路线图 表明了我们如何使用这两种方法改进管理员权限,但最终需要系统范围。
安全影响¶
这种范围划分将允许 OpenStack 服务将系统操作与项目或域范围的操作分开。结果将是 OpenStack 中改进的安全模型。请注意,系统范围的令牌仍然是 bearer 令牌,并允许持有者对部署系统执行操作。
通知影响¶
系统范围将受到与项目或域范围请求相同的通知约束。
其他最终用户影响¶
这在很大程度上取决于操作员如何在 OpenStack 中配置其策略。理想情况下,这将为操作员提供更多工具,以在其部署中提供更好的安全性。
性能影响¶
无。
其他部署者影响¶
部署程序现在将能够通过利用系统角色分配来控制系统操作。该功能将默认可用,但不会提供迁移现有策略解决方法,因为策略在部署中可能会有很大差异。
可以提供升级文档,以帮助操作员可视化该过程并将其应用于其特定的策略场景。
开发人员影响¶
这项工作很可能需要对 keystone 内部和外部的测试进行一些更改,以保证系统操作与项目操作的隔离。减轻这种情况将是实施的必需工作项。
实现¶
负责人¶
- 主要负责人
Lance Bragstad <lbragstad@gmail.com> lbragstad
- 其他贡献者
无
工作项¶
添加一个新的数据库表来支持系统分配
实施系统角色分配
实施将令牌范围限定为系统上下文
迁移 tempest 测试以利用系统角色
清楚地记录操作员可能的升级路径
在 oslo.policy 和 keystonemiddleware 中实施系统上下文
后续工作项目应完成,以确保系统角色分配在 OpenStack 中的策略中得到尊重
确保默认策略遵守系统范围
确保跨项目的范围检查强制执行系统范围
依赖项¶
无。
文档影响¶
我们需要提供一个更一致的身份验证文档,清楚地解释项目和系统级别的范围。描述从现有系统升级的可能路径的单独文档也将是必需的。
参考资料¶
无。