Policy Default Refresh

https://blueprints.launchpad.net/nova/+spec/policy-defaults-refresh

理想情况下,大多数操作员应该能够无需修改策略即可运行,因此我们需要更丰富的默认值。

在修改策略时,策略中的默认值应该易于理解,并允许操作员轻松创建额外的自定义角色。

问题描述

默认策略不够好,而且难以理解。

大多数 API 默认使用以下两种策略规则之一

  • 仅管理员

  • 管理员或所有者

首先,“admin_only” 用于全局管理员,他们能够对 Nova 进行几乎任何更改,并查看 Nova 系统的所有详细信息。该规则实际上适用于具有管理员角色的任何用户,无论使用哪个项目,任何具有 admin 角色的用户都将获得此全局访问权限。

其次,“admin_or_owner” 听起来像是检查用户是否是项目的成员。但是,对于大多数 API,我们使用默认目标,这意味着该规则将适用于任何经过身份验证的用户。数据库层有一个检查项目 ID(使用 project_only kwargs)的检查,以确保只有项目中的用户才能访问该项目中的实例。例如,此数据库检查意味着不可能拥有一个自定义角色,允许用户对不同于其令牌的项目中的服务器执行实时迁移,而无需向用户授予全局管理员角色。此外,如果用户在项目中拥有任何角色,使用默认策略,该用户能够访问 Nova 并在该项目中启动实例(受该项目的任何配额限制)。

第三,如果您想要一个“reader”角色,几个 API 共享一个用于读写操作的策略规则,即我们没有为添加此类角色提供足够的粒度。

Keystone 默认提供 member、admin 和 reader 角色。我们应该使用这些默认角色:https://specs.openstack.org/openstack/keystone-specs/specs/keystone/rocky/define-default-roles.html

此外,我们可以使用新的“system scope”概念来定义哪些用户是全局管理员:https://specs.openstack.org/openstack/keystone-specs/specs/keystone/queens/system-scope.html

用例

默认配置应支持以下用户角色

  • 系统范围管理员(实时迁移、禁用服务等)

  • 项目范围成员(创建服务器、删除服务器)

  • 系统范围读取者(列出主机、列出所有服务器)

  • 项目范围读取者(列出服务器)

在引入上述新的默认权限时,我们必须确保

  • 使用默认策略的运维人员至少有一个周期来向用户添加额外的角色(可能通过隐式角色)

  • 具有覆盖策略的运维人员至少有一个周期来了解新的默认设置可能对他们有何帮助或没有帮助

提议的变更

我们将支持在用例部分中描述的四个新角色。

更改将分以下阶段进行

  1. 为每个 API 端点添加测试。在进行任何更改之前,对每个 API 的行为进行单元和功能测试。

  2. 确保所有 context.can 调用都指定一个目标,然后使目标成为必需参数并删除默认目标。例如 project_id。目前我们在许多地方使用 context.project_id,需要将其替换为实际的目标 project_id。例如,对于服务器操作,我们需要使用服务器的 project_id,而不是发出请求的上下文的 project_id。

  3. 如果 enforce_scope 为 True,则将 DB 检查从“role:admin”更改为“scope:system”。我们可以在 DB 检查的上下文中设置 system_scope。

  4. 从以下选项中刷新每个 API 端点:SYSTEM_ADMIN、SYSTEM_READER、PROJECT_MEMBER_OR_SYSTEM_ADMIN、PROJECT_READER_OR_SYSTEM_READER(以及其他一些用于 keypairs 的选项),如果需要,添加额外的粒度。保留旧的 check_str 以便为现有用户服务。

  5. 在未来的版本中,将强制 enforce_scope 为 True。旧的 admin_or_owner 风格的检查将被删除。届时,将给操作员足够的时间来确保他们的所有用户都使用新的策略默认值,并且我们将确信我们有足够的测试来避免策略中的回归。

范围

每个策略规则都将涵盖适当的 oslo.policy 的“scope_types”,在 nova 的情况下为“system”和“project”。

例如,GET /os-services 将被限定为“system”,以便只有具有系统范围令牌的用户才能授权访问此 API。

POST ‘/servers/{server_id}/action (lock)’ 将被限定为 [‘system’, ‘project’],这意味着系统范围令牌以及项目范围令牌都可以锁定服务器。

PoC:https://review.openstack.org/#/c/645452/

我们需要允许操作员以某种优雅的方式从旧的策略执行系统迁移。 enforce_scope 配置选项可以帮助我们实现这一点,它为操作员提供了一个切换,以便在准备就绪并审计了他们的用户和分配后强制执行范围检查。

