-
-
Notifications
You must be signed in to change notification settings - Fork 359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add remote_opa authorizer #462
Conversation
ryanph seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I've added a couple of comments :)
docs/docs/pipeline/authz.md
Outdated
} | ||
], | ||
"authorizer": { | ||
"handler": "remote_json", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"handler": "remote_json", | |
"handler": "remote_opa", |
pipeline/authz/remote_opa.go
Outdated
|
||
// OPA Policy Input | ||
type OPAInput struct { | ||
User string `json:"user"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This payload is bound to your model of access control and is not generalizable for other use cases. Instead, this should be configurable (see e.g. remote_json
for an implementation). You might also want to wait for JsonNet support (#441) for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The payload for the OPA server needs the Method of the request, as well as the path of the request as an array. I believe I've added the Method correctly into the MatchContext structure, however I'm having a stab at the best way to add the Path "array" into the template.
Given it's specific to this module I don't think it makes sense to put it back in the AuthenticationSession struct but happy to take your guidance on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The payload for the OPA server needs the Method of the request, as well as the path of the request as an array. I believe I've added the Method correctly into the MatchContext structure, however I'm having a stab at the best way to add the Path "array" into the template.
I don't think that is correct. You define the input model using Rego, so it depends on your Rego Policies what input you expect. You're probably referring to this example but as you can see from the Rego policy, the input parameters are defined by the policy itself, not by OPA. If you use a different Rego policy (one using e.g. input.foo_bar_baz
) you would expect {"foo_bar_baz": "..."}
in the JSON payload.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely, the intention though was for it to be able to work with the OPA tutorial you linked "out of the box" and I've also seen this "path split into an array" in use by other developers I'm working with.
Any suggestions on how this could be achieved any other way using text/template, or do you have any objections to this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best approach would be using JsonNet (see #441) but I feat that needs quite some work on my end beforehand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like there's no way to implement this in an acceptable way without JsonNet so I'll close off this PR and look at it again at some point in the future
} | ||
|
||
// Authorize implements the Authorizer interface. | ||
func (a *AuthorizerRemoteOPA) Authorize(_ *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a test :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've basically copied the remote_json test, still reading up on how Viper works and how to run the tests locally to implement some more specific tests for this authorizer.
@@ -0,0 +1,6 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert, see https://github.com/ory/oathkeeper/blob/master/.schemas/README.md :) Changes should be made here: https://github.com/ory/oathkeeper/tree/master/.schema/
Related issue
Issue #98 requests an OPA authoriser
Proposed changes
Implement an OPA authorizer that queries an OPA server via its REST API for authorization. OPA can also be used as a Go library directly within applications and as this authorizer interfaces with an OPA server using the REST API it is called 'remote_opa' rather than just 'opa'.
The existing generic http authorizers (remote and remote_json) rely on the remote service responding with a 200 or 403 response code to authorize requests. When using the OPA REST API to query a policy document with input (e.g. the details of a HTTP request) the response code is always 200 and it is the response body that contains the result of the policy. As such the existing authorizers are not suitable.
A quick way to test / demonstrate this authorizer:
Start an OPA instance:
docker run -p 8181:8181 openpolicyagent/opa run --server
Upload a basic policy:
curl -X PUT --data-binary @example/policy.rego localhost:8181/v1/policies/example
In this example policy anyone can GET /profiles, and users can POST to their own profile under /profiles/username (or in this example with the anonymous authenticator anyone can POST to /profiles/anonymous).
Configure the remote_opa authorizer to use this policy:
The intention of this authorizer is to be a drop in replacement to the python example in the OPA HTTP APIs documentation (https://www.openpolicyagent.org/docs/latest/http-api-authorization/). Rather than allow the policy input sent to the OPA REST API to be templated it is opinionated to use the format from the OPA documentation. An example policy input generated by the module looks like this:
An example response from the OPA REST API looks like this:
Checklist
vulnerability. If this pull request addresses a security. vulnerability, I
confirm that I got green light (please contact
[email protected]) from the maintainers to push
the changes.
works.
Further comments
This is the first Go project I've contributed to, more than happy for address feedback anyone has on any aspect of the code.