理解 Nova 策略

警告

自 Nova 22.0.0 (Victoria) 起,JSON 格式的策略文件已被弃用。请使用 YAML 格式的文件。使用 oslopolicy-convert-json-to-yaml 工具以向后兼容的方式将现有的 JSON 转换为 YAML 格式的策略文件。

Nova 支持一个丰富的策略系统,在其生命周期内得到了显著发展。最初,它采用大型的、大部分手动编写的 policy.yaml 文件形式,但从 Newton (14.0.0) 版本开始,策略默认值已在代码库中定义,因此 policy.yaml 文件仅用于覆盖这些默认值。

在 Ussuri (21.0.0) 版本中,进一步的工作旨在解决一些已识别的问题

  1. 没有全局与项目管理员的区别。 admin_only 角色用于能够对 Nova 进行几乎任何更改并查看 Nova 系统所有细节的全局管理员。规则适用于具有管理员角色的任何用户,无论使用哪个项目。

  2. 没有只读角色。由于几个 API 倾向于为读写操作共享单个策略规则,因此它们没有提供必要的只读访问角色粒度。

  3. admin_or_owner 角色没有按预期工作。对于大多数使用 admin_or_owner 的 API,项目身份验证发生在 Nova 中 API 之外的单独组件中,该组件不遵守策略更改。因此,策略无法覆盖硬编码的入站检查。

Keystone 默认提供 adminmanagermemberreader 角色。请参阅 此文档 以获取有关这些新默认值的更多信息。此外,keystone 支持新的“系统范围”概念,这使得更容易保护部署级别资源免受项目或系统级别资源的侵害。请参阅 此文档系统范围规范 以了解范围概念。

在 Nova 25.0.0 (Yoga) 版本中,Nova 策略实现了范围概念以及 keystone 提供的默认角色(admin、member 和 reader)。使用来自 keystone 的通用角色可以减少跨项目或部署实现类似但不同的角色的可能性(例如,名为 observerreaderauditor 的角色)。借助新的默认值,更容易理解跨项目谁可以做什么,减少差异,并提高互操作性。

以下部分解释了 Nova 中的这些新默认值如何解决上述前两个问题,并以安全可靠的方式为最终用户扩展更多功能。

更多信息请参见 nova 规范

范围

OpenStack Keystone 支持令牌中的不同范围。这些范围在此处描述:此处。令牌范围代表授权层。策略 scope_types 代表访问 API 所需的授权层。

注意

每个策略的 scope_type 均硬编码为 project 范围,并且无法通过策略文件覆盖。

Nova 策略通过将所有策略的 scope_type 定义为 project 范围来实现范围概念。这意味着如果用户尝试使用 system 范围的令牌访问 nova API,他们将收到 403 权限被拒绝错误。

例如,考虑 POST /os-server-groups API。

# Create a new server group
# POST  /os-server-groups
# Intended scope(s): project
#"os_compute_api:os-server-groups:create": "rule:project_member_api"

默认情况下禁用策略范围,以允许操作员以优雅的方式从旧策略执行系统迁移。可以通过配置 oslo_policy.enforce_scope 选项为 True 来启用它。

注意

[oslo_policy] enforce_scope=True

角色

您可以参考 文档以了解 Keystone 提供的所有可用默认值。

除了 scope_type 功能外,Nova 策略还为每个策略定义了新的默认值。

reader

这提供对资源的只读访问权限。Nova 策略默认设置为以下规则

policy.RuleDefault(
    name="project_reader",
    check_str="role:reader and project_id:%(project_id)s",
    description="Default rule for Project level read only APIs."
)

在策略规则中使用(具有 admin + reader 访问权限):(因为我们希望保持遗留 admin 行为不变,我们需要为 reader API 提供 admin 角色的访问权限。)

policy.DocumentedRuleDefault(
    name='os_compute_api:servers:show',
    check_str='role:admin or (' + 'role:reader and project_id:%(project_id)s)',
    description="Show a server",
    operations=[
        {
            'method': 'GET',
            'path': '/servers/{server_id}'
        }
    ],
    scope_types=['project'],
)

OR

policy.RuleDefault(
    name="admin_api",
    check_str="role:admin",
    description="Default rule for administrative APIs."
)

policy.DocumentedRuleDefault(
    name='os_compute_api:servers:show',
    check_str='rule: admin or rule:project_reader',
    description='Show a server',
    operations=[
        {
            'method': 'GET',
            'path': '/servers/{server_id}'
        }
    ],
    scope_types=['project'],
)