enforce_scope 配置选项的默认值为 False,这意味着如果令牌范围不匹配,只会记录警告。可以通过配置选项 nova.conf [oslo_policy] enforce_scope=True 启用此功能

注意:Nova 对 user_id 和 project_id 的使用是正交的,在检查 user_id 时,我们没有项目概念,在检查 project_id 时,我们不太关心 user_id。

Keystone 已经支持隐式角色,这意味着分配一个角色意味着分配另一个角色。新的默认角色 readermember 也已添加到 bootstrap 中。如果重新运行 bootstrap 过程,并且已经存在 readermemberadmin 角色,则将创建一个角色推导链:admin 推导 member 推导 reader

这意味着如果我们创建类似 SYSTEM_READER_OR_PROJECT_READER 的内容,它意味着 PROJECT_MEMBER 和 SYSTEM_ADMIN 也会获得访问权限。

新角色和 check_str

SYSTEM_ADMIN = 'rule:admin_api and system_scope:all'
SYSTEM_READER = 'role:reader and system_scope:all'
PROJECT_MEMBER = 'role:member and project_id:%(project_id)s'
PROJECT_READER = 'role:reader and project_id:%(project_id)s'
PROJECT_MEMBER_OR_SYSTEM_ADMIN = PROJECT_MEMBER + 'or' + SYSTEM_ADMIN
PROJECT_READER_OR_SYSTEM_READER = PROJECT_READER + 'or' + SYSTEM_READER

以下是新角色和 scope_types 与旧角色的映射

Legacy Rule        |    New Rules                     | Operation |scope_type|
-------------------+----------------------------------+-----------+-----------
                   |-> SYSTEM_ADMIN                   | Global    | [system]
RULE_ADMIN_API     |                                    Write
                   |-> SYSTEM_READER                  | Global    | [system]
                   |                                  | Read      |

                   |-> PROJECT_MEMBER_OR_SYSTEM_ADMIN | Project   | [system,
RULE_ADMIN_OR_OWNER|                                  | Write     |  project]
                   |-> PROJECT_READER_OR_SYSTEM_READER| Project   | [system,
                                                      | Read      |  project]

PoC:https://review.opendev.org/#/c/645452

角色

一旦检查了范围,我们需要确保用户在其给定范围内的角色是什么,以及这是否符合操作员允许的内容。

我们应该迁移以下读取者、成员、管理员模式

读取者角色权限最低,通常只能执行非破坏性的 GET API 调用。

成员角色映射到当前默认的权限级别。

管理员角色映射到当前的管理员角色。请注意,这意味着实时迁移是项目范围和管理员的。但是,如果您指定主机,则需要系统范围才能使用该参数。

在定义适当的默认角色时,重要的是要考虑策略的 scope_type。

由于配置选项 [oslo_policy].enforce_scope 默认情况下为 False,这意味着 scope_type 默认情况下未启用,因此如果新的给定角色可以在其范围之外访问 API,则可能会出现安全漏洞。例如:GET /os-services 将被授予“reader”角色和 scope_type=[‘system’],因此 check_str 将保留为“role:reader and system_scope:all”,其中 system_scope:all 是一个特殊的检查,因此具有 reader 角色和项目范围的令牌无法访问此 API。一旦 nova 将 [oslo_policy].enforce_scope 默认为 True,就可以从 check_str 中删除 system_scope:all(这仅适用于包含 system 作为其中一个 scope_type 的 API)。

PoC:https://review.openstack.org/#/c/648480/

在删除之前,DB 级别的管理员角色检查也将放宽,并允许任何系统范围令牌访问。

注意:同时,我们将更新所有策略检查以指定正确目标的 project_id。如果没有相关的项目,我们根本不指定 project_id(即停止默认 target={context.project_id})

粒度

为了实现读取者角色,一些 API 的策略不够细粒度。我们将为这些 API 添加额外的策略检查

