Imagine you have a sharing service, e.g. to let friends share all their photos with each other and the API looks roughly as follows:
GET /<user>/photos
returns all the photos of the user either to the owner of the photo collection itself or to its friends.
To achieve this using OPA, we would need something like the following Rego policy:
package share_photos
default allow = false
# user is owner. that is, the value of first path
# fragment is equal to the identified user
allow { split(input.path, "/")[1] == input.user }
# user is friend. that is, the user referenced by the
# first path fragment has the identified user in its friends list
allow { data.friends[split(input.path, "/")[1]][_] == input.user }
It expects two pieces of information in the payload to the OPA instance:
the actual user, making the request and
the path to witch the request is made
So something like this: { "input": { "user": "alice", "path": "bob/photos" } }
. Since the Rego policy defined above returns just true
or false
the corresponding response from the OPA endpoint whould be { "result": true }
or { "result": false }
. Given this and assuming the above policy can be used by making requests to https://opa.local/v1/data/share_photos/policy/allow
the configuration of the Remote Authorizer would look like follows:
pipeline:
authorizers:
- id: photos_access
type: remote
config:
endpoint:
url: https://opa.local/v1/data/share_photos/policy/allow
payload: |
{ "input": { "user": {{ quote .Subject.ID }}, "path": {{ quote .RequestURL.Path }} } }
script: |
heimdall.Payload.result === true
Here the entire authorization happens within heimdall and is completely outsourced from the business logic of our sharing service.