Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Terraform 使用walk使用rego递归聚合地形状态下的资源_Terraform_Open Policy Agent_Rego - Fatal编程技术网

Terraform 使用walk使用rego递归聚合地形状态下的资源

Terraform 使用walk使用rego递归聚合地形状态下的资源,terraform,open-policy-agent,rego,Terraform,Open Policy Agent,Rego,我正在使用OpenPolicyAgent针对terraform状态的JSON输出编写策略 以下是状态文件的结构: { "format_version": "0.1", "terraform_version": "0.12.28", "values": { "root_module": { "resources": [],

我正在使用OpenPolicyAgent针对terraform状态的JSON输出编写策略

以下是状态文件的结构:

{
  "format_version": "0.1",
  "terraform_version": "0.12.28",
  "values": {
    "root_module": {
      "resources": [],
      "child_modules": [
        {
          "resources": [],
          "address": "",
          "child_modules": [
            {
              "resources": [],
              "address": "",
              "child_modules": [
                {}
              ]
            }
          ]
        }
      ]
    }
  }
}
我已经定义了这个讨厌的规则来实现我想要的,但这显然不是聚合这些资源的理想方式

resources[resource_type] = all {
    some resource_type
    resource_types[resource_type]
    rm := tfstate.values.root_module

    # I think the below can be simplified with the built in "walk" function TODO: do that.
    root_resources := [name |
        name := rm.resources[_]
        name.type == resource_type
    ]

    cmone_resources = [name |
        name := rm.child_modules[_].resources[_]
        name.type == resource_type
    ]

    cmtwo_resources = [name |
        name := rm.child_modules[_].child_modules[_].resources[_]
        name.type == resource_type
    ]

    cm := array.concat(cmone_resources, cmtwo_resources)

    all := array.concat(cm, root_resources)
}
我已经阅读了内置函数walk(x[path,value])的文档。医生。我相信这个函数可以实现我希望它实现的功能,但是基于给出的文档以及我在别处找到的一些稀松平常的例子,我不知道如何让它以我所期望的方式工作


我已经包括了一个非常基本的设置和我定义的当前规则。如果有任何帮助,我们将不胜感激。

您的做法是正确的,使用
walk
无疑是收集任意嵌套子资源的好方法

resources[resource_type] = all {
    some resource_type
    resource_types[resource_type]
    rm := tfstate.values.root_module

    # I think the below can be simplified with the built in "walk" function TODO: do that.
    root_resources := [name |
        name := rm.resources[_]
        name.type == resource_type
    ]

    cmone_resources = [name |
        name := rm.child_modules[_].resources[_]
        name.type == resource_type
    ]

    cmtwo_resources = [name |
        name := rm.child_modules[_].child_modules[_].resources[_]
        name.type == resource_type
    ]

    cm := array.concat(cmone_resources, cmtwo_resources)

    all := array.concat(cm, root_resources)
}
首先,我们要探索步行的功能。它将在我们要遍历的对象中的所有节点上进行迭代,并为每个节点提供“路径”和当前节点值。路径将是一个键数组,与对象类似:

{"a": {"b": {"c": 123}}}
如果我们使用
opa运行
REPL进行巡检(以下示例):

> [path, value] = walk({"a": {"b": {"c": 123}}})
+---------------+-----------------------+
|     path      |         value         |
+---------------+-----------------------+
| []            | {"a":{"b":{"c":123}}} |
| ["a"]         | {"b":{"c":123}}       |
| ["a","b"]     | {"c":123}             |
| ["a","b","c"] | 123                   |
+---------------+-----------------------+
我们看到,对于
路径
的值,我们有每个路径和值组合。您可以在部分规则(如
资源
规则)或理解中迭代时捕获这些值中的任何一个

因此..把这一点转移到地形上。如果我们修改游乐场示例来浏览示例输入(稍作修改以给事物赋予一些独特的名称),我们会得到:

如果您查看
walk\u示例的结果值,我们可以看到我们希望必须处理的所有路径和值

从这里开始,我们需要进行过滤,类似于您在
资源
规则中对
资源_类型
所做的过滤。我们将使用它作为查找来检查每个类型是否正确,而不是在集合上进行迭代,我们将首先构建一个包含所有资源的完整集合(不按类型分组)。其原因是遍历输入json的所有节点非常昂贵,因此我们只希望执行一次。随后,我们可以通过第二次传递到“按类型分组”(根据需要)更快地遍历每个资源的完整列表

更新后的版本类似于:

walk_resources[resource] {  
    [path, value] := walk(tfstate)

    # Attempt to iterate over "resources" of the value, if the key doesn't
    # exist its OK, this iteration for walk will be undefined, and excluded
    # from the results.
    # Note: If you needed to be sure it was a "real" resource, and not some
    # key you can perform additional validation on the path here!
    resource := value.resources[_]
    
    # check if the resource type was contained in the set of desired resource types
    resource_types[resource.type]
}

^游乐场输入已更新,以在示例中包含另一级别的嵌套和类型。您可以看到原始
资源
输出缺少深度3资源,但
漫游资源
集包含所有预期的资源

最后一部分,如果要按类型对它们进行分组,请添加完整的规则,如:

# list of all resources of a given type. given type must be defined in the resource_types variable above
resources = { resource_type: resources |
    some resource_type
    resource_types[resource_type]
    resources := { resource | 
        walk_resources[resource]
        resource.type == resource_type
    }
}

它将原始的
资源
规则替换为一个理解,该理解将迭代每个资源类型,然后收集与该类型匹配的资源

我在这些terraform resource helper规则中发现了一个额外的问题,那就是您希望引用“完整”规则,有关这意味着什么的详细信息,请参阅,而不是“部分”规则(在本例中,是构建一组资源的规则,而不是将值分配给理解结果的规则)。问题在于,在编写本文时,OPA会在内部缓存“完整”规则的值,而部分规则则不会。因此,如果您随后去编写一组规则,如:

deny[msg] {
    r := resources["foo"]
    # enforce something for resources of type "foo"...
    ...
}

deny[msg] {
    r := resources["bar"]
    # enforce something for resources of type "bar"...
    ...
}
您希望确保它每次都为
资源
使用缓存值,而不是重新计算集合。您的
资源
规则的原始版本将遇到该问题,同时使用我在这些示例中显示的
walk_resources
规则。需要注意的是,它可能会有一个相当大的dram如果您有一个大的输入计划,atic会对性能产生影响