Imagine you have a billing service, which requires information about the membership of a user to different groups, which represent different subscription options for you entire offering. Depending on this information your service would create invoices with different amounts. The imaginary API of that service could look like follows:
You could perform the required query to OPA entirely in your service and use the retrieved group memberships then. Alternatively, you could outsource the communication to OPA to heimdall and deal only with the group membership information in your service. Compared to the Sharing Service example, this time heimdall would not perform any authorization, but rather enrich the subject information with further information. This way, we’re not going to use a Authorizer, but a Generic Contextualizer instead. As with Sharing Service example, there is a need for a Rego policy, which could look like this:
package invoice
groups_graph[data.groups[subject].name] = edges {
edges := data.groups[subject].member_of
}
member_of_groups[subject] = groups {
groups_graph[subject]
groups := graph.reachable(groups_graph, {subject})
}
groups {
member_of_groups[input.user][_]
}
It expects just one piece of information, namely the actual user, making the request. So something like this: { "input": { "user": "alice" } }
. Since the Rego policy defined above returns a list of groups, the corresponding response from the OPA endpoint would be { "result": ["group1", "group2"] }
. Given this and assuming the above policy can be used by making requests to https://opa.local/v1/data/invoice/policy/groups
and the authentication to that endpoint requires basic authentication, the configuration of the Generic Contextualizer would look like follows:
id: billing_contextualizer
type: generic
config:
endpoint:
url: https://opa.local/v1/data/invoice/policy/groups
auth:
type: basic_auth
config:
user: MyOpaUser
password: SuperSecretPassword
payload: |
{ "input": { "user": {{ quote .Subject.ID }} } }
Upon successful execution of the corresponding request, the response from the OPA endpoint will be stored in the Outputs["billing_contextualizer"]
field. That way, you can use that information in a Finalizer to forward the group membership to the billing service API.