RBAC 测试多个策略¶
bp rbac-testing-multiple-policies
问题描述¶
Patrole 当前通过检查策略操作是否允许来测试 API 端点,依据 oslo.policy,然后执行使用 CONF.rbac.rbac_test_role 下指定的角色进行策略执行的 API 端点。然而,这种方法没有考虑到直接(在 API 端点实现内部)或间接(在不同的辅助函数和 API 端点之间)强制执行多个策略操作的 API 端点。因此,Patrole 中当前的 RBAC 测试方法并不总是提供完整的策略覆盖。就像对 oslo.policy 进行多次调用是由各种端点执行的,Patrole 也应该这样做。
例如,考虑一个强制执行 2 个策略操作 A 和 B 的 API,其中 A 是 admin_api,B 是 admin_or_owner。使用 rbac_test_role 作为 admin 角色的调用必然会通过,因为 admin 角色具有执行策略操作 A 和 B 的权限,并且也能够执行 API 端点。但是,对于非 admin 角色,测试将失败,rbac_rule_validation 装饰器仅评估策略操作 B。这是因为非 admin 角色(例如 Member 角色)具有执行策略操作 B(即 admin_or_owner)的权限,但不具有执行 API 端点的权限,因为端点强制执行 admin_api 策略:这会导致引发 Forbidden 异常,并且测试失败。
提议的变更¶
建议的更改是修改 rbac_rule_validation 装饰器,使其能够接收策略操作列表,而不仅仅是一个策略操作。对于每个策略操作,将向 oslo.policy 进行调用,以确认测试角色是否允许执行该操作。从 oslo.policy 返回的每个结果都将进行逻辑与运算。例如,如果策略操作 A 评估为 True,而策略操作 B 评估为 False,则最终结果为 False:因此,用户不应能够成功执行 API 调用。因此,Patrole 可以推断角色是否允许调用强制执行多个策略的 API。
为了提供一个具体的例子,以下测试
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:os-lock-server:unlock:unlock_override")
def test_unlock_server_override(self):
server = self.create_test_server(wait_until='ACTIVE')
# In order to trigger the unlock:unlock_override policy instead
# of the unlock policy, the server must be locked by a different
# user than the one who is attempting to unlock it.
self.os_admin.servers_client.lock_server(server['id'])
self.addCleanup(self.servers_client.unlock_server, server['id'])
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.servers_client.unlock_server(server['id'])
可以更改为
@rbac_rule_validation.action(
service="nova",
rules=["os_compute_api:os-lock-server:unlock",
"os_compute_api:os-lock-server:unlock:unlock_override"])
def test_unlock_server_override(self):
server = self.create_test_server(wait_until='ACTIVE')
self.os_admin.servers_client.lock_server(server['id'])
self.addCleanup(self.servers_client.unlock_server, server['id'])
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.servers_client.unlock_server(server['id'])
根据 Nova 关于锁定服务器的文档,“unlock_override”策略“仅在检查 os_compute_api:os-lock-server:unlock 通过后执行”。通过此更改,Patrole 将基于测试角色是否能够执行传递给 rules 的所有策略来生成其“预期”结果;否则,如果测试角色无法执行至少一个策略,则预期结果将为 False。之后,将使用测试角色调用 API 操作,并将结果与预期结果进行比较。
如果预期结果和实际结果匹配,则测试将通过。否则,Patrole 可以生成详细的错误消息,说明传递给 rules 的哪些策略导致测试失败。例如,在上面的示例中,如果测试角色具有执行“os_compute_api:os-lock-server:unlock”的权限,但没有“os_compute_api:os-lock-server:unlock:unlock_override”的权限,那么 Patrole 将发出错误消息,说明“os_compute_api:os-lock-server:unlock:unlock_override”导致测试失败。这将帮助云部署者和开发人员确定测试失败的来源,并精确定位不一致的自定义策略配置。
替代方案¶
目前,没有其他可行的替代方案。由于各种显而易见的原因,反复调用每个 API 端点针对其强制执行的每个策略操作是不切实际的,也不可取的。
应尽量减少代码冗余,以使代码更易于阅读和维护。
这会在 Patrole 的网关中引入严重运行时问题。
安全影响¶
无。
通知影响¶
LOG 语句需要更新,以便在测试失败后向用户传达多个策略操作,尤其是在测试失败后。
如果 Patrole 测试测试多个策略,那么在测试失败后,对于用户来说,Patrole 记录哪些策略导致测试失败会很有用。可以通过迭代调用 oslo.policy 来针对传递给 rbac_rule_validation 装饰器的每个策略,并存储与角色不兼容的策略列表以及预期的测试结果来确定这一点。
其他最终用户影响¶
无。
性能影响¶
性能影响可以忽略不计。此更改只会导致测试运行时间略微变慢,因为将对 oslo.policy 进行多次调用,而不是每个 Patrole 测试仅调用一次。
其他部署者影响¶
无。
开发人员影响¶
建议的更改要求开发人员谨慎地选择包含在建议的 actions 参数中的策略操作。包含过多的策略操作不可维护,并且从开发角度来看很繁琐。例如,Cinder 强制执行 volume_extension:volume_host_attribute 和 volume_extension:volume_mig_status_attribute,以及许多不同的策略操作,适用于许多 API 端点。将这些策略操作重复用于每个 Cinder RBAC 测试将是冗余且设计不良的。(如果可以证明这些策略操作适用于每个 Cinder API 端点,那么 Patrole 框架可以自动注入这些策略操作,并将其与显式指定在 actions 中的策略操作进行逻辑与运算。但是,这种方法超出了本规范的范围)。
建议开发人员明智地使用此增强功能。只有强制执行多个相对唯一策略操作的端点才应包含在 actions 列表中。例如,可以从 Keystone 和 Nova 的自文档化代码策略定义中推断出唯一性。
实现¶
负责人¶
- 主要负责人
Felipe Monteiro <felipe.monteiro@att.com>
Samantha Blanco <samantha.blanco@att.com>
- 其他贡献者
Rick Bartra <rb560u@att.com>
工作项¶
使用
actions参数增强rbac_rule_validation装饰器,并弃用rule参数。在
rbac_rule_validation中编写一个辅助函数,以迭代调用rbac_policy_parser.RbacPolicyParser.allowed,针对在actions中指定的每个策略操作,进行逻辑与运算,并将结果返回到rbac_rule_validation装饰器。重构测试以使用
actions代替rule。编写新的单元测试来测试建议的增强功能。
选择性地将多个策略操作添加到一些测试中。
确认所有 API 测试都适用于建议的增强功能。
更新文档。
依赖项¶
无。
文档影响¶
应更新 Patrole 文档,以传达新的参数以及本规范中描述的预期用途。