如何解决使用走走以rego递归聚合处于地形状态的资源
我正在使用Open Policy Agent针对我的terraform状态的JSON输出编写策略。
这是状态文件的结构:
wrapRootElement
我定义了这个讨厌的规则来实现我想要的,但是显然这不是聚集这些资源的理想方法。
{
"format_version": "0.1","terraform_version": "0.12.28","values": {
"root_module": {
"resources": [],"child_modules": [
{
"resources": [],"address": "","child_modules": [
{
"resources": [],"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)
}
的文档。文档here。我相信此功能可以实现我想要的功能,但是根据我在其他地方提供的文档以及稀疏的示例,我无法弄清楚如何使其按预期运行。
我包括了一个非常基本的设置和我定义的当前规则的playground。任何帮助将不胜感激。
解决方法
您处在正确的轨道上,使用walk
绝对是收集任意嵌套的子资源的好方法。
首先,我们将探索步行的功能。它实际上将遍历我们要遍历的对象中的所有节点,并为每个节点提供“路径”和当前节点值。路径将是一个键数组,就像对象:
{"a": {"b": {"c": 123}}}
如果我们走过去(以下示例,使用opa run
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 |
+---------------+-----------------------+
我们看到path
和value
的值具有每种路径和值的组合。您可以在部分规则(例如resources
规则)或理解中进行迭代时捕获任何这些值。
所以..把它交给了terraform的东西。如果我们修改操场示例以遍历示例输入(对示例输入进行了稍微修改以赋予事物一些唯一的名称),则会得到:
walk_example[path] = value {
[path,value] := walk(tfstate)
}
https://play.openpolicyagent.org/p/2u5shGbrV2
如果查看walk_example
的结果值,我们会看到我们期望必须处理的所有路径和值。
从那里开始,就需要对resources
进行过滤(类似于您在resource_types
规则中所做的操作)。与其对集合进行迭代,我们将使用它作为查询来检查每个确定的类型,然后我们将首先构建完整的 all 资源集(不按类型对它们进行分组)。原因是遍历输入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]
}
https://play.openpolicyagent.org/p/TyqMKDyWyh
^游乐场输入已更新,以在示例中包括另一级嵌套和类型。您可以看到原始的resources
输出缺少该深度3资源,但是walk_resources
集包含了所有预期的资源。
最后一部分,如果您想按类型对它们进行分组,请添加完整的规则,例如:
# 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
}
}
https://play.openpolicyagent.org/p/RlRZwibij9
使用一种理解来替换原始的resources
规则,该规则将遍历每种资源类型,然后收集与该类型匹配的资源。
我在这些terraform资源帮助程序规则中发现了一个额外的指针,那就是您将要引用该“完全”规则,有关其含义的详细信息,请参见https://www.openpolicyagent.org/docs/latest/policy-language/#complete-definitions比“部分”规则(在这种情况下,是建立一组资源而不是将值分配给理解结果的规则)。问题在于,在编写本文时,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"...
...
}
您要确保它每次都使用resources
的缓存值,并且不重新计算集合。您的resources
规则的原始版本以及使用我在这些示例中显示的walk_resources
规则都会遇到该问题。需要注意的是,如果您输入的tfplan很大,它可能会对性能产生极大的影响。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。