Open Policy Agent - 授权读取数据列表
Open Policy Agent - Authorizing READ on a list of data
问题
我们一直在使用 OPA 对我们的 REST HTTP API 进行数据授权。我们保护我们的API
allow {
input.method == "GET"
glob.match(input.path, ["/"], "/department/DEPARTMENT_ID/employee/")
some_rule # Where we check that user can list all employee in the particular deparment/DEPARTMENT_ID based on the ACL of department/DEPARTMENT_ID
}
如上所示,每个 department
都有自己的 ACL,我们授权禁止访问它及其子资源(例如员工)。
我们通过 OPA 的 HTTP API 查询此策略,并将 department/DEPARTMENT_ID
的 ACL 推送到 OPA 以供其做出决定。参见 OPA docs。
但是,有一个新要求,我们必须创建一个 API,它必须列出用户有权访问的所有 employee
。
鉴于授权不能再只查看一个 ACL,如何才能做到这一点? (因为多个 employee
资源将属于不同的 department
,每个资源都有自己的 ACL)。
可能的解决方案
列出 employee
时,我们可以向 OPA 发送每个 department
(即父级)的所有 ACL,并让 OPA 基于此进行授权。这可能非常低效,但我不确定是否有更好的方法。如果我们对 employee
列表进行分页,它的大小也会受到限制。
我不确定我是否完全遵循,但鉴于您 data
看起来像下面这样:
{
"departments": {
"department1": {
"permissions": {
"jane": ["read"]
},
"employees": {
"x": {},
"y": {},
"z": {}
}
},
"department2": {
"permissions": {
"jane": ["read"]
},
"employees": {
"a": {},
"b": {},
"c": {}
}
},
"department3": {
"permissions": {
"eve": ["read"]
},
"employees": {
"bill": {},
"bob": {},
"eve": {}
}
}
}
}
input
看起来像这样:
{
"user_id": "jane",
"method": "GET",
"department_id": "department1",
"path": "/department/department1/employee"
}
为用户查询所有可列出员工的策略可能如下所示:
package play
import future.keywords.in
allow {
input.method == "GET"
glob.match(input.path, ["/"], sprintf("/department/%v/employee", [input.department_id]))
can_read
}
# Where we check that user can list all employee in the particular deparment/DEPARTMENT_ID based on the ACL of department/DEPARTMENT_ID
can_read {
"read" in data.departments[input.department_id].permissions[input.user_id]
}
listable_employees[employee] {
some department in data.departments
"read" in department.permissions[input.user_id]
some employee, _ in department.employees
}
本例中的 listable_employees
计算结果为:
[
"a",
"b",
"c",
"x",
"y",
"z"
]
由于用户 jane
对 department1 和 department2 具有读取权限,但对 department3 没有。
问题
我们一直在使用 OPA 对我们的 REST HTTP API 进行数据授权。我们保护我们的API
allow {
input.method == "GET"
glob.match(input.path, ["/"], "/department/DEPARTMENT_ID/employee/")
some_rule # Where we check that user can list all employee in the particular deparment/DEPARTMENT_ID based on the ACL of department/DEPARTMENT_ID
}
如上所示,每个 department
都有自己的 ACL,我们授权禁止访问它及其子资源(例如员工)。
我们通过 OPA 的 HTTP API 查询此策略,并将 department/DEPARTMENT_ID
的 ACL 推送到 OPA 以供其做出决定。参见 OPA docs。
但是,有一个新要求,我们必须创建一个 API,它必须列出用户有权访问的所有 employee
。
鉴于授权不能再只查看一个 ACL,如何才能做到这一点? (因为多个 employee
资源将属于不同的 department
,每个资源都有自己的 ACL)。
可能的解决方案
列出 employee
时,我们可以向 OPA 发送每个 department
(即父级)的所有 ACL,并让 OPA 基于此进行授权。这可能非常低效,但我不确定是否有更好的方法。如果我们对 employee
列表进行分页,它的大小也会受到限制。
我不确定我是否完全遵循,但鉴于您 data
看起来像下面这样:
{
"departments": {
"department1": {
"permissions": {
"jane": ["read"]
},
"employees": {
"x": {},
"y": {},
"z": {}
}
},
"department2": {
"permissions": {
"jane": ["read"]
},
"employees": {
"a": {},
"b": {},
"c": {}
}
},
"department3": {
"permissions": {
"eve": ["read"]
},
"employees": {
"bill": {},
"bob": {},
"eve": {}
}
}
}
}
input
看起来像这样:
{
"user_id": "jane",
"method": "GET",
"department_id": "department1",
"path": "/department/department1/employee"
}
为用户查询所有可列出员工的策略可能如下所示:
package play
import future.keywords.in
allow {
input.method == "GET"
glob.match(input.path, ["/"], sprintf("/department/%v/employee", [input.department_id]))
can_read
}
# Where we check that user can list all employee in the particular deparment/DEPARTMENT_ID based on the ACL of department/DEPARTMENT_ID
can_read {
"read" in data.departments[input.department_id].permissions[input.user_id]
}
listable_employees[employee] {
some department in data.departments
"read" in department.permissions[input.user_id]
some employee, _ in department.employees
}
本例中的 listable_employees
计算结果为:
[
"a",
"b",
"c",
"x",
"y",
"z"
]
由于用户 jane
对 department1 和 department2 具有读取权限,但对 department3 没有。