member(成员)

project-member 表示在项目上具有 member 角色的某人。它旨在由在项目内消耗资源并需要高于 reader 角色但低于 admin 角色的权限的最终用户使用。它继承了 project-reader 的所有权限。

project-member persona 在策略检查字符串中

policy.RuleDefault(
    name="project_member",
    check_str="role:member and project_id:%(project_id)s",
    description="Default rule for Project level non admin APIs."
)

在策略规则中使用(具有 admin + member 访问权限):(因为我们希望保持遗留 admin 行为,admin 角色可以访问项目级别的 member API。)

policy.DocumentedRuleDefault(
    name='os_compute_api:servers:create',
    check_str='role:admin or (' + 'role:member and project_id:%(project_id)s)',
    description='Create a server',
    operations=[
        {
            'method': 'POST',
            'path': '/servers'
        }
    ],
    scope_types=['project'],
)

OR

policy.RuleDefault(
    name="admin_api",
    check_str="role:admin",
    description="Default rule for administrative APIs."
)

policy.DocumentedRuleDefault(
    name='os_compute_api:servers:create',
    check_str='rule_admin or rule:project_member',
    description='Create a server',
    operations=[
        {
            'method': 'POST',
            'path': '/servers'
        }
    ],
    scope_types=['project'],
)

check_str 中的 ‘project_id:%(project_id)s’ 对于限制请求项目的访问权限非常重要。

manager

project_manager 表示在项目上具有 manager 角色的某人。它旨在用于项目级别管理 API 并对其项目资源执行比 project_member 更多的特权操作。它继承了 project_memberproject_reader 的所有权限。例如,project_manager 可以在不指定主机的情况下迁移(冷迁移或实时迁移)其服务器。此外,project_manager 将能够列出与其项目相关的迁移。

project_manager persona 在 Nova 策略规则中(它在 policy yaml 中定义为 project_manager_api)如下所示

check_str 中的 ‘project_id:%(project_id)s’ 对于限制请求项目的访问权限非常重要。

# Default rule for Project level management APIs.
"project_manager_api": "role:manager and project_id:%(project_id)s"

为了保持遗留 admin 行为不变,Nova 允许 admin 也可以访问项目级别的管理 API

# Default rule for Project level management APIs.
"project_manager_or_admin": "rule:project_manager_api or rule:context_is_admin"

上述基本规则用于特定的 API 访问

# Cold migrate a server without specifying a host
# POST  /servers/{server_id}/action (migrate)
# Intended scope(s): project
"os_compute_api:os-migrate-server:migrate": "rule:project_manager_or_admin"

admin(管理员)

此角色用于执行 admin 级别的写入操作。Nova 策略默认设置为以下规则

policy.DocumentedRuleDefault(
    name='os_compute_api:os-hypervisors:list',
    check_str='role:admin',
    scope_types=['project']
)

使用这些新的默认值,您可以解决以下问题:

  1. 为用户提供只读访问权限。策略更加精细,默认设置为 reader 规则。例如:如果您需要让某人出于安全目的审核您的部署。

  2. 更好地自定义策略。例如,您将能够提供对项目级别用户的访问权限,以仅在其项目内执行操作。

服务

service 角色是 Keystone 中的一个特殊角色,用于内部服务到服务的通信。它分配给模拟 OpenStack 服务的服务用户,即 nova 或 neutron。Nova 将其服务到服务 API 默认设置为需要 service 角色,以便任何非服务用户都无法使用它们。允许非服务用户访问服务到服务 API 会破坏资源并使部署处于无效状态。建议审核 policy.yaml 文件和 keystone 用户,以确保这些 API 不允许任何非服务用户使用,并且服务角色不授予人类管理员帐户。

注意

确保其他服务中配置的 nova 服务用户具有 service 角色,否则从其他服务到 Nova 的通信将失败。例如,配置为 username 选项在 neutron.conf 文件下的 [nova] 部分中的用户具有 service 角色。

Nova 支持的范围和角色

