policy.yaml 文件

每个 OpenStack 服务,包括身份认证、计算、网络等,都有其自身的基于角色的访问策略。它们决定了哪个用户可以以哪种方式访问哪些对象,并在服务的 policy.yaml 文件中定义。

每当对 OpenStack 服务进行 API 调用时,服务的策略引擎都会使用适当的策略定义来确定是否可以接受该调用。对 policy.yaml 的任何更改都会立即生效,这使得在服务运行时可以实施新策略。

一个 policy.yaml 文件是一个 YAML(YAML Ain’t Markup Language)格式的文本文件。每个策略由以下形式的一行语句定义:"<target>" : "<rule>"

策略目标,也称为“action”,代表一个 API 调用,例如“启动实例”或“附加卷”。

Action 名称通常是限定的。例如,计算服务具有用于列出实例、卷和网络的 API 调用。在 /etc/nova/policy.yaml 中,这些 API 分别由 compute:get_allvolume:get_allnetwork:get_all 表示。

API 调用与 action 之间的映射通常没有文档记录。

策略规则确定在什么情况下允许 API 调用。通常,这涉及发出调用的用户(以下称为“API 用户”)以及 API 调用所操作的对象。典型的规则检查 API 用户是否是对象的拥有者。

警告

修改策略

虽然在博客上可以找到编辑 policy.yaml 文件的配方,但修改策略可能会产生意想不到的副作用,因此不建议这样做。

示例

一个简单的规则可能如下所示

"compute:get_all" : ""

目标是 "compute:get_all",即计算服务的“列出所有实例”API。规则是一个空字符串,表示“总是”。此策略允许任何人列出实例。

您也可以拒绝使用 API 的权限

"compute:shelve": "!"

感叹号表示“永不”或“没有人”,有效地禁用了计算 API“shelve an instance”。

可以使用字面值进行简单的比较

"copy_image": "'shared':%(visibility)s"

此检查将字面值 shared 与对象中键 visibility 的值进行比较。只有当 object['visibility'] == 'shared' 时,它才会通过。在编写规则时,有必要在字面值周围包含单引号,以便 oslo.policy 知道不要将其解释为 API 属性。

要确定传递给策略检查的对象中可用的字段,有必要为 oslo.policy 启用调试日志。可以通过为相关服务启用调试日志,并从 default_log_levels 选项中删除 oslo_policy 来完成此操作。

许多 API 只能由管理员调用。这可以通过规则 "role:admin" 来表达。以下策略确保只有管理员才能在身份认证数据库中创建新用户

"identity:create_user" : "role:admin"

注意

admin 是 Keystone 中的一个内置默认角色。有关更多详细信息和其他可用角色,请参阅 Keystone 文档关于默认角色

您可以将 API 限制为任何角色。例如,编排服务定义了一个名为 heat_stack_user 的角色。拥有此角色的任何人都不允许创建堆栈

"stacks:create": "not role:heat_stack_user"

此规则使用了布尔运算符 not。可以使用运算符 andor 和括号构建更复杂的规则。

您可以为规则定义别名

"deny_stack_user": "not role:heat_stack_user"

策略引擎理解 "deny_stack_user" 不是 API,因此将其解释为别名。上面的堆栈创建策略可以写成

"stacks:create": "rule:deny_stack_user"

这直接取自 /etc/heat/policy.yaml

规则可以将 API 属性与对象属性进行比较。例如

"os_compute_api:servers:start" : "project_id:%(project_id)s"

指出只有实例的拥有者才能启动它。冒号前的 project_id 字符串是 API 属性,即 API 用户的项目 ID。它与对象的项目 ID(在本例中,是一个实例)进行比较。更确切地说,它与数据库中该对象的 project_id 字段进行比较。如果两个值相等,则授予权限。

管理员始终有权调用 API。这就是 /etc/keystone/policy.yaml 明确制定此策略的方式

"admin_required": "role:admin or is_admin:1"
"owner" : "user_id:%(user_id)s"
"admin_or_owner": "rule:admin_required or rule:owner"
"identity:change_password": "rule:admin_or_owner"

第一行定义了“用户是管理员用户”的别名。只有在首次设置身份认证服务时,才会使用 is_admin 标志。它指示用户具有服务令牌授予的管理员权限(keystone 命令行客户端的 --os-token 参数)。

第二行通过比较 API 的用户 ID 与对象的用户 ID 创建了“用户拥有对象”的别名。

第 3 行使用布尔运算符 or 定义了第三个别名 admin_or_owner,将前两个别名组合在一起。

第 4 行设置了策略,即密码只能由其所有者或管理员用户修改。

作为最后的示例,让我们检查一个更复杂的规则

"identity:ec2_delete_credential": "rule:admin_required or
             (rule:owner and user_id:%(target.credential.user_id)s)"

此规则确定谁可以使用身份认证 API“删除 EC2 凭证”。在这里,布尔运算符和括号组合了三个更简单的规则。admin_requiredowner 与前一个示例中的别名相同。user_id:%(target.credential.user_id)s 将 API 用户与与目标关联的凭证对象的用户 ID 进行比较。

语法

一个 policy.yaml 文件由以下形式的策略和别名组成:target:rulealias:definition

"alias 1" : "definition 1"
"alias 2" : "definition 2"
....
"target 1" : "rule 1"
"target 2" : "rule 2"
....

目标是 API,并写成 "service:API" 或简单地 "API"。例如,"compute:create""add_image"

规则确定是否允许 API 调用。

规则可以是

  • 始终为真。该操作始终被允许。这可以写成 ""(空字符串)、[]"@"

  • 始终为假。该操作从不被允许。写成 "!"

  • 一个特殊的检查

  • 两个值的比较

  • 基于更简单规则的布尔表达式

特殊检查是

  • role:<role name>,测试 API 凭证是否包含此角色。

  • rule:<rule name>,别名的定义。

  • http:<target URL>,将检查委托给远程服务器。当服务器返回 True 时,API 经过授权。

开发人员可以定义额外的特殊检查。

以以下方式比较两个值

"value1 : value2"

可能的值是

  • 常量:字符串、数字、truefalse

  • API 属性

  • 目标对象属性

  • 标志 is_admin

API 属性可以是 project_iduser_iddomain_id

目标对象属性是数据库中对象描述中的字段。例如,在 "compute:start" API 的情况下,对象是要启动的实例。启动实例的策略可以使用 %(project_id)s 属性,即 API 用户的项目 ID。尾随的 s 表示这是一个字符串。对于 API 属性,例如 %(user_id)s%(domain_id)s,情况也是如此。

在调试日志记录阶段,通常会在 API 调用中检索目标对象属性。将日志中的 API 调用与针对相应 API 强制执行的策略进行比较,您可以检查使用了哪个 API 属性作为目标对象。例如,在 Nova 项目的 policy.yaml 中,您可以找到 "compute:start" API,策略将显示为 "rule:admin_or_owner",这将指向 "admin_or_owner":  "is_admin:True or project_id:%(project_id)s",这样您就可以检查调试日志记录中的目标对象需要是一个 project_id 属性。

is_admin 表示通过 admin token 机制授予管理员权限(keystone 命令的 --os-token 选项)。admin token 允许在 admin 角色存在之前初始化身份认证数据库。

别名构造存在于便利性。别名是复杂或难以理解的规则的简短名称。它以与策略相同的方式定义

alias name : alias definition

定义别名后,使用 rule 关键字在策略规则中使用它。