-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hot reloading tls certificates #2363
Comments
Not sure if this is a second ticket worthy but it would be nice to perhaps provide support for this via a callback which can allow for returning different values based on the incoming domain |
Agreed. I think the ideal interface here is one where both Rocket can provide some default functionality (like updating the TLS certs if they change on disk) but applications can plug in their own dynamic TLS functionality at will as well. I don't have a concrete proposal for an api just yet, but I'm more than in favor of this change. Perhaps this can be part of #1070? |
Sure, ideally as long as it's not all managed or all user driven (ie it would be nice to say here's my tls function without having to manage every aspect of the connection manually) |
I don't think that interface would be a problem. The custom listener could simply forward the majority of the implementation to an existing listener. |
Can I work on this? |
Yes! I'll post a quick guide on how to do so in the next day or so. In the meantime, it would be ideal for you to familiarize yourself with the |
Here's a guide on how to work on this issue. If you decide to work on this, please let me know. I'll assign the issue. Getting FamiliarThe first step, as always, is to get familiar with the relevant code.
You should read through the Using Dynamic Certificate Resolution
Suggested Approach
BonusIf you're feeling adventurous, it would be amazing to add tests that truly exercise the TLS listener. This would mean bringing in an HTTP client library, starting up a real server, and making real requests to that server. This would be easier if we could set custom listeners, since then we wouldn't need to open a TCP connection, but we don't have that yet. |
@SergioBenitez I will work on the weekend As during the weekdays I am busy with C++ |
@SergioBenitez Is there still a need for adding tls tests in /core/lib/tests? (I see there are some tests in the ./examples/tls project |
This commit introduces the ability to dynamically select a TLS configuration based on the client's TLS hello. Added `Authority::set_port()`. Various `Config` structures for listeners removed. `UdsListener` is now `UnixListener`. `Bindable` removed in favor of new `Bind`. `Connection` requires `AsyncRead + AsyncWrite` again The `Debug` impl for `Endpoint` displays the underlying address in plaintext. `Listener` must be `Sized`. `tls` listener moved to `tls::TlsListener` The preview `quic` listener no longer implements `Listener`. All built-in listeners now implement `Bind<&Rocket>`. Clarified docs for `mtls::Certificate` guard. No reexporitng rustls from `tls`. Added `TlsConfig::server_config()`. Added some future helpers: `race()` and `race_io()`. Fix an issue where the logger wouldn't respect a configuration during error printing. Added Rocket::launch_with(), launch_on(), bind_launch(). Added a default client.pem to the TLS example. Revamped the testbench. Added tests for TLS resolvers, MTLS, listener failure output. TODO: clippy. TODO: UDS testing. Resolves #2730. Resolves #2363. Closes #2748. Closes #2683. Closes #2577.
This commit introduces the ability to dynamically select a TLS configuration based on the client's TLS hello. Added `Authority::set_port()`. Various `Config` structures for listeners removed. `UdsListener` is now `UnixListener`. `Bindable` removed in favor of new `Bind`. `Connection` requires `AsyncRead + AsyncWrite` again The `Debug` impl for `Endpoint` displays the underlying address in plaintext. `Listener` must be `Sized`. `tls` listener moved to `tls::TlsListener` The preview `quic` listener no longer implements `Listener`. All built-in listeners now implement `Bind<&Rocket>`. Clarified docs for `mtls::Certificate` guard. No reexporitng rustls from `tls`. Added `TlsConfig::server_config()`. Added some future helpers: `race()` and `race_io()`. Fix an issue where the logger wouldn't respect a configuration during error printing. Added Rocket::launch_with(), launch_on(), bind_launch(). Added a default client.pem to the TLS example. Revamped the testbench. Added tests for TLS resolvers, MTLS, listener failure output. TODO: clippy. TODO: UDS testing. Resolves #2730. Resolves #2363. Closes #2748. Closes #2683. Closes #2577.
This commit introduces the ability to dynamically select a TLS configuration based on the client's TLS hello. Added `Authority::set_port()`. Various `Config` structures for listeners removed. `UdsListener` is now `UnixListener`. `Bindable` removed in favor of new `Bind`. `Connection` requires `AsyncRead + AsyncWrite` again The `Debug` impl for `Endpoint` displays the underlying address in plaintext. `Listener` must be `Sized`. `tls` listener moved to `tls::TlsListener` The preview `quic` listener no longer implements `Listener`. All built-in listeners now implement `Bind<&Rocket>`. Clarified docs for `mtls::Certificate` guard. No reexporitng rustls from `tls`. Added `TlsConfig::server_config()`. Added some future helpers: `race()` and `race_io()`. Fix an issue where the logger wouldn't respect a configuration during error printing. Added Rocket::launch_with(), launch_on(), bind_launch(). Added a default client.pem to the TLS example. Revamped the testbench. Added tests for TLS resolvers, MTLS, listener failure output. TODO: clippy. TODO: UDS testing. Resolves #2730. Resolves #2363. Closes #2748. Closes #2683. Closes #2577.
👋 thanks for getting this in! Question wrt to configuring an app for TLS: TLS resolution happens via a Resolver, which does the user provided TLS lookup on request handshake. However, this requires that the app is configured for TLS, which (afaik) must be prefilled when starting the app up. This creates a bit of an awkward design, as Resolver::init() must supply a (I assume) valid configuration, and then again during resolve(), particularly when trying to serve certs for multiple domains |
No, this part isn't correct. struct MyResolver(Option<Arc<ServerConfig>>);
#[rocket::async_trait]
impl Resolver for MyResolver {
async fn init(rocket: &Rocket<Build>) -> tls::Result<Self> {
Ok(MyResolver(None))
}
async fn resolve(&self, hello: ClientHello<'_>) -> Option<Arc<ServerConfig>> {
self.0.clone()
}
} Assuming something replaces the |
The issue I am seeing is starting up the HTTPS redirector based on the example from this repo:
and this while fielding requests |
Okay, I think I understand now. As it stands, TLS is only enabled if you provide a valid TLS configuration. That includes certificates/keys which are used as the fallback if there is no resolver or the resolver returns It sounds like you want to use TLS without what is currently considered to be a complete TLS configuration opting instead to only have a resolver. Is that right? |
Ideally yeah |
How should we handle the case where a Resolver returns None? Currently, we fall back to some static certificate & keys configured on startup. I don't think we should change the resolver trait to return a certificate (rather than an option). There are valid reasons why a cert resolver wouldn't be able to return a valid certificate, trivially, if no such certificate exists. We could make the static certificate optional, however, we would likely need to refuse any connection that doesn't return a certificate. Is this reasonable? We can't return a graceful error, our only options are a 'connection refused' or 'tls error'. That being said, it's quite reasonable to assume that a single running Rocket instance will outlive any certificate it was initially configured with, in which case we cannot have a valid static certificate configured when the instance started. I think the best option would be to continue requiring users to supply a default certificate. We could add a note in the documentation that it is only used if the resolver does not return a certificate. In this case, it might not be a bad idea to suggest that using an expired certificate is not an issue. (It means cert resolver failures are reported as tls certificate expired). |
I would be fine with returning a TLS error/refused if there were no certificates returned. It would also be ok to provide (optional) fallbacks if one is fine w/ expired certs. |
I believe |
I'll reopen this while we investigate the feasibility of resolver-only configs. |
After some tinkering, it looks like rustls refuses the connection. Firefox reports As far as I can tell, this is the same error as rejecting an mtls connection because we choose not to accept the client's certificate (At least on the client side). Obviously, the server logs explain exactly why the connection was refused. I'm not sure what the correct option is here. I'd like to allow Resolver-only configs, especially since I don't think we can rely on a default cert to remain valid for the entire lifetime of the server. Right now, I see two options for behavior if we don't have a valid certificate: either we follow rustls's example, or we reset the tcp connection. Right now, I'm leaning towards the rustls behavior, since it makes it clear to the client that the issue is related to TLS certificates. No matter what we choose, the client side of this is not pretty. We have very limited options in how we can respond without a valid certificate, so it might just be a case of picking an option, and logging an error that actually explains the issue. |
Is your feature request motivated by a concrete problem? Please describe.
I am not sure if this feature already exists, but most SSL certs have an expiration and it would be nice to have the web server able to reload the certs (either automatically from the file specified, or manually by my own code)
Why this feature can't or shouldn't live outside of Rocket
Rocket implements TLS
Ideal Solution
Rocket provides a way to supply tls after launch, or supports hot reloading
The text was updated successfully, but these errors were encountered: