http-rs / tide

Fast and friendly HTTP server framework for async Rust
https://docs.rs/tide
Apache License 2.0
5.06k stars 321 forks source link

Production-grade Reverse Proxy #808

Open Walther opened 3 years ago

Walther commented 3 years ago

The example created in this PR https://github.com/http-rs/tide/pull/784 looks super interesting!

That PR has a comment:

I think before merging anything like this, the example should have a large and clear warning not to use this in production. There is more to a correct reverse proxy implementation than this example, and it should be a standalone crate. This is a security-sensitive feature

What would it take for Tide to have a production-grade reverse proxy feature built in?

I think it would be incredibly valuable to get a good reverse proxy story to Tide. It could become a very serious contender for entirely replacing nginx and apache http server in certain use cases, with configurability & extensibility in Rust. This would be especially suitable in the modern containerized environments, where you do not have long-lived installations that you configure and edit, but rather build containers and replace the deployments. Instead of having to use some configuration DSL, you could just code the logic in Rust directly - with all the great benefits of working with a "real" programming language - and build & deploy the entire application. Imagine having proper tests for your proxy & edge layer logic!

Obligatory disclaimer - if this would feel like something that does not fit the goals of the tide project, feel free to close the issue and direct me elsewhere 😄

But: if this could be something you could see as a project to add to tide, I would love to see this broken down to an actionable plan & tasks, and help contributing 🙇‍♂️ Thank you!

jbr commented 3 years ago

Speaking for myself: I think this would be an excellent addition to the tide ecosystem.

I started in on a fallthrough proxy implementation here that I'd be happy to spin out into a crate of its own. Fallthrough is a slightly different use case, but not hugely so.

The security implications come about when the upstream applications are in a "trusted proxy setting." (express, rails, phoenix, django sort of). In a trusted proxy setting, the app uses some predicate logic like "is the request coming from this specific trusted IP" or if it's on an internal network, a blanket "the reverse proxy is trusted." The reverse proxy then needs to appropriately set the appropriate headers (which might be the forwarded header or the x-forwarded-{proto,for,by} headers, depending on the upstream) so the upstream server knows the originating source and protocol, etc. If as the reverse proxy we get the details of that wrong, we risk allowing the upstream to serve https-only content over http, or incorrectly attributing the peer address of a request, making it easy to put false information into logs

This isn't particularly hard at all. My concern with including it as an example is that it will be copy-pasted into any number of repositories and not be upgradable or fixable. There's no reason end-applications should need to write this logic in their application. There's also no reason tide itself needs to bundle this code, in my opinion. This would be a great third party crate, or external crate hosted by http-rs if the http-rs team wants to own and maintain more code.

I personally also think that http 1.0 is an essential feature for tide to exist on the public internet. We can do tls termination, but we can't do http 1.0, so currently the primary reason to use nginx is for it to proxy http/1.0 into http/1.1 for async-h1 and tide to understand it.

I've committed initial support for http 1.0 to async-h1, but there are remaining details about how tide servers are configured that have yet to be determined. cc @yoshuawuyts, who owns those decisions. In specific, tide applications that serve http 1.0 need to be configured with a "default host"