reverse-proxy icon indicating copy to clipboard operation
reverse-proxy copied to clipboard

Support port routes

Open saber-wang opened this issue 4 years ago • 9 comments
trafficstars

What should we add or change to make your life better?

Support port routes

Why is this important to you?

Host routing is currently supported, but the host may change due to the pre agent. The only thing you can know is the port currently listening

saber-wang avatar Sep 13 '21 07:09 saber-wang

Can you give some examples of the expected server configuration, request fields, and the YARP configuration you'd like to see?

Tratcher avatar Sep 13 '21 14:09 Tratcher

@Tratcher

  "Kestrel": {
    "Endpoints": {
      "http1": {
        "Url": "http://*:13500",
        "Protocols": "Http1"
      },
      "http2": {
        "Url": "http://*:51001",
        "Protocols": "Http2"
      }
    }
  },
  "ReverseProxy": {
    "Routes": {
      "grpc": {
        "ClusterId": "grpccluster",
        "Match": {
          "Ports": [ 51001 ] or "Port": 51001
        }
      },
      "http": {
        "ClusterId": "httpcluster",
        "Match": {
          "Ports": [13500] or  "Port": 13500
        }
      }
    },
    "Clusters": {
      "grpccluster": {
        "HttpRequest": {
          "Version": "2",
          "VersionPolicy": "RequestVersionExact"
        },
        "Destinations": {
          "50001": {
            "Address": "http://grpccluster:30923"
          }
        }
      },
      "httpcluster": {
        "Destinations": {
          "30913": {
            "Address": "http://httpcluster:30913"
          }
        }
      }
    }
  }

saber-wang avatar Sep 15 '21 04:09 saber-wang

Seems reasonable.

There are a few ways to go about this.

  1. You might be able to approximate this behavior using the Host header, it often contains the port. "Hosts" : [ "*:51001" ],.
  2. This can be implemented in your project today using AspNetCore's routing extensibility just like how YARP added support for header based routing. https://github.com/microsoft/reverse-proxy/blob/1ad89df30ac6d58fcb3e1f3231d81fa6d100bb98/src/ReverseProxy/Routing/HeaderMatcherPolicy.cs. You can add the information in config via route metadata and then add it to routes with ConfigureEndpoints. https://github.com/microsoft/reverse-proxy/blob/1ad89df30ac6d58fcb3e1f3231d81fa6d100bb98/src/ReverseProxy/Routing/ReverseProxyConventionBuilder.cs#L57
  3. It can be implemented in YARP
  4. It can be implemented in AspNetCore

Long term we'd like to move most routing features to AspNetCore. We've added some in YARP to support older framework versions and to experiment.

Tratcher avatar Sep 15 '21 18:09 Tratcher

https://github.com/dotnet/aspnetcore/issues/46057

Tratcher avatar Jan 12 '23 17:01 Tratcher

Being able to match on ports would be really helpful. In my use-case I want to differentiate between a port providing the proxy services and a port for internal purposes like prometheus, health endpoints, management and so on. Using the existing host header based matching, you can still request proxy endpoints from the internal purposes port and the other way around just by messing with the port stated in the Hosts header which is not good. For security reasons I want to be able to cleanly separate what is offered on what port.

@Tratcher with the upstream issue being closed is there still a chance of this happening?

hacst avatar May 05 '23 14:05 hacst

The linked issue said that since the port is part of the host header you can use that:

{
  "ReverseProxy": {
    "Routes": {
      "route1" : {
        "ClusterId": "cluster1",
        "Match": {
          "Hosts" : [ "*:80", "*:8080"],
        },
      }
    },
    // ...
  }
}

Tratcher avatar May 05 '23 16:05 Tratcher

The linked issue said that since the port is part of the host header you can use that:

{
  "ReverseProxy": {
    "Routes": {
      "route1" : {
        "ClusterId": "cluster1",
        "Match": {
          "Hosts" : [ "*:80", "*:8080"],
        },
      }
    },
    // ...
  }
}

But that's the problem. The host header ist whatever the client sets it to. So if I setup Kestrel to listen on 80 and 9000 and I set a host match to only *:9000 for a route in YARP I can still connect to port 80 and just send "whatever:9000" in the Host header and it will match the route for *:9000 and respond.

hacst avatar May 05 '23 16:05 hacst

It's easy enough to make a middleware that validates the host header matches the local port.

Tratcher avatar May 05 '23 17:05 Tratcher

For me I work around this using an endpoint filter checking against localport. I still think there should be a integrated way to do this right because many people will use the "obvious" but unsafe solution.

Proposing host matching for port restrictions in ASP.NET core seems to be a widespread pattern. After stumbling over it again in the Microsoft documentation on health checks today I opened a issue there. Hopefully the documentation can at least be clarified (https://github.com/dotnet/AspNetCore.Docs/issues/29399)

hacst avatar Jun 01 '23 11:06 hacst