简介

开放策略代理(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 例子 :::

  1. package app.rbac
  2. import future.keywords.in
  3. default allow := false
  4. # 如果是 admin 直接放行
  5. # 注意:多个 allow 结果是 "||"
  6. allow {
  7. user_is_admin(null)
  8. }
  9. user_is_admin(_) {
  10. "admin" in data.user_roles[input.user]
  11. }
  12. allow {
  13. user_is_granted(null)
  14. }
  15. user_is_granted(_) {
  16. # some every 都是循环,区别是 some 只要有一个为true,就会终止循环
  17. # 以下可以理解为一个嵌套循环
  18. # 先找 user 的角色
  19. some role in data.user_roles[input.user]
  20. # 根据 角色 再找到 授予权限
  21. some grant in data.role_grants[role]
  22. input.action == grant.action
  23. input.type == grant.type
  24. }

资源限定

  1. package project.submodel
  2. import future.keywords.in
  3. import future.keywords.every
  4. default allow := false
  5. allow {
  6. # 定义在一起的,逻辑是 "&&", 以这个为例子,以下3个条件 要全是 trueallow 才是 true
  7. normal_policy(input.payload)
  8. authentication_policy(input.payload)
  9. resource(null) # 如果这个函数 被定义了多次,逻辑是 "||"
  10. }
  11. # 定义函数,必须得有个参数
  12. resource(_) {
  13. # 如果 input["resource"]["resource"] 不存在,返回true
  14. not input["resource"]["resource"]
  15. }
  16. resource(_) {
  17. input.packaging[input["resource"]["resource"]]["enable"] == true
  18. }
  19. authentication_policy(payload) {
  20. # every 遍历所有
  21. every policy, _ in payload["policies"]["authentication"] {
  22. input.packaging["policies"]["authentication"]["methods"][policy]["enabled"] == true
  23. }
  24. }
  25. authentication_policy(payload) {
  26. not payload["policies"]["authentication"]
  27. }
  28. normal_policy(payload) {
  29. every policy, _ in payload["policies"] {
  30. input.packaging["policies"][policy]["enabled"] == true
  31. }
  32. }
  33. normal_policy(payload) {
  34. not payload["policies"]
  35. }

自定义的权限

  1. package cloud.authz
  2. import future.keywords.in
  3. default allow := false
  4. allow {
  5. method := input.method
  6. resource := input.resource
  7. # 提前将 scope resource method 定义好,放在 role
  8. # 当发生请求时,将请求的行为,为role 里的行为做对比
  9. # some 只要一个满足即可,并为打断循环
  10. some role in input.roles
  11. role.role.permissions[resource.scope][resource.resource][method] == true
  12. }
  13. allow {
  14. # role admin 时,直接放行
  15. some role in input.roles
  16. role["admin"] == true
  17. }


go-client

文档:https://pkg.go.dev/github.com/open-policy-agent/opa/rego

  1. var (
  2. //go:embed pricing.rego
  3. module string
  4. )
  5. func main() {
  6. query, err := rego.New(rego.Query("data.project.submodel.allow"), rego.Module("project.submodel.rego", module))
  7. .PrepareForEval(ctx.GlobalContext)
  8. if err != nil {
  9. panic(err)
  10. }
  11. input := map[string]interface{}{
  12. "payload": payload,
  13. input["packaging"] = plan.(*types.Plan).Packaging
  14. }
  15. if resource != consts.AppResourceType && resource != consts.APIResourceType {
  16. input["resource"] = resource
  17. }
  18. result, err := query.Eval(c, rego.EvalInput(input))
  19. if err != nil {
  20. panic(err)
  21. }
  22. fmt.Println(result.Allowed())
  23. }