文档地址https://www.openpolicyagent.org/docs/latest/#1-download-opa
curl -L -o opa https://openpolicyagent.org/downloads/v0.33.1/opa_linux_amd64_static
chmod a+x opa
mv opa /usr/local/bin
package r1 #必须有包名
pi = 3.14
运行:
opa eval -d r1.rego "data.r1.pi"
// -d为代码文件,data字段固定,r1为package名,pi为变量名,该行为获取pi的值
如果需要用到input文件:
opa eval -i input.json -d r1.rego "data.r1.xx"
input.json
{
"servers": [
{"id": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]},
{"id": "db", "protocols": ["mysql"], "ports": ["p3"]},
{"id": "cache", "protocols": ["memcache"], "ports": ["p3"]},
{"id": "ci", "protocols": ["http"], "ports": ["p1", "p2"]},
{"id": "busybox", "protocols": ["telnet"], "ports": ["p1"]}
],
"networks": [
{"id": "net1", "public": false},
{"id": "net2", "public": false},
{"id": "net3", "public": true},
{"id": "net4", "public": true}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net3"},
{"id": "p3", "network": "net2"}
]
}
opa run input.json
>data.servers[0].id // 用 []加索引 取列表,用 . 取key
"app"
或者不使用input,直接
opa run
input.json如下
{
"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"
]
}
]
}
进入交互式界面
opa run input.json
OPA 0.33.1 (commit 64359ae, built at 2021-10-04T11:26:46Z)
Run 'help' to see a list of commands and check for updates.
> data.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"
]
}
]
>
>
> data.servers[0]
{
"id": "app",
"ports": [
"p1",
"p2",
"p3"
],
"protocols": [
"https",
"ssh"
]
}
>
>
> data.servers[0].ports
[
"p1",
"p2",
"p3"
]
>
> data.servers[0].ports[0]
"p1"
>
>
> data.servers[0].ports[0] == "p2"
false
>
> data.servers[0].ports[0] == "p1"
true
>
> data.servers[0].ports[0] > "p0"
true
>
> data.servers[0].ports[0] > "p2"
false
>
>
> data.servers[0].ports[0] != "p2"
true
>
> data.servers[0].ports[0] >= "p1"
true
>
> count(data.servers[0].protocols) >= 1
true
>
> p1 = 1
Rule 'p1' defined in package repl. Type 'show' to see rules.
>
> p2 {p1=1} # 意思是p2==true如果p1等于1,否则为undefined,不会有false,
# 如果使用opa eval -d r1.rego "data.r1.p2"去取值的话,如果不满足条件返回{}
Rule 'p2' defined in package repl. Type 'show' to see rules.
>
> p1
1
>
> p2
true
>
> p3 {x=1; y=2; x+y=3}
Rule 'p3' defined in package repl. Type 'show' to see rules.
>
> p3
true
>
> p4 {x=1; y=2; x+y=4} # 如果条件不成立p4结果为undefined
Rule 'p4' defined in package repl. Type 'show' to see rules.
>
> p4
undefined
注意1:顺序无所谓
s {
x == y + 1
y = 41
x = 42
}
# 结果还是为true
注意2:= 与 :=的区别
z {
y := 41
y := 42
43 > y
}
# 会报错 var y assigned above,y已经被定义过了,不能重复定义,
# 演示的时候为了重复使用,没有使用:=赋值,推荐使用:=赋值
注意3:不可使用未声明的变量
z {
abc == 2
}
# 会报错var abc is unsafe
/*
[{"msg": i, "index": j}]表示返回值的格式,表示包含多个{"msg": i, "index": j}的集合
z6 = [{"a":1}, {"a":1}, {"b":2}]
z7 [{"msg": v}]{
v = z6[_] # _的含义再后面说明
}
此时z7的结果中只有[{"a":1},{"b":2}]
z8 [{"msg": v, "index": i}]{
v = z6[i]
}
*/
z5 [{"msg": i, "index": j}]{
i = input.servers[0].ports[j] == "p1" # 使用了input文件,则数据从input.xxxx取
}
# opa eval -i input.json -d r1.rego "data.r1.z5"
结果为
{
"result": [
{
"expressions": [
{
"value": [
{
"index": 0,
"msg": true
},
{
"index": 1,
"msg": false
},
{
"index": 2,
"msg": false
}
],
"text": "data.r1.z5",
"location": {
"row": 1,
"col": 1
}
}
]
}
]
}
多维数组遍历
z5 [{"msg": msg, "index":[i, j]}]{
msg = input.servers[i].ports[j] == "p1"
}
或者不关注索引
z5 [{"msg": msg}]{
msg = input.servers[_].ports[_] == "p1"
}
_ 的含义
满足全部条件的rule
r1 {
n1 = 1
n2 = 3
n1 + n2 = 4
}
# {}中的条件全部满足,则返回true
# 交互式命令行满足条件返回true,不满足返回undefined
# 非交互式满足条件返回true,不满足返回{}
满足部分条件的rule
r2_data = [{"a":true, "id":1}, {"a": false, "id":2}]
r2 [r2_rlt.id]{
r2_rlt = r2_data[_] # 遍历r2_data,忽略索引
r2_rlt.a # 如果列表中有元素的a字段为true,则满足条件,不需要全部满足,存在即可
}
violation(不一定非要用这个名称,只是violation即表示违反的意思)
input.json:
{
"servers": [
{
"id": "busybox",
"protocols": ["http", "telnet"]
},
{
"id": "db",
"protocols": ["mysql", "ssh"]
},
{
"id": "web",
"protocols": ["https"]
}
]
}
想要达到的效果是协议包含https和ssh的server不能被暴露,如果servers中存在这样的主机,则不被允许
allow {
count(violation) == 0
}
violation[server.id] {
server = input.servers[_]
server.protocols[_] == "https"
}
violation[server.id] {
server = input.servers[_]
server.protocols[_] == "ssh"
}
opa eval -i input.json -d r1.rego "data.r1.allow"
列表生成式
sites = [
{"region": "west", "name": "name1"},
{"region": "west", "name": "name2"},
{"region": "not-west", "name": "name3"}
]
region := "west"
names = [name | some i; sites[i].region == region; name := sites[i].name]
# 可以不用声明变量i,直接使用,其他字符也可,比如,b,c,d,e,f
names2 = [name | sites[i].region == region; name := sites[i].name]
# 不可以使用_,_表示存在region="west"的即满足
names2 = [name | sites[_].region == region; name := sites[_].name]
# 如同python中
names = [site.name for site in sites if site.region == "west"]
集合生成式、字典操作
ipt = {"metadata": {"name": "ns-test", "labels": {"a": "b", "gatekeeper": "abc", "b": "c"}}}
# {}表示集合,此行表示获取labels所有的key,而不是value,会获取到{"a", "gatekeeper", "b"}
provided := {label | ipt.metadata.labels[label]}
# 获取所有val, 用key去获取即可
provided2 := {ipt.metadata.labels[label] | ipt.metadata.labels[label]}
# 集合可以做减操作,c == {"c"},不可做加操作
a = {"a", "b", "c"}
b = {"a", "b"}
c = a - b
# 验证字典中是否有某个key
viok[{"msg": msg}]{
kv := {"a": 1, "b": 2}
k := "a"
not kv[k]
# v := object.get(kv, k, "abc") 如果不存在取默认值abc
# v == "abc"
msg = sprintf("msg: not k %v", [k])
}
# 内置函数https://www.openpolicyagent.org/docs/latest/policy-reference/#objects-2
trim_and_split(s) = x {
t := trim(s, " ")
x := split(t, ".")
}
trim_and_split(" foo.bar ")
[
"foo",
"bar"
]
Rego在线编辑器The Rego Playground