我们将弃用旧规则并添加新的细粒度规则。例如:os_compute_api:os-agents 将被弃用,并添加新的规则 os_compute_api:os-agents:deleteos_compute_api:os-agents:getos_compute_api:os-agents:createos_compute_api:os-agents:update

  • ‘os_compute_api:os-agents’

    • 文件:nova/policies/agents.py

    • API 操作它控制

      • POST /os-agents,

      • PUT /os-agents,

      • GET /os-agents,

      • DELETE /os-agents

  • ‘os_compute_api:os-attach-interfaces’

    • 文件:nova/policies/attach_interfaces.py

    • API 操作它控制

      • GET ‘/servers/{server_id}/os-interface’

      • GET ‘/servers/{server_id}/os-interface/{port_id}’

      • POST ‘/servers/{server_id}/os-interface’,

      • DELETE ‘/servers/{server_id}/os-interface/{port_id}’

  • ‘os_compute_api:os-deferred-delete’

    • 文件:nova/policies/deferred_delete.py

    • API 操作它控制

      • POST ‘/servers/{server_id}/action (restore),

      • POST ‘/servers/{server_id}/action (forceDelete)’

  • ‘os_compute_api:os-hypervisors’

    • 文件:nova/policies/hypervisors.py

    • API 操作它控制

      • GET ‘/os-hypervisors’,

      • GET ‘/os-hypervisors/details’,

      • GET ‘/os-hypervisors/statistics’,

      • GET ‘/os-hypervisors/{hypervisor_id}’,

      • GET ‘/os-hypervisors/{hypervisor_id}/uptime’,

      • GET ‘/os-hypervisors/{hypervisor_hostname_pattern}/search’,

      • GET ‘/os-hypervisors/{hypervisor_hostname_pattern}/servers’,

  • ‘os_compute_api:os-instance-actions’

    • 文件:nova/policies/instance_actions.py

    • API 操作它控制

      • GET ‘/servers/{server_id}/os-instance-actions’,

      • GET ‘/servers/{server_id}/os-instance-actions/{request_id}’

  • ‘os_compute_api:os-instance-usage-audit-log’

    • 文件:nova/policies/instance_usage_audit_log.py

    • API 操作它控制

      • GET ‘/os-instance_usage_audit_log’,

      • GET ‘/os-instance_usage_audit_log/{before_timestamp}’

  • ‘os_compute_api:os-remote-consoles’

    • 文件:nova/policies/remote_consoles.py

    • API 操作它控制

      • POST ‘/servers/{server_id}/action (os-getRDPConsole)’,

      • POST ‘/servers/{server_id}/action (os-getSerialConsole)’,

      • POST ‘/servers/{server_id}/action (os-getSPICEConsole)’,

      • POST ‘/servers/{server_id}/action (os-getVNCConsole)’,

      • POST ‘/servers/{server_id}/remote-consoles’,

  • ‘os_compute_api:os-rescue’

    • 文件:nova/policies/rescue.py

    • API 操作它控制

      • POST ‘/servers/{server_id}/action (rescue)’,

      • POST ‘/servers/{server_id}/action (rescue)’

  • ‘os_compute_api:os-security-groups’

    • 文件:nova/policies/security_groups.py

    • API 操作它控制

      • POST ‘/servers/{server_id}/action (addSecurityGroup)’,

      • POST ‘/servers/{server_id}/action (removeSecurityGroup)’

  • ‘os_compute_api:os-server-password’

    • 文件:nova/policies/server_password.py

    • API 操作它控制

      • GET ‘/servers/{server_id}/os-server-password’,

      • DELETE ‘/servers/{server_id}/os-server-password’

  • ‘os_compute_api:servers:show:host_status

    • 文件:nova/policies/servers.py

    • API 操作它控制

      • GET ‘/servers/{server_id}’,

      • GET ‘/servers/detail’

  • ‘network:attach_external_network’

    • 文件:nova/policies/ servers.py

    • API 操作它控制

      • POST ‘/servers’,

      • POST ‘/servers/{server_id}/os-interface’

  • ‘os_compute_api:os-services’

    • 文件:nova/policies/ services.py

    • API 操作它控制

      • PUT ‘/os-services/enable’,

      • PUT ‘/os-services/disable’,

      • GET ‘/os-services’,

      • PUT ‘/os-services/disable-log-reason’,

      • PUT ‘/os-services/force-down’,

      • PUT ‘/os-services/{service_id}’,

      • PUT ‘/os-services/{service_id}’

以下策略存在相同问题,但它们的 API 已被弃用,因此此提案不会对这些产生任何影响。

  • ‘os_compute_api:os-floating-ips-bulk’

  • ‘os_compute_api:os-fping’

  • ‘os_compute_api:os-hosts’

  • ‘os_compute_api:os-networks’

  • ‘os_compute_api:os-networks-associate’

  • ‘os_compute_api:os-security-group-default-rules’

  • ‘os_compute_api:os-baremetal-nodes’

  • ‘os_compute_api:os-fixed-ips’

  • ‘os_compute_api:os-floating-ip-dns’

  • ‘os_compute_api:os-floating-ips’

  • ‘os_compute_api:os-multinic’

  • ‘os_compute_api:os-tenant-networks’

  • ‘os_compute_api:os-volumes’

