Array.map 用于 Rego 或如何将 RBAC 与 api 路由组合
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
}
这种方法的缺点是,在最坏的情况下,每次评估都必须扫描所有权限。随着更多权限的添加,评估将花费更长的时间。根据权限集可以获得的大小,这可能无法满足延迟要求。
对此的典型答案是对 pre-evaluate 权限数据使用部分评估,并生成一个规则集,由于规则索引,该规则集可以在 constant-time 中评估。 Policy Performance 页面介绍了这种方法。例如,如果您 运行 对此策略进行部分评估,则输出为:
$ 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...它是一个 attribute-based 策略,它将(路径段和主题之间的)相等性检查编码到权限数据中。如果我们稍微重组权限数据,我们可以解决这个问题:
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 |
| | } |
+-----------+-------------------------------+
规则主体上的所有条件现在都可以被规则索引器识别,并且评估延迟将根据可能与输入匹配的规则数量进行缩放。这里的权衡当然是每当权限更改时,部分评估必须是 re-executed.
我想在 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
}
这种方法的缺点是,在最坏的情况下,每次评估都必须扫描所有权限。随着更多权限的添加,评估将花费更长的时间。根据权限集可以获得的大小,这可能无法满足延迟要求。
对此的典型答案是对 pre-evaluate 权限数据使用部分评估,并生成一个规则集,由于规则索引,该规则集可以在 constant-time 中评估。 Policy Performance 页面介绍了这种方法。例如,如果您 运行 对此策略进行部分评估,则输出为:
$ 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...它是一个 attribute-based 策略,它将(路径段和主题之间的)相等性检查编码到权限数据中。如果我们稍微重组权限数据,我们可以解决这个问题:
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 |
| | } |
+-----------+-------------------------------+
规则主体上的所有条件现在都可以被规则索引器识别,并且评估延迟将根据可能与输入匹配的规则数量进行缩放。这里的权衡当然是每当权限更改时,部分评估必须是 re-executed.