0

我想在 JSON 数据中定义权限,例如:

"permissions": [
 {
  "resource": ["users", ":uid", "salary"],
  "action": "GET"
 }
]

现在在评估时,我想:uidinput.subject. 我该怎么办?Rego 中有类似 Array.prototype.map() 的东西吗?

PS:例如,我知道我可以做到这一点。

allow {
    input.action = ["GET", "POST"][_]
    input.resource = ["users", uid, "salary"]
    input.subject = uid
}

但是,我不想在策略中拼出每个路径,而是想使用 RBAC(角色 + 权限),以便我可以将这些 API 端点权限作为 JSON 数据传递。可能吗?

4

1 回答 1

3

您当然可以编写一个扫描所有权限并检查是否匹配的策略。这是一个简单(但完整)的示例:

package play

permissions = [
    {
        "resource": "/users/:uid/salary",
        "action": "GET"
    },
    {
        "resource": "/metrics",
        "action": "GET"
    }
]

default allow = false

allow {
    some p
    matching_permission[p]
}

matching_permission[p] {
    some p
    matching_permission_action[p]
    matching_permission_resource[p]
}

matching_permission_action[p] {
    some p
    permissions[p].action == input.action
}

matching_permission_resource[p] {
    some p
    path := replace(permissions[p].resource, ":uid", input.subject)
    path == input.resource
}

这种方法的缺点是每次评估都必须在最坏的情况下扫描所有权限。随着更多权限的添加,评估将需要更长的时间。根据权限集可以获得的大小,这可能无法满足延迟要求。

对此的典型答案是使用部分评估来预先评估权限数据并生成一个规则集,由于规则索引,该规则集可以在恒定时间内进行评估。政策绩效页面介绍了这种方法。例如,如果您对此策略运行部分评估,则输出如下:

$ opa eval -d play.rego -f pretty 'data.play.allow' -p --disable-inlining data.play.allow
+-----------+-------------------------------------------------------------------------+
| Query 1   | data.partial.play.allow                                                 |
+-----------+-------------------------------------------------------------------------+
| Support 1 | package partial.play                                                    |
|           |                                                                         |
|           | allow {                                                                 |
|           |   "GET" = input.action                                                  |
|           |                                                                         |
|           |   replace("/users/:uid/salary", ":uid", input.subject) = input.resource |
|           | }                                                                       |
|           |                                                                         |
|           | allow {                                                                 |
|           |   "POST" = input.action                                                 |
|           |                                                                         |
|           |   replace("/metrics", ":uid", input.subject) = input.resource           |
|           | }                                                                       |
+-----------+-------------------------------------------------------------------------+

在这种情况下,规则索引器将识别等式语句。... = input.resource但是,由于replace()调用,索引器将无法有效地索引语句。

部分挑战在于该策略不是纯粹的 RBAC……它是一种基于属性的策略,将(路径段和主题之间的)相等性检查编码到权限数据中。如果我们稍微重构一下权限数据,我们可以解决这个问题:

package play2

permissions = [
    {
        "owner": "subject",
        "resource": "salary",
        "action": "GET"
    },
    {
        "resource": "metrics",
        "action": "GET"
    },
]

allow {
    some p
    matching_permission[p]
}

matching_permission[p] {
    some p
    matching_permission_action[p]
    matching_permission_resource[p]
    matching_permission_owner[p]
}

matching_permission_action[p] {
    some p
    permissions[p].action == input.action
}

matching_permission_resource[p] {
    some p
    permissions[p].resource == input.resource
}

matching_permission_owner[p] {
    some p
    permissions[p]
    not permissions[p].owner
}

matching_permission_owner[p] {
    some p
    owner := permissions[p].owner
    input.owner = input[owner]
}

这个版本非常相似,只是我们将所有权明确编码到权限模型中。“所有者”字段表示资​​源所有者(在输入文档中提供的"owner"键下)必须等于指定的输入值(在本例中为input.subject)。

在此版本上运行部分评估会产生以下输出:

$ opa eval -d play2.rego -f pretty 'data.play2.allow' -p --disable-inlining data.play2.allow
+-----------+-------------------------------+
| Query 1   | data.partial.play2.allow      |
+-----------+-------------------------------+
| Support 1 | package partial.play2         |
|           |                               |
|           | allow {                       |
|           |   "GET" = input.action        |
|           |                               |
|           |   "salary" = input.resource   |
|           |                               |
|           |   input.owner = input.subject |
|           | }                             |
|           |                               |
|           | allow {                       |
|           |   "GET" = input.action        |
|           |                               |
|           |   "metrics" = input.resource  |
|           | }                             |
+-----------+-------------------------------+

规则索引器现在可以识别规则主体上的所有条件,并且评估延迟将随着可能与输入匹配的规则数量而扩展。当然,这里的权衡是每当权限发生变化时,都必须重新执行部分评估。

于 2020-09-18T16:14:58.280 回答