开放策略代理-CI管道中的显式逻辑“与”

时间:2020-07-07 11:56:02

标签: eval logical-operators opa open-policy-agent rego

我正在尝试编写一项管理管理员用户名兼容性的策略,该策略包含三个规则:字母数字值,不属于禁止名称(管理员,管理员等)的一部分以及超过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>
}

因为这是双重分配,所以无效。即使我使用=而不是:=,如果一个术语为true,另一个术语为false,它也会产生冲突,并且错误不是我想要的(我需要布尔值答案)。如何创建一个复杂的规则,可以将其输出放入此词典中?

谢谢。

1 个答案:

答案 0 :(得分:1)

TLDR;明确回答您的问题:

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

让您的软件查询某些规则生成的值没有错。实际上,规则是在策略中定义抽象的基本方式,因此您可以将策略决策(即产生决策的逻辑)与策略执行(即基于策略决策采取的逻辑/动作)分离。 )

唯一真实的选择是在一个或多个如您所示的包中查询一组规则。

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

您在问如何表达Logical 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_name映射到result,并且将policy_name2映射到result2。我们称这种规则为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'

结果将包含为什么不允许使用用户名的原因。