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 没有。