PoC:https://review.openstack.org/#/c/645427/

向后兼容性和迁移计划

旧规则作为已弃用的规则保留,默认值与今天相同,以便现有的部署可以继续正常工作。

在两个周期内(这是一个大更新,因此我认为我们应该给操作员两个周期的过渡期),我们需要使现有的用户权限与新角色一起工作,以便操作员可以将他们的用户迁移到新角色。

请注意,这意味着

  • 从策略文件中删除任何项目或用户检查,因为现在在代码中完成,而不会破坏基于用户 ID 的策略执行

  • 将来读取者不允许访问的内容,但当前具有角色的任何人都可以访问的内容,必须获得明确的非读取者角色检查

  • 系统范围检查失败仅记录警告,本周期

  • 等等…

这将通过使用 oslo.policy 的弃用方法来完成。这样,我们可以允许使用旧的 check_str 以及带有适当警告的新 check_str 进行访问。

  • 弃用计划:由于这些策略更新非常庞大,并且几乎影响了所有 nova 策略,我们正在定义一个使用两个周期的过渡计划,而策略和配置选项修改通常只需要一个周期。

  • 操作员可以通过以下警告来迁移旧策略到新策略

    /opt/stack/nova/.tox/py27/local/lib/python2.7/site-packages/oslo_policy/ policy.py:665: UserWarning: 策略 “os_compute_api:os-services”: “rule:admin_api” 在 19.0.0 版本中已被弃用,推荐使用 “compute:services: disable”:”rule:admin_api”。 原因:自 Stein 版本发布以来,nova API 策略更加精细,并引入了具有 scope_type 功能的新默认角色。这些新变化提高了安全性、可管理性。新的策略在系统和项目级别处理访问权限方面更加丰富,具有读写角色。Nova APIs 正在利用这些新的策略改进,并自动迁移旧的覆盖策略。旧策略将在 nova 21.0.0 (OpenStack U) 版本中被静默忽略。请确保您的部署已准备好使用新的默认设置,或将弃用的策略复制/粘贴到您的策略文件中并手动维护。

示例: https://review.opendev.org/#/c/662971/

备选方案

我们可以只执行上述步骤中的一两个,但一次性修复这些问题似乎更有效。

我们可以根据 CONF.oslo_policy.enforce_scope,在基础层注册新的或旧的策略默认值,作为一种回退机制。

数据模型影响

REST API 影响

在弃用策略被移除或启用 enforce_scope 之前,现有用户不应受到这些更改的影响。

一旦强制执行 scope,系统 scope 用户需要学习如何请求系统 scope 的 token。但对于大多数用户,常规项目 scope 的 token 保持不变。

操作员未来可以创建具有更严格权限的新角色。

安全影响

易于理解的策略默认值将有助于保持系统的安全性。

一旦删除弃用的默认值,我们将能够拥有在项目中具有角色的用户,但无法访问 Nova(例如,仅 swift 用户)。

通知影响

其他最终用户影响

性能影响

其他部署者影响

开发人员影响

新的 API 必须添加遵循新模式的策略。

升级影响

API 策略名称和默认角色已被修改,如果部署使用 nova 中定义的默认策略,这可能会影响部署。如果部署覆盖这些策略,则需要开始考虑新的默认策略规则。

实现

负责人

主要负责人

gmann

其他贡献者

johnthetubaguy melwitt

工作项

  • 改进策略规则单元测试

  • 添加当前行为的策略功能测试

  • 添加对系统 scope admin 和项目 scope member 的支持

  • 取消对系统 scope 用户的 DB 检查,更新功能测试

  • 添加系统读取器和项目读取器,添加额外的策略规则,在需要更多粒度控制的地方。

依赖项

测试

当前的单元测试通常在测试策略方面表现很差,在进行上述任何更改之前,应该解决这个问题。

修改 Tempest 测试以适应 scope 和默认角色。

专注于功能测试,以覆盖 DB 检查并确保策略今天能够正确运行,这样我们就可以知道,随着代码的演进,我们不会破坏现有用户。

Patrole 可以在以后考虑,因为它对于操作员验证其云的策略是否按预期工作很有用。

文档影响

API 参考应与任何策略更改保持一致,特别是关于默认读者角色。

参考资料

历史

修订版

发布名称

描述

Train

引入