-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Make TLS & QUIC Pay-for-Play (Redux) #47454
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
Conversation
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
I did manage to get the template tests to run locally, but they pass. I'll keep investigating, but I don't expect a substantial product change (i.e. I think it's safe to review). Edit: I don't know what it was doing, but it wasn't running the tests. I debugged in CI and now the tests are green. |
974b528 fixed most tests. The issue was that |
The remaining test failure appears to be induced by my logging code, so I'm ignoring it for now. Edit: It was. Resolved. |
src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs
Outdated
Show resolved
Hide resolved
Force push drops all debugging commits and, hopefully, fixes CI. |
src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Kestrel/src/WebHostBuilderKestrelExtensions.cs
Outdated
Show resolved
Hide resolved
@amcasey, this change will be considered for inclusion in the blog post for the release it'll ship in. Nice work! Please ensure that the original comment in this thread contains a clear explanation of what the change does, why it's important (what problem does it solve?), and, if relevant, include things like code samples and/or performance numbers. This content may not be exactly what goes into the blog post, but it will help the team putting together the announcement. Thanks! |
public void ApplyHttpsConfiguration( | ||
HttpsConnectionAdapterOptions httpsOptions, | ||
EndpointConfig endpoint, | ||
KestrelServerOptions serverOptions, | ||
CertificateConfig? defaultCertificateConfig, | ||
ConfigurationReader configurationReader) | ||
{ | ||
throw new NotImplementedException(); // Not actually required by this impl | ||
} | ||
|
||
public ListenOptions UseHttpsWithSni(ListenOptions listenOptions, HttpsConnectionAdapterOptions httpsOptions, EndpointConfig endpoint) | ||
{ | ||
throw new NotImplementedException(); // Not actually required by this impl | ||
} | ||
|
||
public CertificateAndConfig? LoadDefaultCertificate(ConfigurationReader configurationReader) | ||
{ | ||
throw new NotImplementedException(); // Not actually required by this impl | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I'm missing something. This is saying that these methods aren't called when KestrelServer is newed up manually?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, KestrelServer
and KestrelServerImpl
only pass the IHttpsConfigurationService
to TransportManager
and AddressBinder
, so they don't need the parts of the interface that are exclusively for KestrelConfigurationLoader
.
var HttpsConfigurationService = ApplicationServices.GetRequiredService<IHttpsConfigurationService>(); | ||
|
||
if (!HttpsConfigurationService.IsInitialized) | ||
{ | ||
var hostEnvironment = ApplicationServices.GetRequiredService<IHostEnvironment>(); | ||
var logger = ApplicationServices.GetRequiredService<ILogger<KestrelServer>>(); | ||
var httpsLogger = ApplicationServices.GetRequiredService<ILogger<HttpsConnectionMiddleware>>(); | ||
HttpsConfigurationService.Initialize(hostEnvironment, logger, httpsLogger); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually, there's a single call to some entry point service that resolved dependencies. This feels very manual. Is there a way to avoid these checks to IsInitialized
or does that happen opportunistically in various places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the pattern I came up with for making it possible to light up this functionality either during DI setup or afterwards (esp when calling ListenOptions.UseHttps
). Alternatives welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To elaborate a bit, there's always an IHttpsConfigurationService
, but all of its methods throw unless you either register an HttpsConfigurationService.IInitializer
(as in UseHttpsConfiguration
) or explicitly invoke Initialize
(as here, in service of ListenOptions.UseHttps
). Since UseHttps
is called after the DI container is sealed, there needed to be a different mechanism for enabling the functionality in that code path. (Eric and Stephen both felt strongly that UseHttps
should "just work".)
Looks like I was once again sabotaged by my local dev certs. I'll update the tests. |
Rename "UseKestrelSlim" to "UseKestrelCore"? |
`CreateSlimBuilder` now calls `UseKestrelSlim` (name TBD) to create a Kestrel server that doesn't automatically support TLS or QUIC. If you invoke `ListenOptions.UseHttps`, TLS will "just work" but, if you want to enable https using `ASPNETCORE_URLS`, you'll need to invoke the new `WebHostBuilder.UseHttpsConfiguration` extension method. Quic is enabled using the existing `WebHostBuilder.UseQuic` extension method. Squash: Break direct dependency of AddressBinder on ListenOptionsHttpsExtensions.UseHttps Factor out the part of TransportManager that depends on https Introduce KestrelServerOptions.HasServerCertificateOrSelector for convenience Factor TlsConfigurationLoader out of KestrelConfigurationLoader Introduce but don't consume IHttpsConfigurationHelper Consume IHttpsConfigurationHelper - tests failing Fix most tests Fix KestrelServerTests Fix remaining tests Respect IHttpsConfigurationHelper in ApplyDefaultCertificate Introduce UseKestrelSlim Delete unused TryUseHttps Enable HttpsConfiguration when UseHttps is called Introduce UseHttpsConfiguration Drop incomplete test implementation of IHttpsConfigurationHelper Tidy up test diffs Fix AOT trimming by moving enable call out of ctor Fix some tests Simplify HttpsConfigurationHelper ctor for more convenient testing Improve error message Don't declare Enabler transient Fix tests other than KestrelConfigurationLoaderTests Correct HttpsConfigurationHelper Add IEnabler interface to break direct dependency Restore UseKestrel call in WebHost.ConfigureWebDefaults Stop registering an https address in ApiTemplateTest boolean -> bool HttpsConfigurationHelper -> HttpsConfigurationService HttpsConfigurationService.Enable -> Initialize ITlsConfigurationLoader.ApplyHttpsDefaults -> ApplyHttpsConfiguration ITlsConfigurationLoader.UseHttps -> UseHttpsWithSni IHttpsConfigurationService.UseHttps -> UseHttpsWithDefaults Inline ITlsConfigurationLoader in IHttpsConfigurationService Document IHttpsConfigurationService Document new public APIs in WebHostBuilderKestrelExtensions Clean up TODOs Improve error text recommending UseQuic Co-authored-by: James Newton-King <[email protected]> Add assert message Clarify comment on assert Fix typo in doc comment Co-authored-by: Aditya Mandaleeka <[email protected]> Fix typo in doc comment Co-authored-by: Aditya Mandaleeka <[email protected]> Fix typo in doc comment Co-authored-by: Aditya Mandaleeka <[email protected]> Don't use regions Correct casing Replace record with readonly struct Test AddressBinder exception Test an endpoint address from config Test certificate loading Bonus: use dynamic ports to improve reliability Test Quic with UseKestrelSlim Test the interaction of UseHttps and UseHttpsConfiguration Test different UseHttps overloads Add more detail to doc comment Set TestOverrideDefaultCertificate in the tests that expect it
Force push is a squash and a rebase on |
I played around a bit on a branch - 6e10637 MemberNotNull can definitely be used to remove some bangs. |
Co-authored-by: James Newton-King <[email protected]>
I'll have a look. Edit: I only see
I didn't know about that attribute. Neat. Edit: done.
It was a DI service in #47209, but Stephen asked me not to clutter the service collection. Edit: It's definitely cleaner, but we really need to finally land this. That won't affect the public surface area, so we can refactor in a follow-up PR if there's still appetite.
It is ridiculously easy to regress this. I think @mitchdenny is working on AOT template tests that might provide this coverage? |
You also need the If it's very easy to undo this improvement, we need unit tests. @eerhardt does dotnet/runtime have a way to assert types aren't accidentally being brought in that we could use? Would publishing an app with native AOT and then doing Type.GetType(xxx) work? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Need a way to automate testing this to prevent accidentally regressing the next time we need to change TLS cert logic.
This will be non-trivial. Can happen in a follow-up PR.
Yes, we do that in 2 places (that I know of) in dotnet/runtime: Invariant Globalization: System.Text.Json: Note there is a bit of infrastructure to support this. We have a "TrimmingTests" leg that publishes all these EXE projects for trimming. And then we execute the published executable and ensure the exit code is Note that ASP.NET has a backup system (https://github.com/aspnet/Benchmarks/tree/main/src/BenchmarksApps) which publish fully trimmed apps and measure the output size. We also have a regression bot that logs an issue if those apps increase by more than 2%. |
Based on the feedback on #47209, I've prepared this substantially different approach. Whereas #47209 focuses on providing a describable set of restrictions and guardrails to prevent their violation, this PR focuses on making a best effort to improve trimmed size while breaking as few scenarios as possible.
What's disabled when you create a slim builder? You'll find out at bind-time if you crossed the line and a helpful error message will tell you the one-liner (either
IWebHostBuilder.UseHttpsConfiguration
orIWebHostBuilder.UseQuic
) to add to fix it. What does that mean, in practice? Kestrel won't callUseHttps
on your behalf - in particular, setting your URL tohttps
won't "just work" - and there won't be any QUIC transports.Presently,
IWebHostBuilder.UseQuic
doesn't implyIWebHostBuilder.UseHttpsConfiguration
, but it could if we're willing to slightly clutter the public API (i.e. with a marker service in Connection.Abstractions).There are exactly two new DI services, both internal:
IHttpsConfigurationHelper
is always present, but throws until it is explicitly enabled.IEnabler
is a declarative way to enableIHttpsConfigurationHelper
(vs a method call). I suspect there's a better way to do this in DI, but I'm not familiar enough with the available APIs.There are two new public APIs (plus overloads):
UseKestrelSlim
(name TBD) doesn't callUseQuic
orIHttpsConfigurationHelper.Enable
.UseHttpsConfiguration
(effectively) callsIHttpsConfiguration.Enable
.I have more validation to do, but the trimmed size is as in #47209 and the tests pass.
Fixes #47567
Fixes #46681