Skip to content

Instantly share code, notes, and snippets.

@binzram
Last active February 14, 2019 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save binzram/1d72e265ae7926d1fa5ba7493e2b05a3 to your computer and use it in GitHub Desktop.
Save binzram/1d72e265ae7926d1fa5ba7493e2b05a3 to your computer and use it in GitHub Desktop.
OPA Spikes, Permission example
# curl -X PUT http://localhost:8181/v1/data/permission -H 'Content-Type: application/json' -d '# Data #'
{
"write": [
{ "ressource": [1, 2], "context": null },
{ "ressource": [1, 3], "context": ["foo"] }
]
}
# curl -X PUT http://localhost:8181/v1/policies/policies/example.rego -H 'Content-Type: text/plain' -d '# Data #'
package opa.example
default allow = false
allow {
input.ressource = data.permission.write[i].ressource[_]
input.context = data.permission.write[i].context[_]
}
allow {
input.ressource = data.permission.write[i].ressource[_]
is_null(data.permission.write[i].context)
}
# curl -X POST http://localhost:8181/v1/data/opa/example -H 'Content-Type: application/json' -d '# Data #'
{
"input": {
"ressource": 2,
"context": "bar"
}
}
@binzram
Copy link
Author

binzram commented Feb 13, 2019

Rules:

  • Write access on ressource 1 with any context (including foo) is granted
  • Write access on ressource 2 with any context is granted
  • Write access on ressource 3 with context foo is granted
  • Write access on ressource 4 is denied

@tsandall
Copy link

Refactored with helper rules

More verbose but avoids duplicating logic inside allow. Policy says that allow is true if permissions_for_resource and perimssions_for_context intersect. This version will only search over the write collection once (whereas in the original version it'll search over it twice.)

allow {
    permissions_for_resource[i]
    permissions_for_context[i]
}

permissions_for_resource[i] {
    data.permission.write[i].resource[_] = input.resource
}

permissions_for_context[i] {
    data.permission.write[i].context[_] = null   
}

permissions_for_context[i] {
    data.permission.write[i].context[_] = input.context
}

Refactored with objects

Using objects instead of arrays. Benefit is that resource permission lookup is constant-time.

allow {
    perm := example_perms[input.resource]
    perm.any_context
}

allow {
    perm := example_perms[input.resource]
    perms.context[_] = input.context
}

example_perms = {
    "resource1": {
        "any_context": true,
        "context": ["foo"], # additional context. not required.
    },
    "resource2": {
        "any_context": true,
    },
    "resource3": {
        "context": ["foo"],
    },
}

Additional thoughts

In your original version and the first version above the permissions are organized into an array. One challenge with arrays is that OPA has to do a linear scan to find matches. The policy query latency will go up as the size of the array increases. One way to resolve this is to use objects instead of arrays to structure the data. Another way to resolve this is to use OPA's partial evaluation feature on the policy to generate a version that can be evaluated in constant-time: https://blog.openpolicyagent.org/partial-evaluation-162750eaf422.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment