Kestrel needs restarted when TLS certificate renewed - ssl-certificate

When our certificate is automatically updated by "Let's Encrypt", it is necessary to restart our web API service to use the new certificate. I have two challenges: (1) how to automatically detect when the certificate is renewed, and (2) how to use the new certificate without requiring a restart of the web API service.
We configure Kestrel to support https in the appsettings.json file. Something similar to:
HttpsInlineCertAndKeyFile": {
"Url": "https://localhost:5002",
"Certificate": {
"Path": "<path to .pem/.crt file>",
"KeyPath": "<path to .key file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
We are developing in c# .net core 6

There is a possibility to reload the certificate without restarting. basically there is a callback mechanism which loads the certificate for each request.
.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(o =>
{
o.ServerCertificateSelector = (context, dnsName) =>
{
return GetCertificateFromPath();
};
});
});
since it calls this GetCertificateFromPath method for each request so you have to cache the certificate somehow inside the GetCertificateFromPath() method and only read when it is changed.
it should be possible with some way by checking modified date or something.

Related

How to test UseHttpsRedirection setting locally in .NET Core

In my ASP.NET Core project, I have turned ON HTTPS Redirection, with this setting in my Program.cs:
app.UseHttpsRedirection();
I have referred to MS doc.
Locally, when I run my Core Web project, it uses https by default (https://localhost:7432/). Now, to test if redirection from http -> https works, I browse to http://localhost:7432/, but I get a "This page isn’t working right now" error.
So, how do I test if this redirection is working locally?
In the Properties/launchSettings.json file, you'll see a property for applicationUrl that looks like this:
"applicationUrl": "https://localhost:7250;http://localhost:5097"
This sets up the app to listen on two different ports: 7250 for HTTPS and 5097 for HTTP. In your specific project, find the HTTP URL and use that to test the HTTPS redirection locally.
As far I know, you can't share the same port for both http and https. Instead, you should define the ports in the appsettings.json or appsettings.Production.json. FYI, I never define such thing in appsettings.json, because that file is typically part of the repository. To me, the best place is in the other file.
In one of those files, you should see (or add whereas not present) something like this:
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://*:5000"
},
"Https": {
"Url": "https://*:5001",
"Certificate": {
"Path": "(your certificate file)",
"Password": "(your certificate password)"
},
}
}
},
"AllowedHosts": "*",
"AllowInvalid": true,
"https_port": 443,
...
Doing so, when you try to call your site as http, it will attempt to switch to the other port, using https.
For sure not the best explaination, but that's what I know about the https redirection.

Bind certificate to a micro service in pod (mTLS)

I am trying to implement the mTLS in cluster across micro service for secured communication. I know that there are service meshes are available for this purpose. But we would like to stay away from service mesh and implement the mTLS in cluster.
So, after going through several posts, then I am able to create the tls secret and mount the volume as part of the service deployment. This certificate i can retrieve from X509Store:
using var certificateStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadOnly);
if (certificateStore.Certificates.Any())
{
var certs = certificateStore.Certificates.Find(X509FindType.FindByIssuerName, issuerName, true);
if (certs.Any())
{
return certs.First();
}
}
return null;
But, now, when i am trying to assign this certificate as part of the
kestrelServerOptions.ConfigureHttpsDefaults(listenOptions =>
{
Log.Information($"Configuring the https defaults.");
if (serverCertificate == null)
{
return;
}
// self signed certificate
Log.Information($"Before : Private key: {serverCertificate?.HasPrivateKey}");
Log.Information($"After : Server certificate: {listenOptions.ServerCertificate?.Issuer}");
listenOptions.ServerCertificate = serverCertificate; // throws exception saying that the serer certificate should have the private key.
....
my secret volume has both .crt(pem) and .key files stored as part of the tls secret. But service is not able to attach this private .key to it.
I am really lost here... and not able to proceed further.
I really appreciate if someone help me to work with this certificate and mTLS.
Thanks in advance.

How to resolve ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY for self hosted signalR?

I'm trying to host a SignalR hub in a .NET Core 3.1 Windows Service, and when my client begins negotiation it fails with the response net::ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY
My SSL certificate is successfully loaded, and it checks out as valid in browser on port 443, but when browsing to my alternate port (randomly selected 12457) the browser does not consider it valid
If I switch down to HTTP1, I get a 405 I suspect from incompatibility with the client (microsoft/angular).
Here's how I'm configuring with my SSL certificate
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls(configuration.GetValue<string>("ListenerEndpoint"));
webBuilder.UseKestrel(options =>
{
options.Listen(IPAddress.Any, 12457, listenOptions =>
{
listenOptions.UseHttps(options =>
{
var certificateStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadOnly);
var certificates = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, "<thumbprint>", true);
var certificate = certificates[0];
options.ServerCertificate = certificate;
});
});
});
});
I've followed the netsh command to expose the cert on this port per: https://weblog.west-wind.com/posts/2013/Sep/23/Hosting-SignalR-under-SSLhttps#:~:text=Even%20if%20your%20self-hosted%20SignalR%20application%20doesn%27t%20explicitly,that%20will%20reject%20mixed%20content%20on%20SSL%20pages. without a positive effect

Having certificate issues when calling Web API from Web App

I am developing a web api and a web app locally. I am having trouble calling the web api from the web app.
When I call it I keep getting the error: "The remote certificate is invalid according to the validation procedure."
Both apps are built with ASP.Net Core and are running on kestrel. The webapp is callable as https://mylibrary.com:5003 and the Web API is callable as https://api.mylibrary.com:5001.
How can I get them working together with valid certificates?
Edit: Come to realise that the issue is that the apps are using localhost certs by default. I want to be able to use my own self signed cert.
If someone can point me to somewhere that explains how to set up two apps to use a self-signed certificate in .net core web projects please do :)
If you need to work around the cert validation using HttpClient, you could do it by creating a HttpClientHandler and passing it to HttpClient as per Rohit Jangid's answer to The SSL connection could not be established
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
// Pass the handler to httpclient(from you are calling api)
HttpClient client = new HttpClient(clientHandler)
Avoid accidentally circumventing certificate validation in production by checking if it is in development environment:
HttpClient httpClient = new HttpClient();
if (env.IsDevelopment())
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, ssl) => { return true; };
httpClient = new HttpClient(clientHandler);
}
Inject information about webhostenvironment by injecting it in the handler/action:
public async Task OnGet([FromServices] IWebHostEnvironment env)
Please try to use RestSharp library to make the webapi request and set the cert validation to true. see here
or you can install the dotnet dev certs by executing dotnet dev-certs https --trust in a command promt or powershell

Kestrel and https very slow

I am using Rider from JetBrains and it made me realize that configuring https directly through Kestrel makes the requests to API very slow. I have the same behaviour if I just run
dotnet MyApi.dll
When I am using Visual Studio and running the API on IIS Express I don't have any performance issues.
This is how I configured Kestrel to listen on https
X509Certificate2 cert = null;
using (var store = new X509Store(StoreName.My))
{
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySubjectName, "localhost", false);
cert = certs[0];
}
WebHost.CreateDefaultBuilder(args).UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, 44317, listenOptions =>
{
listenOptions.UseHttps(cert);
});
})
.UseStartup<Startup>()
.Build();
I tried to remove the https and just use http, and it is working as fast as with IIS Express. So it tells me that there is something wrong with the way I am configuring https.
Is there any configuration I am missing that is making the Kestrel slower when https is activated or is it simply better to run it on IIS Express ?