Nova 支持以下范围和角色的组合,这些角色可以在 policy.yaml 文件中覆盖,但范围不可覆盖。

  1. ADMIN:admin 角色在 project 范围内。这是一个管理员,用于执行 admin 级别的操作。例如:启用/禁用计算服务、实时迁移服务器等。

  2. PROJECT_MANAGER:manager 角色在 project 范围内。这用于在项目内执行项目管理操作。例如:迁移服务器。

  3. PROJECT_MEMBER:member 角色在 project 范围内。这用于在项目内执行资源所有者级别的操作。例如:暂停服务器。

  4. PROJECT_READER:reader 角色在 project 范围内。这用于在项目内执行只读操作。例如:获取服务器。

  5. PROJECT_MANAGER_OR_ADMIN:adminmanager 角色在 project 范围内。此类策略规则默认设置为项目管理级别的 API,并且除了 manager 角色外,遗留 admin 还可以继续访问这些 API。

  6. PROJECT_MEMBER_OR_ADMIN:adminmember 角色在 project 范围内。此类策略规则默认设置为大多数所有者级别的 API,并与 member 角色保持一致,遗留 admin 还可以继续访问这些 API。

  7. PROJECT_READER_OR_ADMIN:adminreader 角色在 project 范围内。此类策略规则默认设置为大多数只读 API,以便遗留 admin 还可以继续访问这些 API。

  8. SERVICE_ROLE(内部):service 角色在具有 project 范围的服务用户上。此类策略规则默认设置为服务到服务 API(仅供 OpenStack 服务调用的 API)。

向后兼容性

通过支持旧默认值并默认禁用 scope_type 功能,与 21.0.0 (Ussuri) 之前的版本的向后兼容性得以保持。这意味着旧默认值和使用它们的部署将继续正常工作。但是,我们鼓励每个部署切换到新的策略。新的默认值将在 OpenStack 2023.1 (Nova 27.0.0) 版本中默认启用,旧默认值将在 OpenStack 2023.2 (Nova 28.0.0) 版本中删除。

为了实现新的默认 reader 角色,一些策略需要变得更加精细。它们已被重命名,旧名称仍然受支持以保持向后兼容性。

迁移计划

为了实现平滑迁移,Nova 提供了两个标志来完全切换到新的策略。您无需覆盖策略文件即可采用新的策略默认值。

以下是迁移的分步指南

  1. 创建范围令牌

    您需要通过以下 CLI 创建了解范围的令牌

  2. 如果尚未完成,请在 keystone 中创建新的默认角色

    如果您在 Keystone 中没有新的默认设置,您可以创建并重新运行 Keystone Bootstrap。Keystone 在 14.0.0 (Rocky) 版本中添加了此支持。

  3. 启用 Scope 检查

    标志 oslo_policy.enforce_scope 用于启用 scope_type 功能。请求中使用的 token 的 scope 始终与 policy 的 scope_type 进行比较。如果 scope 不匹配,可能会发生以下两种情况之一。如果 oslo_policy.enforce_scope 为 True,则请求将被拒绝。如果 oslo_policy.enforce_scope 为 False,将记录警告,但请求将被接受(假设 policy 的其余部分通过)。此标志的默认值为 False。

  4. 启用新的默认设置

    标志 oslo_policy.enforce_new_defaults 将 policy 切换为仅使用新的默认设置。此标志控制在评估 policy 时是否使用旧的已弃用默认设置。如果为 True,则不会评估旧的已弃用默认设置。这意味着,如果任何现有 token 允许使用旧的默认设置,但新的默认设置不允许,则将被拒绝。此标志的默认值为 False。

    注意

    在您启用此标志之前,您需要告知用户他们需要使用的不同角色才能继续使用 Nova APIs。

  5. 检查已弃用的 policy

    为了实现 reader 角色,对一些 policy 进行了更细粒度的划分。可以使用新的 policy 名称。如果在 policy 文件中覆盖了已重命名的旧 policy 名称,将记录警告。请将这些 policy 迁移到新的 policy 名称。

注意

We recommend to enable the both scope as well new defaults together
otherwise you may experience some late failures with unclear error
messages. For example, if you enable new defaults and disable scope
check then it will allow system users to access the APIs but fail
later due to the project check which can be difficult to debug.

下表显示了旧规则如何映射到新规则

旧规则

新规则

操作

范围

RULE_ADMIN_API

ADMIN

全局资源写入 & 读取

project

RULE_ADMIN_API

PROJECT_MANAGER_OR_ADMIN

项目管理级别

project

RULE_ADMIN_OR_OWNER

PROJECT_MEMBER_OR_ADMIN

项目资源写入

project

RULE_ADMIN_OR_OWNER

PROJECT_READER_OR_ADMIN

项目资源读取

project

我们预计所有部署将在 OpenStack 2023.1 (Nova 27.0.0) 版本之前迁移到新的 policy (project_manager 角色从 Nova 32.0.0 开始可用),以便我们可以删除对旧 policy 的支持。