microsoft / reverse-proxy

A toolkit for developing high-performance HTTP reverse proxy applications.
https://microsoft.github.io/reverse-proxy
MIT License
8.52k stars 836 forks source link

Http Method Match in K8S Controller #1828

Open adityamandaleeka opened 2 years ago

adityamandaleeka commented 2 years ago

Discussed in https://github.com/microsoft/reverse-proxy/discussions/1825

Originally posted by **pinkfloydx33** August 13, 2022 I have a proxied endpoint that requires authorization based on the Http Method. For `POST`, the endpoint accepts anonymous requests; for everything else it requires authorization. It's something akin to a user endpoint where `POST` represents signing up to an application. I can easily codify this in configuration-based routes using the `route.Match.Methods` property, plus _either_ a higher priority `Order` for the `POST` endpoint _or_ spelling out the remaining HTTP methods on the other. However, this doesn't seem possible to do when using the Ingress controller as it does not have an http-methods annotation. If such an annotation _were_ supported, this would require creating two `Ingress` resources with the same path and host. So far as I am aware, this is technically a valid thing to do per K8S. The Ingress Controller should be able to support such a case since it uses the `Ingress` name to construct the route's, so there'd be no conflict. Is this something that could in theory be supported, or was it explicitly not considered? Or am I overlooking something that would prevent it?
adityamandaleeka commented 2 years ago

Transferred from discussions. Thanks @pinkfloydx33 for the suggestion.

dpbevin commented 2 years ago

The Kubernetes Ingress resource doesn't have a concept of "HTTP Method", so AFAIK configuring two resources with the same host and path would be invalid.

I even looked at the newer Kubernetes Gateway API and that has the same limitation relating to HTTP methods.

Are you attempting to route a POST request to one backend and non-POST requests to another? Or are you trying to enforce auth at the ingress controller?

pinkfloydx33 commented 2 years ago

Auth at the ingress controller. In our case YARP is acting as an API gateway and does authorization there.

K8s doesn't have a concept of HTTP method, you are correct. But that doesn't matter. It does support two Ingress resources with the same hosts and path. In what I am proposing, HTTP methods would be codified in the metadata.annotations with all the other YARP route configuration.

In my use case I would create three Ingress resources:

I could likely get this down to two Ingress resources with a bit of thinking. In any case, it's the second and third bullets that are of note. As far as K8S is concerned they'd have the same host, path and ingressClass which is a supported scenario. As different resources they'd have to have different names; the YARP ingress controller would treat them as distinct routes, as it should. Without any annotations/metadata this would be an issue as there would be two YARP routes with the exact same match configuration. If HTTP methods was a supported annotation this would work just fine as the two routes created on the YARP end would have different set of match criteria.

This is a supported scenario with Ingress resources managed by ingress-nginx (via metadata.annotations) as well as with Istio's VirtualService (via spec.http.match.method) and I'm sure others. I know the goal isn't parity, but figured I'd call these cases out.

I'm posting from my cell, but I can provide hypothetical Ingress examples later.

specialforest commented 2 months ago

I believe this can be resolved as done now.