简介
开放策略代理(Open Policy Agnet)是一个开源的通用策略引擎,可统一整个堆栈的策略执行。OPA 提供了一种高级声明性语言,可让您将策略指定为代码和简单的 API,以从您的软件中卸载策略决策。
文档:https://www.openpolicyagent.org/docs/latest/
rego
Rego 是 OPA 定义的一套规则,我们可以利用 rego 来实现我们的需求,这里不详细介绍它的语法
playgroud: https://play.openpolicyagent.org/
同时 playgroud 里提供了几个模板,有助于我们学习 rego
case
RABC
:::warning
与官方提供的demo的不一样,返回值这里只有 一个 allow
input 与 data 参考 playground 的 RABC 例子
:::
package app.rbacimport future.keywords.indefault allow := false# 如果是 admin 直接放行# 注意:多个 allow 结果是 "||"allow {user_is_admin(null)}user_is_admin(_) {"admin" in data.user_roles[input.user]}allow {user_is_granted(null)}user_is_granted(_) {# some 和 every 都是循环,区别是 some 只要有一个为true,就会终止循环# 以下可以理解为一个嵌套循环# 先找 user 的角色some role in data.user_roles[input.user]# 根据 角色 再找到 授予权限some grant in data.role_grants[role]input.action == grant.actioninput.type == grant.type}
资源限定
package project.submodelimport future.keywords.inimport future.keywords.everydefault allow := falseallow {# 定义在一起的,逻辑是 "&&", 以这个为例子,以下3个条件 要全是 true,allow 才是 truenormal_policy(input.payload)authentication_policy(input.payload)resource(null) # 如果这个函数 被定义了多次,逻辑是 "||"}# 定义函数,必须得有个参数resource(_) {# 如果 input["resource"]["resource"] 不存在,返回truenot input["resource"]["resource"]}resource(_) {input.packaging[input["resource"]["resource"]]["enable"] == true}authentication_policy(payload) {# every 遍历所有every policy, _ in payload["policies"]["authentication"] {input.packaging["policies"]["authentication"]["methods"][policy]["enabled"] == true}}authentication_policy(payload) {not payload["policies"]["authentication"]}normal_policy(payload) {every policy, _ in payload["policies"] {input.packaging["policies"][policy]["enabled"] == true}}normal_policy(payload) {not payload["policies"]}
自定义的权限
package cloud.authzimport future.keywords.indefault allow := falseallow {method := input.methodresource := input.resource# 提前将 scope resource method 定义好,放在 role 里# 当发生请求时,将请求的行为,为role 里的行为做对比# some 只要一个满足即可,并为打断循环some role in input.rolesrole.role.permissions[resource.scope][resource.resource][method] == true}allow {# 或 role 为 admin 时,直接放行some role in input.rolesrole["admin"] == true}
go-client
文档:https://pkg.go.dev/github.com/open-policy-agent/opa/rego
var (//go:embed pricing.regomodule string)func main() {query, err := rego.New(rego.Query("data.project.submodel.allow"), rego.Module("project.submodel.rego", module)).PrepareForEval(ctx.GlobalContext)if err != nil {panic(err)}input := map[string]interface{}{"payload": payload,input["packaging"] = plan.(*types.Plan).Packaging}if resource != consts.AppResourceType && resource != consts.APIResourceType {input["resource"] = resource}result, err := query.Eval(c, rego.EvalInput(input))if err != nil {panic(err)}fmt.Println(result.Allowed())}
