jooby-project / jooby

The modular web framework for Java and Kotlin
https://jooby.io
Apache License 2.0
1.7k stars 199 forks source link

SniHandler support? #3489

Open Luuzzi opened 1 month ago

Luuzzi commented 1 month ago

Hello. First of all, thank you for this amazing framework, it looks incredible!

I would like to ask how to integrate SNI SSL support for multiple domains without having to launch several servers and instead operate on a single instance. I am using Netty. Is there a way to safely integrate into the channel pipeline without rewriting the start method? This feature would be very helpful.

jknack commented 1 month ago

Glad you enjoy it. Look at dynamic routing: https://jooby.io/#router-dynamic-routing

You basically can mount an app base on some condition (like header). There is a shortcut too:

{
   domain("www.domain.com", new FooApp());
}
Luuzzi commented 1 month ago

Glad you enjoy it. Look at dynamic routing: https://jooby.io/#router-dynamic-routing

You basically can mount an app base on some condition (like header). There is a shortcut too:

{
   domain("www.domain.com", new FooApp());
}

Thank you for your response. Yes, I have seen this feature. But I mean entirely different domains (in this case, it is technically impossible), if we have test.com and test.org and they have different SSL certificates. I understand that a redirect can be used, but in my case, it serves as a "fallback," so a regular SslContext won't suffice. Perhaps we can rewrite the current SslOptions abstraction and create something like a condition: if the number of SSL certificates is more than one, then use SniHandler for each domain through DomainWildcardMappingBuilder. I am not sure if such mechanisms exist in frameworks other than Netty, unfortunately, and I don't know how difficult it would be to add support for all network engines. But it seems this "out-of-the-box" feature would be extremely useful.

jknack commented 1 month ago

In 2.x (if I remember correctly) there was a request to support multiple applications on same JVM. That means a single server listening on multiples ports. Probably that could help here too.

agentgt commented 1 month ago

@Luuzzi just out of curiosity why are you not terminating the SSL with a proxy or load balancer? Are you using a TCP load balancer instead of HTTP/s (as I think that is the only way you can load balance terminating SSL by the endpoint)?

EDIT the only time I could see wanting to handle this at the endpoint is:

  1. if you really do not want a load balancer for latency reasons or ease
  2. or the extremely complicated scenario of having SSL certificates handled dynamically.

Number 2 is for multitenancy of customers (or whoever) to upload their SSL certificates (or letscrypt). Number 2 I would imagine is nontrivial to support in Jooby.

agentgt commented 1 month ago

In 2.x (if I remember correctly) there was a request to support multiple applications on same JVM. That means a single server listening on multiples ports. Probably that could help here too.

@jknack I don't think that would work unless they terminate at the load balancer which makes the SniHandler moot. That is if you are not terminating the load balancer it is essentially a pass through (TCP proxy) and thus they can only direct traffic based on other things (like health checks) and not host name (e.g. direct to different ports on same machine). Maybe there are some newer load balancers that can act as TCP proxy and sniff the SNI extension that I'm unaware of.

Otherwise they have to run each domain on its own IP address (assuming they want 443 externally).

That is why I'm curious what @Luuzzi is trying to do here. If they are just trying to have SSL for development purposes of two different domains and not a dynamic amount I would recommend they develop with a load balancer. That is you startup Jooby and the load balancer with your certificates and this is less hard these days with Docker. Load up Nginx and have it loaded with the certificates and direct traffic unencrypted to Jooby.

Luuzzi commented 1 month ago

Otherwise they have to run each domain on its own IP address (assuming they want 443 externally).

@Luuzzi just out of curiosity why are you not terminating the SSL with a proxy or load balancer? Are you using a TCP load balancer instead of HTTP/s (as I think that is the only way you can load balance terminating SSL by the endpoint)?

EDIT the only time I could see wanting to handle this at the endpoint is:

  1. if you really do not want a load balancer for latency reasons or ease
  2. or the extremely complicated scenario of having SSL certificates handled dynamically.

Number 2 is for multitenancy of customers (or whoever) to upload their SSL certificates (or letscrypt). Number 2 I would imagine is nontrivial to support in Jooby.

We do not use load balancers or proxies, they are unnecessary for our tasks. We simply listen on port 443 instead of doing something like 8443 -> 443. And yes, the problem is that we need dynamic SSL configuration. We have many domains with the same routes. Imagine registering FooApp multiple times for different hosts as @jknack described, but they serve different content depending on the host, and the whole process is dynamic, meaning they can expand and be removed.

Overall, I have already developed a solution using your framework by overriding classes. But you might consider this change for the future. I understand that this is a non-trivial task because other network frameworks likely do not have such a simple and convenient SniHandler as Netty.

Regards!

agentgt commented 1 month ago

I understand that this is a non-trivial task because other network frameworks likely do not have such a simple and convenient SniHandler as Netty.

Yes that is correct. Similarly to how Jooby has a facade or abstraction with Context for request/response it would need something similar for the wiring of SNI handling.

Alternatively Server could have something akin to how Spring does it with getNativeObject where you have to cast to the actual implementation. I assume you are doing something like that now? Actually it would be great to see how you are registering the SniHandler with Jooby.

BTW I don't blame you for wanting something like this because I too have had the need (dynamic SSL + host registration) and ended up doing it with custom nginx extensions. I just had to ask the questions because most folks are not in the camp we are in.

It looks like Jetty and Netty are possible but Undertow not as much.

jknack commented 1 month ago

@agentgt seems undertow also support SNI. @Luuzzi want to give a try? PR is welcome

Luuzzi commented 1 month ago

Good day, and sorry for the delayed responses — I’m currently on a short vacation.

Right now, I have a rather crude solution where I simply extend NettyServer and override the start method to replace the NettyPipeline (using SniHandler instead of the usual SslContext). Something like that as I remember

I could try to organize a PR, but I’ll need some time to make it "organic"... Meaning, not breaking backward compatibility and ensuring the solution looks good within the context of SslOptions. I also need to figure out support for Jetty and Undertow (since I haven’t worked with them before).

In short — if we're not in a hurry, I can do it.

jknack commented 1 month ago

no hurry at all. thanks!