代码中的策略

https://blueprints.launchpad.net/oslo?searchtext=policy-in-code

长期以来,一直希望将合理的策略默认值嵌入到代码中,并允许策略文件覆盖它们。这将允许部署者仅配置他们想要覆盖的策略,从而减少这些文件的数量和复杂性。它还将允许生成一个示例策略文件,其中包含所有策略的详尽列表。

问题描述

这里涉及两个问题

给定一个部署的策略文件,确定它与项目期望的默认值之间的差异并不容易。这是因为没有一个权威的地方可以找到所有策略及其默认值。一些项目提供示例文件,但它们并不总是详尽的。而且,在进行大量修改后,很难将生产策略文件与示例文件进行比较。

给定一个经过身份验证的请求上下文,无法确定哪些策略将通过。这是因为策略检查在代码中是临时的,没有一个中心化的注册表来记录所有可能的检查。而且,策略文件可能没有列出所有策略,因为有些策略可能依赖于默认规则的回退。

提议的变更

提议是,代码中应检查的任何策略都可以使用 Enforcer 类进行注册,类似于配置注册的方式。将添加一种新的策略执行方法,如果被检查的策略先前未注册,则会报错。从文件加载策略和策略检查的当前方法不受影响。

注册需要两部分数据

  1. 规则名称,例如“compute:get”或“os_compute_api:servers:index”

  2. 规则,例如“rule:admin_or_owner”或“role:admin”

注册可以选择性地接受第三部分数据

  1. 描述字符串。这可以帮助管理员了解每个策略的信息。

需要规则名称以便后续查找。规则对于设置默认值和生成示例文件是必要的。描述可以作为注释添加到策略示例文件中。

通过将 PolicyOpt 类传递给 Enforcer.register_rule 或 PolicyOpt 列表传递给 Enforcer.register_rules 来完成注册。

例如,基于 Nova 可能会如何使用它

-- nova/policy/create.py

from oslo_policy import policy
from nova import policy as nova_policy

server_policies = [
    policy.PolicyOpt(rulename='os_compute_api:servers:create',
                     rule='rule:admin_or_owner',
                     description='Checked on POST /servers'),
    policy.PolicyOpt(rulename='os_compute_api:servers:create:forced_host',
                     rule='rule:admin_or_owner',
                     description='Controls whether the forced_host '
                     'scheduler hint is allowed.'),
    policy.PolicyOpt(rulename='os_compute_api:servers:create:attach_volume',
                     rule='rule:admin_or_owner',
                     description='Checks if a volume can be attached '
                     'during instance create.'),
    policy.PolicyOpt(rulename='os_compute_api:servers:create:attach_network',
                     rule='rule:admin_or_owner',
                     description='Checks if a network can be attached '
                     'during instance create.'),
]

policy_engine = nova_policy.get_policy()
# registration will error if a duplicate policy is defined
policy_engine.register_rules(server_policies)


-- nova/api/openstack/compute/servers.py

from nova import policy

policy_engine = policy.get_policy()

def create(self, context):
    ...
    policy_engine.authorize('os_compute_api:servers:create', target, creds)
    try:
        # This would error because the policy is not registered
        policy_engine.authorize(
            'os_compute_api:servers:create_not_registered', target, creds)
    except:
        pass
    if volume_to_attach:
        policy_engine.authorize(
            'os_compute_api:servers:create:attach_volume', target, creds)

对 oslo.policy 的提议更改是,Enforcer 类将获得两种新方法:“register_rule”和“register_rules”。这些方法将处理和存储注册的策略。将修改“load_rules”方法,以将从策略文件中加载的规则与注册的默认值合并。从文件中加载的规则将覆盖注册的默认值。

将更新“authorize”方法,以便尝试检查不存在的规则将导致错误。换句话说,默认规则失去了其特殊状态,并且不是未定义规则的回退。它仍然会作为其他规则使用的参考。

将添加一个 PolicyOpt 类,该类定义要注册的策略。它最初将包含 rulenames、rules 和 descriptions。

要更改的文件

  • oslo_policy/policy.py

备选方案

与其修改 oslo_policy/policy.py 中的 Enforcer 类,不如可以添加一个新的 Policy 类,该类处理注册并包含一个新的“authorize”方法。Policy 类将主要处理策略的注册和存储,并将代理给 Enforcer 以从文件中加载策略并处理实际的执行。随着时间的推移,将从文件中加载策略移出 Enforcer 类并放入 Policy 类可能是有意义的。

Impact on Existing APIs

将向 Enforcer 类添加一个新的“register”方法。

安全影响

此更改不会产生安全影响。策略的执行方式没有改变,只是策略的加载位置发生了改变。

性能影响

从代码注册策略将在注册时产生轻微的性能影响,但这与注册配置选项应该没有区别

Configuration Impact

此更改不会直接影响配置。此更改将允许注册了策略的项目无需策略文件即可使用这些默认值。这将允许部署者减少或删除他们的策略文件,如果他们正在运行接近默认值。

开发人员影响

在注册策略规则之前使用它们不是必需的,但会受到鼓励。因此,开发人员需要养成在注册后使用该注册的习惯,类似于添加新的配置选项。

Testing Impact

单元测试应该足够了。这增加了一种可以被其他项目使用的功能,但它不直接依赖于任何东西。

实现

负责人

主要负责人

alaski

其他贡献者

里程碑

完成目标里程碑

newton-1

工作项

  • 将 PolicyOpt 类添加到 oslo_policy/policy.py

  • 向 Enforcer 添加“register_rule”方法以进行规则注册

  • 向 Enforcer 添加“register_rules”方法以进行规则注册

  • 更新 Enforcer.load_rules() 以将注册的规则与从文件中加载的规则合并

  • 向 Enforcer 添加“authorize”方法,该方法类似于“enforce”,但如果被检查的策略未注册,则会报错。

孵化

N/A

采用

Nova 想要使用此功能。

N/A

预计 API 稳定

N/A

文档影响

注册策略规则的能力将在面向开发者的文档中记录。任何面向部署者的更改将由使用项目负责记录,因为他们切换到使用策略注册。

依赖项

参考资料

Nova 的此功能规范:https://review.openstack.org/#/c/290155/

注意

本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode