Open Policy Agent(OPA) 【1】介绍(2)

简介: Open Policy Agent(OPA) 【1】介绍(2)

6. OPA run(互动式)

OPA包括一个交互式外壳程序或REPL(读取-评估-打印循环)。您可以使用REPL来试验策略并为新策略创建原型。

要启动REPL,只需:

./opa run

当您在REPL中输入语句时,OPA会对它们进行评估并打印结果。

> true
true
> 3.14
3.14
> ["hello", "world"]
[
  "hello",
  "world"
]

大多数REPL允许您定义以后可以引用的变量。OPA允许您执行类似的操作。例如,您可以定义一个pi常量,如下所示:

> pi := 3.14

定义“ pi”后,您将查询该值并根据该值编写表达式:

> pi
3.14
> pi > 3
true

通过按Control-D或键入exit以下命令退出REPL :

> exit

您可以通过在命令行上传递策略和数据文件来将它们加载到REPL中。默认情况下,JSON和YAML文件植于下data。

opa run input.json

运行一些查询以查找数据:

> data.server[0].protocols[1]
undefined
> data.servers[0].protocols[1]
"ssh"
> data.servers[i].protocols[j]
+---+---+------------------------------+
| i | j | data.servers[i].protocols[j] |
+---+---+------------------------------+
| 0 | 0 | "https"                      |
| 0 | 1 | "ssh"                        |
| 1 | 0 | "mysql"                      |
| 2 | 0 | "memcache"                   |
| 3 | 0 | "http"                       |
| 4 | 0 | "telnet"                     |
+---+---+------------------------------+
> net := data.networks[_]; net.public
+-----------------------------+
|             net             |
+-----------------------------+
| {"id":"net3","public":true} |
| {"id":"net4","public":true} |
+-----------------------------+

要将数据文件设置为inputREPL中的文档,请在文件路径前添加前缀:

opa run example.rego repl.input:input.json
> data.example.public_server[s]
+-------------------------------------------------------------------+-------------------------------------------------------------------+
|                                 s                                 |                   data.example.public_server[s]                   |
+-------------------------------------------------------------------+-------------------------------------------------------------------+
| {"id":"app","ports":["p1","p2","p3"],"protocols":["https","ssh"]} | {"id":"app","ports":["p1","p2","p3"],"protocols":["https","ssh"]} |
| {"id":"ci","ports":["p1","p2"],"protocols":["http"]}              | {"id":"ci","ports":["p1","p2"],"protocols":["http"]}              |
+-------------------------------------------------------------------+-------------------------------------------------------------------+

7. OPA run(服务器)

要与OPA集成,您可以将其作为服务器运行并通过HTTP执行查询。您可以使用-s或将OPA作为服务器启动--server

./opa run --server ./example.rego

默认情况下,OPA在上侦听HTTP连接0.0.0.0:8181。请参阅参考资料opa run --help,以获取用于更改侦听地址,启用TLS等的选项的列表。


在另一个终端内部使用curl(或类似的工具)来访问OPA的HTTP API。查询/v1/dataHTTP API时,必须将输入数据包装在JSON对象内:

{
    "input": <value>
}

创建输入文件的副本,以通过发送curl:

cat <<EOF > v1-data-input.json
{
    "input": $(cat input.json)
}
EOF

执行一些curl请求并检查输出:

curl localhost:8181/v1/data/example/violation -d @v1-data-input.json -H 'Content-Type: application/json'
curl localhost:8181/v1/data/example/allow -d @v1-data-input.json -H 'Content-Type: application/json'

默认情况下data.system.main,用于不带路径的策略查询。当您在不提供路径的情况下执行查询时,不必包装输入。如果该data.system.main决定未定义,则将其视为错误:

curl localhost:8181 -i -d @input.json -H 'Content-Type: application/json'

您可以重新启动OPA并将其配置为使用任何决策作为默认决策:

./opa run --server --set=default_decision=example/allow ./example.rego

curl从上面重新运行最后一个命令:

curl localhost:8181 -i -d @input.json -H 'Content-Type: application/json'

8. Rego 语法

OPA策略以称为Rego的高级声明性语言表示。Rego(发音为“ ray-go”)是专门为在复杂的分层数据结构上表达策略而构建的。有关Rego的详细信息,请参阅策略语言文档。


