将细粒度限制添加到应用程序凭据

bp

目前 Keystone 应用程序凭据几乎没有限制。 只能对后续应用程序凭据的创建和信任施加限制。 除此之外,它们允许无限制地使用在应用程序凭据创建的项目中委派的角色。 这使得应用程序凭据在需要最小权限委派的任何地方都存在问题。 从技术上讲,可以存储白名单风格的访问规则列表,供应用程序凭据使用,其他 OpenStack 服务将强制执行这些规则。 本规范概述了一种存储和处理此类限制的方法。

问题描述

本节使用应用程序凭据的前身 Keystone 信任,来概述一些不受限制的角色委派存在问题的示例。 由于两者都委派用户角色的一个子集,因此同样的问题也适用于应用程序凭据。 唯一的区别是身份验证方法(应用程序凭据使用密钥,信任使用受托用户的用户名/密码)。

Keystone 信任已经存在相当一段时间了(它们是在 Grizzly 版本中引入的)。 目前,以下项目(可能不完整)正在使用信任:

  • Heat:在令牌可能已经过期时,代表用户进行操作。

  • Magnum:访问 Magnum 的证书签名 API 和集群实例内的其他 OpenStack API,容器编排引擎需要这些 API(例如,Glance 作为 docker-registry 的后端,或 cinder 作为 docker-volume 的后端)

其他项目(neutron-lbaas、Barbican)不愿使用信任和应用程序凭据,因为它们是一种全有或全无的方法:它们授予对其创建的项目中所有 OpenStack API 的完全访问权限。 为了提供最小权限访问,这些服务会实现自己的 ACL(Barbican、Swift),或依赖其他服务的 ACL 来授予对资源的有限访问(neutron-lbaas 使用 Barbican 的 ACL 来授予其服务用户访问包含 SSL 密钥的 secret 容器)。 Monasca 存在略有不同的问题:它使用 Keystone 来验证指标提交,这需要 Keystone 凭据或应用程序凭据。 这可能会被滥用,从 Monasca 代理运行的任何 VM 内部访问其他 OpenStack API。

总而言之,确实需要细粒度的访问委派。 目前 Keystone 应用程序凭据的实现无法满足此需求:应用程序凭据只能用于授予应用程序凭据的项目/角色范围内的完全访问权限,但不能用于授予仅限于特定资源访问权限,或仅允许创建特定新资源,但不修改/删除现有资源的访问权限。

在实施了细粒度限制后,可以使用应用程序凭据来安全地授予上述场景所需的最小权限。 这在使用某些服务当前使用的基于角色的访问控制解决方案时是不可能的,该解决方案只是明确地将特殊用途的角色(例如 Heat 的 heat_stack_user 角色)列入黑名单,以禁止除其预期用途之外的所有操作。 通常,这种黑名单仅扩展到拥有该角色的服务,并且将这些限制到位(其他服务通常不知道此角色应该对 _他们_ 的所有操作进行黑名单条目,因此允许无限制的访问)。

提议的变更

