I’m trying to configure HTTPS for kestrel using certificate from certificate store. Here’s what I’ve achieved so far:
appsettings.json
{
"SSLCertificate": {
"Serial": "serialNumberFromCertificateStore"
},
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "https://*:8090",
"Protocols": "Http1"
},
"gRPC": {
"Url": "https://*:8091",
"Protocols": "Http2"
}
}
}
}
Program.cs
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
});
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
var kestrelSection = context.Configuration.GetSection("Kestrel");
var certSerial = context.Configuration.GetSection("SSLCertificate").GetValue<string>("Serial");
if (!string.IsNullOrEmpty(certSerial))
{
// Retrieve the certificate from the Windows certificate store
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates.Where(f => f.SerialNumber.ToUpper().Equals(certSerial.ToUpper())).FirstOrDefault();
if (certificate != null)
{
serverOptions.Configure(kestrelSection);
// Configure HTTPS endpoint with the retrieved certificate
serverOptions.ListenAnyIP(8090, listenOptions =>
{
listenOptions.UseHttps(certificate);
});
}
}
});
I read certificate serial number from appsettings.json and apply it in UseHttps method after retrieving certificate. The issue is that it tries to start listening to port 8090 twice. If I change the port, it listens to that port and recognizes certificate, but fails to respond with anything.
What am I supposed to do here?
2
Answers
I managed to figure out the solution for myself.
I had to replace
With
It is important to note that this solutions requires administrator permissions.
You can and probably should manage most of this via the appsettings.json file automatically. There are detailed instructions in the kestrel docs.
The most important point I would recommend is not to use the serial number in the settings. This will expire at some point and most automated processes for certificate renewal will not automatically change this setting.
Instead reference the "Subject" of the certificate which will not change from one certificate renewal to the next.
Something like this:
This should work without having to write any additional code to get the certificate from the store as all the values are already set in the configuration. It will throw exceptions if it can’t find the appropriate certificates, and if you are using self-signed certificates (like the default localhost asp.net dev cert in appsettings.Development.json) then adding
"AllowInvalid": true
to theCertificate
setting may be required.