below以下示例是交互式的!如果在包含服务器,网络和端口的上方编辑输入数据,则输出将在下面更改。同样,如果您在下面的示例中编辑查询或规则,则输出将更改。在通读本节时,请尝试更改输入,查询和规则,并观察输出的差异。


也可以使用以下命令在您的计算机上本地运行它们opa eval,这是设置说明。

8.1 参考

当OPA评估策略时,它将查询中提供的数据绑定到名为的全局变量input。您可以使用.(点)运算符在输入中引用数据。

input.servers
[
  {
    "id": "app",
    "ports": [
      "p1",
      "p2",
      "p3"
    ],
    "protocols": [
      "https",
      "ssh"
    ]
  },
  {
    "id": "db",
    "ports": [
      "p3"
    ],
    "protocols": [
      "mysql"
    ]
  },
  {
    "id": "cache",
    "ports": [
      "p3"
    ],
    "protocols": [
      "memcache"
    ]
  },
  {
    "id": "ci",
    "ports": [
      "p1",
      "p2"
    ],
    "protocols": [
      "http"
    ]
  },
  {
    "id": "busybox",
    "ports": [
      "p1"
    ],
    "protocols": [
      "telnet"
    ]
  }
]

要引用数组元素,可以使用熟悉的方括号语法:

input.servers[0].protocols[0]
"https"

如果引用的值不存在,则OPA返回undefined。未定义表示OPA无法找到任何结果。

input.deadbeef
undefined decision

8.2 表达式(逻辑与)

要在Rego中制定政策决策,您要针对输入和其他数据编写表达式。

input.servers[0].id == "app"
true

OPA包括一组内置函数,可用于执行常见操作,例如字符串操作,正则表达式匹配,算术,聚合等。

count(input.servers[0].protocols) >= 1
true

有关现成的OPA支持的内置功能的完整列表,请参阅“策略参考”页面。

多个表达式通过;(AND)运算符连接在一起。为了使查询产生结果,查询中的所有表达式必须为真或已定义。表达式的顺序无关紧要。

input.servers[0].id == "app"; input.servers[0].protocols[0] == "https"
true

您可以;通过将表达式分成多行来省略(AND)运算符。以下查询与上一个查询具有相同的含义:

input.servers[0].id == "app"
input.servers[0].protocols[0] == "https"
true

如果查询中的任何表达式都不为真(或未定义),则结果为未定义。在下面的示例中,第二个表达式为false:

input.servers[0].id == "app"
input.servers[0].protocols[0] == "telnet"
undefined decision

8.3 逻辑或

在查询中将多个表达式连接在一起时,您表示的是逻辑与。要在Rego中表达逻辑OR,您可以定义多个具有相同名称的规则。让我们来看一个例子。


想象一下,您想知道是否有任何服务器公开允许客户端外壳访问的协议。为了确定这一点,你可以定义声明了一个完整的规则 shell_accessible是true,如果任何服务器暴露"telnet"或"ssh" 协议:

package example.logical_or
default shell_accessible = false
shell_accessible = true {
    input.servers[_].protocols[_] == "telnet"
}
shell_accessible = true {
    input.servers[_].protocols[_] == "ssh"
}
{
    "servers": [
        {
            "id": "busybox",
            "protocols": ["http", "telnet"]
        },
        {
            "id": "web",
            "protocols": ["https"]
        }
    ]
}
shell_accessible
true

defaultkeyword如果未定义具有相同名称的所有其他规则,则该关键字告诉OPA为该变量分配一个值。

当您将逻辑或与部分规则一起使用时,每个规则定义都会影响分配给变量的一组值。例如,可以将上面的示例修改为生成一组公开"telnet"或 的服务器"ssh"。

package example.logical_or
shell_accessible[server.id] {
    server := input.servers[_]
    server.protocols[_] == "telnet"
}
shell_accessible[server.id] {
    server := input.servers[_]
    server.protocols[_] == "ssh"
}
{
    "servers": [
        {
            "id": "busybox",
            "protocols": ["http", "telnet"]
        },
        {
            "id": "db",
            "protocols": ["mysql", "ssh"]
        },
        {
            "id": "web",
            "protocols": ["https"]
        }
    ]
}
shell_accessible
[
  "busybox",
  "db"
]

8.4 Variables变量

您可以使用:=(赋值)运算符将值存储在中间变量中。可以像一样引用变量input

s := input.servers[0]
s.id == "app"
p := s.protocols[0]
p == "https"
+---------+-------------------------------------------------------------------+
|    p    |                                 s                                 |
+---------+-------------------------------------------------------------------+
| "https" | {"id":"app","ports":["p1","p2","p3"],"protocols":["https","ssh"]} |
+---------+-------------------------------------------------------------------+

当OPA评估表达式时,它将查找使所有表达式都为真的变量的值。如果没有使所有表达式都为真的变量赋值,则结果是不确定的。

s := input.servers[0]
s.id == "app"
s.protocols[1] == "telnet"
undefined decision

变量是不可变的。如果您尝试两次分配相同的变量,OPA将报告错误。

s := input.servers[0]
s := input.servers[1]
1 error occurred: 2:1: rego_compile_error: var s assigned above

OPA必须能够枚举所有表达式中所有变量的值。如果OPA无法枚举任何表达式中变量的值,则OPA将报告错误。

x := 1
x != y  # y has not been assigned a value
2 errors occurred:
2:1: rego_unsafe_var_error: var _ is unsafe
2:1: rego_unsafe_var_error: var y is unsafe

8.5 迭代

像其他声明性语言(例如SQL)一样,Rego没有显式的循环或迭代构造。而是将变量注入表达式中时,隐式发生迭代。

要了解Rego中迭代的工作原理,请想象您需要检查是否有任何公共网络。回想一下,网络是在数组中提供的:

input.networks
[
  {
    "id": "net1",
    "public": false
  },
  {
    "id": "net2",
    "public": false
  },
  {
    "id": "net3",
    "public": true
  },
  {
    "id": "net4",
    "public": true
  }
]

一种选择是测试输入中的每个网络:

input.networks[0].public == true
false
input.networks[1].public == true
false
input.networks[2].public == true
true

这种方法是有问题的,因为可能有太多网络无法静态列出,或更重要的是,可能无法事先知道网络的数量。

在Rego中,解决方案是将数组索引替换为变量。

some i; input.networks[i].public == true
+---+
| i |
+---+
| 2 |
| 3 |
+---+

现在,查询将要求该值i使整个表达式为真。当您在引用中替换变量时,OPA会自动查找满足查询中所有表达式的变量分配。就像中间变量一样,OPA返回变量的值。

您可以根据需要替换任意多个变量。例如,要确定是否有服务器公开了不安全的"http"协议,您可以编写:

some i, j; input.servers[i].protocols[j] == "http"
+---+---+
| i | j |
+---+---+
| 3 | 0 |
+---+---+

如果变量出现多次,则分配满足所有表达式。例如,要查找连接到公共网络的端口的ID,可以编写:

some i, j
id := input.ports[i].id
input.ports[i].network == input.networks[j].id
input.networks[j].public
+---+------+---+
| i |  id  | j |
+---+------+---+
| 1 | "p2" | 2 |
+---+------+---+

为变量提供好名字可能很难。如果仅引用一次变量,则可以将其替换为特殊的_(通配符变量)运算符。从概念上讲,的每个实例_都是一个唯一变量。

input.servers[_].protocols[_] == "http"
true

就像引用不存在的字段或无法匹配的表达式的引用一样,如果OPA无法找到满足所有表达式的任何变量赋值,则结果是不确定的。

some i; input.servers[i].protocols[i] == "ssh"  # there is no assignment of i that satisfies the expression
undefined decision

8.6 规则

Rego使您可以使用规则封装和重用逻辑。规则只是if-then逻辑语句。规则可以是“完整”或“部分”。

8.6.1 完整规则

完整的规则是if-then语句,这些语句将单个值分配给变量。例如:

package example.rules
any_public_networks = true {  # is true if...
    net := input.networks[_]  # some network exists and..
    net.public                # it is public.
}

每条规则都由一个头和一个身体组成。在Rego中,如果规则主体对于某些变量分配集为true,则说规则标题为true 。在上面的示例any_public_networks = true中,头是net := input.networks[_]; net.public是身体。


您可以查询规则生成的值,就像其他任何值一样:

any_public_networks
true

规则生成的所有值都可以通过全局data变量查询。

data.example.rules.any_public_networks
true

您可以通过使用绝对路径引用OPA加载的任何规则来查询其值。规则的路径始终为:

data.<package-path>.<rule-name>

如果您省略= <value>规则标题的一部分,则该值默认为true。您可以按以下方式重写上面的示例,而无需更改其含义:

package example.rules
any_public_networks {
    net := input.networks[_]
    net.public
}

要定义常量,请省略规则主体。省略规则正文时,默认为true。由于规则主体为true,因此规则标头始终为true / defined

package example.constants
pi = 3.14

如果OPA无法找到满足规则主体的变量分配,则可以说该规则是未定义的。例如,如果input提供给OPA的不包括公共网络,any_public_networks则将是未定义的(与false相同)。下面,为OPA提供了一组不同的输入网络(都不是公共的):

{
    "networks": [
        {"id": "n1", "public": false},
        {"id": "n2", "public": false}
    ]
}
any_public_networks
undefined decision
相关文章
|
1月前
|
JSON 编译器 网络安全
open policy agent 语法总结
open policy agent 语法总结
36 1
|
JSON Kubernetes Cloud Native
Open Policy Agent(OPA) 【1】介绍(1)
Open Policy Agent(OPA) 【1】介绍(1)
Open Policy Agent(OPA) 【1】介绍(1)
|
Cloud Native
Open Policy Agent (OPA) 【3】实战
Open Policy Agent (OPA) 【3】实战
Open Policy Agent (OPA) 【3】实战
|
存储 JSON Kubernetes
Open Policy Agent(OPA) 【2】rego 语法
Open Policy Agent(OPA) 【2】rego 语法
|
缓存 Cloud Native Go
Open Policy Agent(OPA) 【1】介绍(3)
Open Policy Agent(OPA) 【1】介绍(3)
|
1月前
|
存储 人工智能
|
8天前
|
人工智能 JSON 数据格式
RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验
【9月更文挑战第6天】RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验
RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验
|
10天前
|
人工智能 算法 自动驾驶
用AI自动设计智能体,数学提分25.9%,远超手工设计
【9月更文挑战第18天】《智能体自动设计(ADAS)》是由不列颠哥伦比亚大学等机构的研究者们发布的一篇关于自动化设计智能体系统的最新论文。研究中提出了一种创新算法——“Meta Agent Search”,此算法通过迭代生成并优化智能体设计,从而实现更高效的智能体系统构建。实验表明,相比人工设计的智能体,Meta Agent Search生成的智能体在多个领域均有显著的性能提升。然而,该方法也面临着实际应用中的有效性与鲁棒性等挑战。论文详细内容及实验结果可于以下链接查阅:https://arxiv.org/pdf/2408.08435。
44 12
|
2天前
|
人工智能 自然语言处理 API
深入浅出 LangChain 与智能 Agent:构建下一代 AI 助手
我们小时候都玩过乐高积木。通过堆砌各种颜色和形状的积木,我们可以构建出城堡、飞机、甚至整个城市。现在,想象一下如果有一个数字世界的乐高,我们可以用这样的“积木”来构建智能程序,这些程序能够阅读、理解和撰写文本,甚至与我们对话。这就是大型语言模型(LLM)能够做到的,比如 GPT-4,它就像是一套庞大的乐高积木套装,等待我们来发掘和搭建。
|
18天前
|
存储 机器学习/深度学习 人工智能
深入浅出 AI 智能体(AI Agent)|技术干货
随着人工智能技术的发展,智能体(AI Agents)逐渐成为人与大模型交互的主要方式。智能体能执行任务、解决问题,并提供个性化服务。其关键组成部分包括规划、记忆和工具使用,使交互更加高效、自然。智能体的应用涵盖专业领域问答、资讯整理、角色扮演等场景,极大地提升了用户体验与工作效率。借助智能体开发平台,用户可以轻松打造定制化AI应用,推动AI技术在各领域的广泛应用与深度融合。
226 0

热门文章

最新文章