Open christian-roggia opened 4 years ago
I'd be interested to hear ideas how we could implement this:
Both in terms of the access rule semantics as well as the actual code base given that we don't actually know the GraphQL schema, implying that all of this needs to be more or less as generic as possible!
This is an early stage RFC proposal for an integration of oathkeeper with GraphQL. A Proof-of-Concept of this RFC is being developed at Animeshon under the project name "graphql-proxy" and will likely be open-sourced once it is ready for an early alpha and custom business logic has been decoupled from the main repository.
In the current state, oathkeeper is not able to perform any useful operation when a GraphQL request is intercepted.
Lets first analyze why this is the case:
/graphql
Due to the reasons explained above, you are currently limited in the following core operations:
guest
or anonymous
handler, resolvers must be responsible for authentication, oathkeeper can only forward authentication headers to the GraphQL server or gateway. If you want to manage everything from oathkeeper it results again in a scenario where you either ALLOW all requests from a user or you DENY allIn the past year, we at Animeshon had to deal very frequently with both Istio and Oathkeeper as the two services are the most important components in routing and dispatching requests to the right service, authenticated, authorized, and hydrated. This is the main reason why we took the request flow example from these two technologies to design a proxy for our GraphQL Gateway service (we use Apollo Federation internally).
The current request flow looks very often like the following diagram:
Requests get through a load balancer, which forwards them to a reverse-proxy (e.g. oathkeeper-proxy, Ambassador, Istio, ...) which in turn will authenticate and authorize (hydrate, mutate, etc.) the requests through Hydra, Kratos, etc. This flow does not work with GraphQL as previously mentioned.
The Proof-of-Concept that we are implementing is an additional component that is placed in front of the GraphQL Gateway or Server and intercepts all the requests awaiting authorization (it is designed to work in the same manner as a sidecar):
The final RFC should (hopefully) look similar to the following diagram:
That is - GraphQL requests are natively managed by oathkeeper with a logic similar to the one implemented in the PoC. We believe this is a very important feature as the GraphQL community is growing fast and many companies use it as an alternative to REST APIs.
What is left to be discussed is how to actually implement Authentication and Authorization, and more specifically how to translate the path
and methods
from REST APIs to the GraphQL logic.
The following request is a very basic GraphQL request:
mutation {
updateLibrary(input: {name: "Test", id: "47b3f42a-65c2-46b1-93d5-47ff4e92cf5b"}) {
id
}
}
Analyzing the request the following information might be relevant to oathkeeper:
mutation
updateLibrary
input
field has the attribute id
set to 47b3f42a-65c2-46b1-93d5-47ff4e92cf5b
id
is requested in the responseThe best way to extract this information is to parse the request with a GraphQL parser, we use https://github.com/graphql-go/graphql/blob/master/language/parser/parser.go for this purpose. The output is an Abstract Syntax Tree which is surprisingly easy to use.
Through the AST the information mentioned above can easily be extracted to generate a meaningful context for oathkeeper.
Once this information is known it can be used according to the requirements of the client, and rules might look similar to the following structure:
- id: "graphql:libaries:update"
match:
name: "updateLibrary"
operations: [ mutation ]
authorizer:
- handler: remote_json
config:
remote: http://keto-api.keto:4456/engines/acp/ory/exact/allowed
payload: |
{
"subject": "identities:{ print .Subject }",
"action": "library.set",
"resource": "libraries:{ print .Arguments.input.id }"
}
This implementation should be enough to cover the most common use-cases and through Go-Templates / Jsonnet the rules should be flexible enough to also allow for complex scenarios. This implementation is also completely schema-agnostic and authorizes requests based on the information provided by the rules.
While this example covers only Authorization, once the AST is in place it should be easy to also mutate or hydrate the requests in the same manner as REST APIs. As an example, new arguments can be injected into the requests in transit to hydrate the request with more information such as metadata, user identity information, and more.
This is an early draft for potential future implementation, any feedback is as always more than welcome.
@christian-roggia thank you for the super detailed post! I just wanted to post this as an acknowledgement - I will try to get to this ASAP, probably tomorrow!
Nice, this sounds great! I wasn't aware that there is an AST parser for GraphQL but given that there is, your approach seems very sensible, very sensible! We are currently at full capacity unfortunately so we'll not be able to spend time on this at the moment. However, if you plan on contributing this, I'd be more than happy to help!
We are still evaluating some details regarding the RFC for the PoC, I will get you a new proposal once it is finalized on our side :+1:
Awesome, looking forward to it!!
I would be interested in this. Is there any code anywhere to play around with?
The project was momentarily put on hold while keto "new generation" was being developed.
The development of this authorization flow will resume on our side in the next months.
Hello contributors!
I am marking this issue as stale as it has not received any engagement from the community or maintainers a year. That does not imply that the issue has no merit! If you feel strongly about this issue
Throughout its lifetime, Ory has received over 10.000 issues and PRs. To sustain that growth, we need to prioritize and focus on issues that are important to the community. A good indication of importance, and thus priority, is activity on a topic.
Unfortunately, burnout has become a topic of concern amongst open-source projects.
It can lead to severe personal and health issues as well as opening catastrophic attack vectors.
The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone.
If this issue was marked as stale erroneous you can exempt it by adding the backlog
label, assigning someone, or setting a milestone for it.
Thank you for your understanding and to anyone who participated in the conversation! And as written above, please do participate in the conversation if this topic is important to you!
Thank you šāļø
@aeneasr hi, is this completed or being left for now?
If the latter, @christian-roggia do you have any code from the previous POC you could share?
Closed in error
@aeneasr / @christian-roggia is this issue still being considered?
Sure, but it's not on Ory's roadmap right now as we focus on other priorities.
Hey, @christian-roggia!
We're interested in picking this up @gameflow-tv, would you mind sharing some of the progress you made?
Hello contributors!
I am marking this issue as stale as it has not received any engagement from the community or maintainers for a year. That does not imply that the issue has no merit! If you feel strongly about this issue
Throughout its lifetime, Ory has received over 10.000 issues and PRs. To sustain that growth, we need to prioritize and focus on issues that are important to the community. A good indication of importance, and thus priority, is activity on a topic.
Unfortunately, burnout has become a topic of concern amongst open-source projects.
It can lead to severe personal and health issues as well as opening catastrophic attack vectors.
The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone.
If this issue was marked as stale erroneously you can exempt it by adding the backlog
label, assigning someone, or setting a milestone for it.
Thank you for your understanding and to anyone who participated in the conversation! And as written above, please do participate in the conversation if this topic is important to you!
Thank you šāļø
Iām still very interested in this feature!
This ticket has been created with the intent to collect consensus and feedback from the community for future GraphQL integration and support.
If you would like to see GraphQL natively integrated with oathkeeper please add a :+1: or a :heart: to this post rather than writing "+1" in the comments.
If you want to contribute with your personal input and use-case regarding GraphQL please do so in this ticket.