实施应用程序凭据的细粒度权限的方法是双管齐下的。 权限数据存储在 Keystone 中,并由 keystonemiddleware 强制执行,如下所示

  1. 在应用程序凭据旁边,可以存储一个包含零个或多个访问规则的列表。 此列表中的一个条目包括

    1. URL 路径(例如 /v2.1/servers/v2.1/servers/*/v2.1/servers/{server_id})。 此 URL 路径必须根据运算符配置的访问规则列表明确允许(请参阅 访问规则配置)。

    2. 请求方法(例如 GET

    3. 服务类型(理想情况下与 已发布的 Service Types Authority 匹配),来自 Keystone 服务目录。

    此列表是白名单,即任何未被访问规则明确允许的请求都将被拒绝。 Keystone 本身不会验证访问规则的内容,因为这需要对目录中的每个服务都有领域知识。

    访问规则存储在单独的数据库表中,并链接到应用程序凭据,以便可以使用新的应用程序凭据重用旧规则。

  2. keystonemiddleware 在服务侧接收令牌验证期间的访问规则列表。 然后它检查

    1. 服务类型(例如 compute

    2. URL 路径(例如 /v2.1/servers/*/v2.1/servers/{server_id}/v2.1/servers/b2088298-50e5-4c81-8a50-66bfd1d8943b

    3. 请求方法(例如 GET

    与从令牌中检索到的访问规则列表中的每个条目进行匹配。 如果访问规则与请求匹配,则检查停止并将请求交给 oslo.policy 进行常规的基于角色的检查。 如果没有访问规则匹配,则立即拒绝该请求。

    访问规则列表处理有三种特殊情况

    1. 如果未提供列表(即 access_rules 属性为 None),则不执行任何访问规则检查,并且请求立即传递给 oslo.policy

    2. 如果提供了空列表(即 []),则拒绝所有请求(即使请求否则会通过 (c) 中的测试)。

    3. 如果请求中存在有效的服务令牌,keystonemiddleware 立即将请求传递给 oslo.policy,尽管此功能的未来迭代将启用一个切换来控制此行为。

防止回归

如果 Keystone API 支持此功能遇到 keystonemiddleware 版本(或针对 Keystone 进行身份验证的第三方软件)早于此功能的实施日期,则存在回归的可能性:虽然 Keystone 会在令牌验证时提供访问规则列表,但另一方会简单地忽略它 - 授予请求由委派的角色授予的所有权限。 可以通过以下方式防止这种情况:将具有访问规则的应用程序凭据(即 access_rules 属性不是 None)视为如下:

  1. 在请求令牌验证时,keystonemiddleware(或任何支持访问规则强制执行的第三方应用程序)在其值中设置一个带有版本字符串的 Openstack-Identity-Access-Rules 标头。 具有访问规则列表的应用程序凭据的令牌验证仅在存在此标头时才会成功。 版本字符串将允许我们通过使仅支持此功能旧版本的 keystonemiddleware 无效来安全地扩展此功能。

  2. 如果令牌验证请求中没有 Openstack-Identity-Access-Rules 标头,则令牌验证失败。

这样,我们确保没有人错误地认为在过时的 keystonemiddleware(或其在第三方软件中的等效软件)无法强制执行它们的情况下,正在强制执行访问规则,因为它不知道它们。 对于没有访问规则的任何应用程序凭据,验证过程与在引入访问规则之前一样进行(无论是否存在 Openstack-Identity-Access-Rules)。

API 示例

创建应用程序凭据的示例请求如下

POST /v3/users/{user_id}/application_credentials
{
    "application_credential": {
        "name": "allow-metrics-logs",
        "description": "Allow submitting metrics and logs to Monasca",
        "access_rules": [
            {
                "path": "/v2.0/metrics",
                "method": "POST"
            },
            {
                "path": "/v3.0/logs",
                "method": "POST"
            }
        ]
    }
}

这样,将在用户 ID 下创建两个新的访问规则。 它们可以像这样查询:

请求

GET /v3/users/{user_id}/access_rules

响应

{
    "access_rules": [
        {
            "id": "180e86bc",
            "path": "/v2.0/metrics",
            "method": "POST"
        },
        {
            "id": "03e13d17",
            "path": "/v3.0/logs",
            "method": "POST"
        }
    ]
}

如果需要,可以通过提供 ID 来为另一个应用程序凭据重用它们

POST /v3/users/{user_id}/application_credentials
{
    "application_credential": {
        "name": "allow-just-metrics",
        "description": "Allow submitting only metrics to Monasca",
        "access_rules": [
            {
                "id": "180e86bc"
            }
        ]
    }
}

备选方案

  1. 另一种选择是各种 OpenStack 服务内部的 ACL 实现。 这种状况有几个原因:

    1. 可审计性:授权信息存储在多个

      位置,所有位置都需要检查才能确定谁有权执行什么操作。 从可审计性的角度来看,最好有一个中央事实来源。

    2. 维护:当存在多个独立实现时,会复制大量

      代码,并且错误可能会被复制,因为新项目会实现自己的 ACL 系统。

    3. 一致性:使用多个事实来源,单个服务

      的 ACL 可能会覆盖允许或拒绝操作的云范围策略。

  2. 391624 提出了一种在 keystonemiddleware 中进行类似的角色检查的方法。 但是,存在几个关键的区别:

    1. 应用程序凭据访问规则不需要管理员管理为每个 OpenStack 服务的每个 API 操作创建一个细粒度角色(类似于 寒武纪大爆发)。

    2. 应用程序凭据访问规则不需要更改现有的策略强制执行。 相反,它们添加了一个在策略强制执行甚至开始之前发生的额外检查,并尽早拒绝请求。 不与策略强制执行纠缠使我们能够从一个非常基本的实现开始,并在以后根据需要添加功能(而不是立即需要功能完整)。

    3. keystonemiddleware 中的角色检查针对希望为其用户创建角色配置的管理员,例如“授予此用户对任何服务资源的只读访问权限,但不允许他们创建新的资源”。 另一方面,应用程序凭据访问规则针对 OpenStack 服务和第三方应用程序,它们只需要访问一小部分操作,例如“将 SSL 证书提交到 Magnum API 进行签名”。

    4. 应用程序凭据访问规则不需要 Keystone 成为访问控制规则的守护者,因为令牌中包含验证访问所需的所有信息。

    5. 与基于策略的检查不同,基于访问规则的检查也适用于不使用 oslo.policy 的服务,例如 Swift。

  3. 前一节中的一个实施细节在 Rocky PTG 上进行了长时间讨论:可以选择匹配 oslo.policy 目标而不是访问规则中的 URL 路径,这在某些方面会更容易。 最终,我们选择 URL 路径的原因如下:

    1. 这是面向用户的,与 API 路径不同,策略目标不易被用户发现,因为没有关于它们的文档。 此外,策略目标不像 API 那样正式,并且可能会随着时间的推移而更改,从而破坏现有的访问规则。

    2. 可以在 keystonemiddleware 中拒绝 URL 路径,而无需涉及 oslo.policy,从而导致未经授权的请求更快失败。

未来考虑

链式 API 调用

此功能的未来迭代可能会创建一个切换来控制服务是否可以使用这些令牌代表用户进行后台请求,例如允许计算服务即使块存储 API 未在应用程序凭据访问规则中明确列入白名单,也可以向块存储服务发出请求。 对于目前而言,像这样的链式服务请求将利用服务令牌来确保代表用户发出的后续请求将正常完成,并将依赖于运算符配置的策略来防止滥用。

访问规则配置

此功能的未来迭代可能会启用一种方法,让运算符可以通过创建一个全局访问规则白名单来限制用户可以配置的允许访问规则,用户在创建应用程序凭据之前,会根据该白名单验证用户的访问规则。 其价值在于通过验证与已知工作规则来帮助用户创建有效的访问规则。 它还将为运算符提供对整体访问控制配置的更多控制。 但是,目前,此功能不可行,因为我们缺乏对 API 的可发现性,并且不可能为 OpenStack 内部和外部的所有服务的有效访问规则创建完整的列表。 由于提供完整的列表不可行,让运算符来管理自己的列表会导致运算符体验不佳,并且该列表容易出错,从而导致最终用户体验极差。

当此功能可行时,另一种可能性是允许运算符为每个访问规则配置一个角色 ID,以指示用户需要在应用程序凭据中提供该角色,才能继续调用。 这可以更好地协调策略规则和访问规则。

限制

本提案不会以任何方式限制请求的主体。

安全影响

此更改通过提供限制应用程序凭据授予的权限的手段来加强安全性。 也就是说,它的实施具有各种安全关键方面

  • 此变更在令牌验证时,向 keystone 中间件检索到的令牌数据中添加了额外信息。

  • 访问规则中的 URL 是用户提供的字符串。如果除了逐字符比较之外还进行任何操作,则必须小心防范格式字符串攻击。

  • 限制每个 API 凭据的访问规则的数量/长度可能是一个好主意,以防止对 Keystone 数据库(通过填充无效规则)或 Keystone API(通过大型验证负载)的拒绝服务攻击。引入此类限制的另一个原因是,通过创建具有大量不匹配访问规则的应用程序凭据来减慢服务速度的可能性,这可用于减慢特定服务的速度。

  • 此变更不太可能允许权限提升,因为它仅在令牌验证和策略执行中添加了额外的失败条件。但是,需要仔细测试这些失败条件是否存在误报。

通知影响

此 API 不会添加任何新的通知。

其他最终用户影响

由于此变更向应用程序凭据添加了额外信息,因此 python-keystoneclient 和 python-openstackclient 都需要扩展以处理该额外信息。

性能影响

应用程序凭据创建的性能影响可能可以忽略不计,因为发生的情况只是将少量数据与应用程序凭据一起存储。

然而,在令牌验证期间,这少量数据可能并不那么小,导致响应验证请求时发送多个/更多的数据包,从而导致拥塞和/或增加延迟。可以通过限制每个应用程序凭据允许的访问规则数量来缓解此问题。

开发人员影响

此变更为所有 OpenStack 服务的开发人员提供了一种创建具有细粒度权限的应用程序凭据的方式,从而允许他们根据最小权限原则委派对用户角色的访问权限。

就应用程序凭据 API 而言,它将完全向后兼容,因为在创建应用程序凭据时指定访问规则是可选的:如果未指定任何规则,则 access_rules 属性将为 None,从而不会执行任何访问规则检查。

实现

负责人

主要负责人

其他贡献者

工作项

  1. 扩展 Keystone 中的应用程序凭据 API 和数据库模式,以允许接收和存储访问规则列表。

  2. 在 python-keystoneclient 和 python-openstackclient 中实现对访问规则的处理。

  3. 扩展 Keystone 令牌验证 API,以便在令牌验证时访问访问规则列表。

  4. 在 keystonemiddleware 中实现端点列表检查。

依赖项

文档影响

  • 应用程序凭据相关的访问规则设置需要在发布说明和管理指南中进行记录。

  • 需要在 Keystone 用户文档的应用程序凭据部分添加有关访问规则的文档。

参考资料