I would like to define permissions in JSON data such as:
"permissions": [
{
"resource": ["users", ":uid", "salary"],
"action": "GET"
}
]
Now when evaluating, I want to replace :uid
with input.subject
. How would I go about this? Is there something like Array.prototype.map() in Rego?
PS: I know I can do this, for example.
allow {
input.action = ["GET", "POST"][_]
input.resource = ["users", uid, "salary"]
input.subject = uid
}
But instead of spelling out each path in the policy, I would like to use RBAC (roles + permissions) so that I can pass those API endpoint permissions as JSON data. Is it possible?
You can certainly write a policy that scans over all of the permissions and checks if there's a match. Here's a simple (but complete) example:
The downside of this approach is that each evaluation has to, in the worse case, scan over all permissions. As more permissions are added, evaluation will take longer. Depending on how large the permission set can get, this might not satisfy the latency requirements.
The typical answer to this is to use partial evaluation to pre-evaluate the permissions data and generate a rule set that can be evaluated in constant-time due to rule indexing. This approach is covered on the Policy Performance page. For example, if you run partial evaluation on this policy, this is the output:
In this case, the equality statements would be recognized by the rule indexer. However, the indexer will not be able to efficiently index the
... = input.resource
statements due to thereplace()
call.Part of the challenge is that this policy is not pure RBAC...it's an attribute-based policy that encodes an equality check (between a path segment and the subject) into the permission data. If we restructure the permission data a little bit, we can workaround this:
This version is quite similar except we have explicitly encoded ownership into the permission model. The "owner" field indicates the resource owner (provided in the input document under the
"owner"
key) must be equal to the specified input value (in this example,input.subject
).Running partial evaluation on this version yields the following output:
All of the conditions on the rule bodies are now recognized by the rule indexer and evaluation latency will scale w/ the number of rules that could potentially match the input. The tradeoff here of course is that whenever the permissions change, partial evaluation has to be re-executed.