[英]Array.map for Rego or how to combine RBAC with api routes
我想在 JSON 数据中定义权限,例如:
"permissions": [
{
"resource": ["users", ":uid", "salary"],
"action": "GET"
}
]
现在在评估时,我想用input.subject
替换:uid
。 我该怎么办? Rego 中是否有类似 Array.prototype.map() 的东西?
PS:例如,我知道我可以做到这一点。
allow {
input.action = ["GET", "POST"][_]
input.resource = ["users", uid, "salary"]
input.subject = uid
}
但是,我不想详细说明策略中的每个路径,而是想使用 RBAC(角色 + 权限),以便我可以将这些 API 端点权限作为 JSON 数据传递。 是否可以?
您当然可以编写一个策略来扫描所有权限并检查是否存在匹配项。 这是一个简单(但完整)的示例:
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 |
| | } |
+-----------+-------------------------------------------------------------------------+
在这种情况下,规则索引器将识别等式语句。 但是,由于replace()
调用,索引器将无法有效地索引... = input.resource
语句。
部分挑战是该策略不是纯粹的 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”字段指示资源所有者(在"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 |
| | } |
+-----------+-------------------------------+
现在规则索引器可以识别规则主体上的所有条件,并且评估延迟将随着可能与输入匹配的规则数量而扩展。 当然,这里的权衡是,无论何时权限发生变化,都必须重新执行部分评估。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.