首页 > 解决方案 > 开放策略代理 - CI 管道中的显式逻辑与

问题描述

我正在尝试编写一个管理管理员用户名兼容性的策略,该策略由三个规则组成:字母数字值,不是不允许的名称(管理员、管理员等)的一部分,以及超过 5 个字符。

我发现当使用 OPA 作为 CI 管道(这是我的用例)的一部分时,最舒适的解决方案是创建一个包含策略结果的对象(字典),以便我可以直接查询它们。我在 CI 管道中的行将如下所示:

for file in rego_directory:
     opa eval -i file -d data.json "package_name.policy"

它不会打印我在 rego 文件中使用的所有变量和临时资源(这会节省大量日志和输出)。为了制作这个“策略”对象,我在我的 rego 文件中有以下模式:

policy[policy_name] = result {
    policy_name := 
    ...
    computations...
    ...
    result := <logical condition>
}

现在,我的问题如下:这对我来说似乎不是最佳实践。有没有另一种方法可以简单地从输出中省略变量?以前我使用过单独的值(即像这样:

default policy_1 = false
default policy_2 = false

policy_1 = {
    <logical condition>
}
policy_2 = {
    <logical condition>
}

第二个问题:如何创建一个可以满足多个条件的输出字典(毕竟字典的 JSON 输出是一种很好的格式)?回顾我的例子,我不能写这样的东西:

policy[policy_name] = result {
    policy_name := 
    ...
    computations...
    ...
    result := <logical condition>
    result := <logical condition 2>
}

由于这是双重分配,这是无效的。即使我使用=而不是:=,如果一个术语为真而另一个为假,它也会产生冲突,并且错误不是我要寻找的(我需要布尔答案)。我如何创建一个复杂的规则,我可以把它的输出放在这个字典中?

提前致谢。

标签: evallogical-operatorsopen-policy-agentrego

解决方案


TLDR;明确回答您的问题:

现在,我的问题如下:这对我来说似乎不是最佳实践。有没有另一种方法可以简单地从输出中省略变量?

让您的软件查询某些规则生成的值没有任何问题。事实上,规则是在策略中定义抽象的基本方式,这样您就可以将策略决策(即产生决策的逻辑)与策略执行(即基于策略决策所采取的逻辑/行动)分离。 )

唯一真正的选择是在一个或多个包中查询一组规则,就像你展示的那样。

第二个问题:如何创建一个可以满足多个条件的输出字典(毕竟字典的 JSON 输出是一种很好的格式)?回顾我的例子,我不能写这样的东西:

您在问如何表达逻辑 OR。在这种情况下,您将创建policy规则的多个定义(我们在某些地方称它们为“增量定义”):

policy[policy_name] = result {
    policy_name := 
    ...
    computations...
    ...
    result := <logical condition>
}

policy[policy_name2] = result2 {
    policy_name2 := 
    ...
    some other computations...
    ...
    result2 := <some other logical condition>
}

policy此代码段定义了一个映射policy_nameresultpolicy_name2的对象(名为) result2。我们称这种规则为Partial Object。您还可以定义部分集。当你定义一个 Partial Object 时,你需要确保每个键映射到最多一个值(否则你会得到一个运行时错误。)

构建策略的另一种方法是(基本上)使用部分集定义拒绝列表:

package usernames

deny["username must use alphanumeric characters"] {
  re_match("[a-zA-Z0-9]", input.username)
}

deny["username must be at least 5 characters long"] {
  count(input.username) < 5
}

deny["username is reserved"] {
  reserved_usernames[input.username]
}

reserved_usernames := {"admin", "root"}

然后您的 CI 管道可以简单地查询deny

opa eval -i input.json 'data.usernames.deny'

结果将包含不应允许该用户名的原因。


推荐阅读