Skip to content

Preload default Kestrel config before running Kestrel's configureOptions callback #28120

Open
@halter73

Description

@halter73

This issue is inspired by an email from @wiktork. From the email:

I’m [working] on dotnet-monitor. The tool uses Asp.net Core to host a web server that acts as a control plane for diagnostic tooling. We are currently working on the security work for this tool, in particular supporting https.

I have a scenario where I want to do the following:

  • Bind https://localhost:52323

  • Bind http://localhost:52525

  • Notice one is https, and the other is http.

  • Note the two endpoints serve different information (sensitive data over https, non-sensitive data over http).

  • If there is no default certificate (one generated by dotnet dev-certs) or one specified via Kestrel:Certificates:Default, I would like to successfully bind and listen on the http endpoint, but gracefully fail on the https endpoint.

My initial take on this was to use ConfigureKestrel:

//Simplified code
ConfigureKestrel((context, options) =>
{
        try
        {
               //If https
               options.ListenLocalhost(url.Port, listenOptions => listenOptions.UseHttps() )
        }
        catch (InvalidOperationException e)
        {
            //This binding failure is typically due to missing default certificate
            console.Error.WriteLine($"Unable to bind to {url}. Dotnet-monitor functionality will be limited.");
            console.Error.WriteLine(e.Message);
        }

This allows me to selectively UseHttps on an endpoint, but this doesn’t work because the default certificate has not been loaded yet. From my understanding of the code, that happens post configuration:

  1. All configuration occurs (my UseHttps code always throws, indicating there is no default certificate)
  2. KestrelConfigurationLoader.Load will actually load the default certificate into CertificateManager
  3. Binding/Running server

At this point I could pass along the certificate myself if it’s present to UseHttps, but I don’t really want to replicate all the default certificate logic from asp.net core. Do you guys have any suggestions on how to accomplish this?

The workaround I provided in the email thread was as follows:

It's too bad that UseHttps() doesn't automatically use the default certificate from config. UseHttps() will use the installed development certificate if there's one available. I would love to fix it, but this is the unfortunate side-effect of being able change the config section Kestrel reads from in the ConfigureKestrel callback. Fortunately, since you can load the configuration early yourself inside the ConfigureKestrel callback, the fix should be a one-liner. If you add

options.Configure(context.Configuration.GetSection("Kestrel")).Load();

before

options.ListenLocalhost(url.Port, listenOptions => listenOptions.UseHttps());

does that fix your issue?

While I expect this workaround of manually loading config at the start of the ConfigureKestrel callback works, it's not at all obvious that this should be necessary and is an overall bad experience.

If we instead preload default Kestrel config before running configureKestrel's callback should allow the KestrelServerOptions.Listen() and ListenOptions.UseHttps() methods to pick up "Default"/"Development" certificates and "EndpointDefaults" from config. Since ConfigureWebDefaults is responsible for binding the KestrelConfigurationLoader the the "Kestrel" subsection of config here, this is also where we should do the preloading.

This is a behavioral breaking change, but maybe we can make this less risky by loading just the defaults, and not the endpoints before ConfigureKestrel's callback is run.

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-fewThis issue impacts only small number of customersarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsbugThis issue describes a behavior which is not expected - a bug.feature-kestrelhelp candidateIndicates that the issues may be a good fit for community to help with. Requires work from eng. teamseverity-minorThis label is used by an internal tool

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions