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
相关文章
|
3月前
|
JSON 编译器 网络安全
open policy agent 语法总结
open policy agent 语法总结
52 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)
|
3月前
|
存储 人工智能
|
4天前
|
人工智能 API 决策智能
swarm Agent框架入门指南:构建与编排多智能体系统的利器 | AI应用开发
Swarm是OpenAI在2024年10月12日宣布开源的一个实验性质的多智能体编排框架。其核心目标是让智能体之间的协调和执行变得更轻量级、更容易控制和测试。Swarm框架的主要特性包括轻量化、易于使用和高度可定制性,非常适合处理大量独立的功能和指令。【10月更文挑战第15天】
46 6
|
25天前
|
Python 机器学习/深度学习 人工智能
手把手教你从零开始构建并训练你的第一个强化学习智能体:深入浅出Agent项目实战,带你体验编程与AI结合的乐趣
【10月更文挑战第1天】本文通过构建一个简单的强化学习环境,演示了如何创建和训练智能体以完成特定任务。我们使用Python、OpenAI Gym和PyTorch搭建了一个基础的智能体,使其学会在CartPole-v1环境中保持杆子不倒。文中详细介绍了环境设置、神经网络构建及训练过程。此实战案例有助于理解智能体的工作原理及基本训练方法,为更复杂应用奠定基础。首先需安装必要库: ```bash pip install gym torch ``` 接着定义环境并与之交互,实现智能体的训练。通过多个回合的试错学习,智能体逐步优化其策略。这一过程虽从基础做起,但为后续研究提供了良好起点。
82 4
手把手教你从零开始构建并训练你的第一个强化学习智能体:深入浅出Agent项目实战,带你体验编程与AI结合的乐趣
|
21天前
|
机器学习/深度学习 人工智能 算法
打造你的超级Agent智能体——在虚拟迷宫中智斗未知,解锁AI进化之谜的惊心动魄之旅!
【10月更文挑战第5天】本文介绍了一个基于强化学习的Agent智能体项目实战,通过控制Agent在迷宫环境中找到出口来完成特定任务。文章详细描述了环境定义、Agent行为及Q-learning算法的实现。使用Python和OpenAI Gym框架搭建迷宫环境,并通过训练得到的Q-table测试Agent表现。此项目展示了构建智能体的基本要素,适合初学者理解Agent概念及其实现方法。
61 9
|
18天前
|
人工智能 算法 决策智能
面向软件工程的AI智能体最新进展,复旦、南洋理工、UIUC联合发布全面综述
【10月更文挑战第9天】近年来,基于大型语言模型(LLM)的智能体在软件工程领域展现出显著成效。复旦大学、南洋理工大学和伊利诺伊大学厄巴纳-香槟分校的研究人员联合发布综述,分析了106篇论文,探讨了这些智能体在需求工程、代码生成、静态代码检查、测试、调试及端到端软件开发中的应用。尽管表现出色,但这些智能体仍面临复杂性、性能瓶颈和人机协作等挑战。
45 1