Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems running/configure self hosted console application (ASP.net core 2.1, Kestrel) with public certificate on a windows webserver

I have developed various webservices in the past (VB ASP.net web-api applications) with https for production. I have done the development with http and then setup https on the production servers. To setup a port on the production server for https and the certificate, I have:

  1. Imported a public certificate in the certificate store on the windows server configured a specific port for https with netsh. E.g:

netsh http add urlacl url=https://+:22224/ user=everyone

  1. bound the certificate (over the thumbprint) to the port. E.g:

netsh http add sslcert ipport=0.0.0.0:22224 certhash=31cf73308a768100d4d32fe6e77638593e68ab57 appid={a33a711f-c587-44e5-96bc-dca8a7f3fc3c}

  1. Setup the application to listen to the specific port, whereby I have read the url from a config file at startup - e.g. https://IP:Port and applied it to (vb.net) HttpSelfHostConfiguration()

This works without problems and I am able to configure the applications as I need it (e.g. configure a port in the config file for http for doing tests on a intranet server, configure another port in the config file for the production environment with https).

Now, I want to do the same with an asp.net core 2.1.6 application and it seems not to work the same way.
Public certificate (comodo) is installed in the certificate store of the windows web server.
Port 22224 is configured with netsh for https.
The certificate is bound to the port with netsh (certificate is showed correct with netsh http show sslcert ipport=0.0.0.0:22224
In Program.cs, I add the port to listen with UseUrls:

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>() //;
            .UseUrls(GV.cURL, "http://localhost:5000"); 
    }

whereby GV.curl contains https://IP:22224 at runtime

The application run’s fine (over the Internet), if I configure it to a http-port (e.g. http://IP:22222).
If I set the (configured) https port (https://IP:22224), the application don’t start and give out the error message:
Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found.

The information’s, I found on the web are confusing and it seems as this theme is a “moving target” (often changes in the base handling of asp.net core x-x).
My findings for now:
The snipped “No server certificate was specified” in the error message indicates, that the certificate has to be configured in the application?

I have found an example to specify a certificate in CreateWebHostBuilder with .useKestrel options:

.UseKestrel(options =>
        {
            options.Listen(IPAddress.Loopback, 5000);
            options.Listen(IPAddress.Loopback, 5001, listenOptions =>
            {
                listenOptions.UseHttps("certificate.pfx", "topsecret");
            });

Note: In my case, I would have to change 5001 to 22224.

Questions:

  • Do I really have to configure the (already to the port bound) public certificate also in the asp.net core 2.1 application?

  • If yes, what is the best way to do this (is the example above a good way)?

like image 552
FredyWenger Avatar asked Dec 18 '22 19:12

FredyWenger


2 Answers

After a lot of try-and-error, I have found the relevant information that works for me.
Note: I work with ASP.net core 2.1.6 now (if you work with an older version, this may not work for you...

You don’t need to do any configuration with netsh, but you have to configure the cert (including password).
You further not need to change the program.cs...
The configurations can be done completely in appsettings.json (included in the project root)
So... in the project (debugging on my machine), I work with the default appsettings.json (with http):

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

On the intranet server, I use another appsettings.json (still with http):

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
,
    "Kestrel": {
      "EndPoints": {
        "Http1": { "Url": "http://localhost:5000" },
        "Http2": { "Url": "http://172.16.1.120:22222" }
        }
      }
    }

This way, the app can be tested in the LAN over the IP address of the intranet server and also directly on the intranet server (localhost port 5000).

On the internet server, I use another appsettings.json (for localhost with http, for the server IP with https and certficate):

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
,
    "Kestrel": {
        "EndPoints": {
            "Http": {
                "Url": "http://localhost:5000"
            },
            "HttpsInlineCertFile": {
                "Url": "https://192.168.3.3:22224",
                "Certificate": {
                    "Path": "./certificate.pfx",
                    "Password": "NotReally",
                    "AllowInvalid": "true"
                }
            }
        }
    }
}

This way, the app can be tested with http directly on the intranet server and with https and cert over the internet.

Handling:

  • On the servers, I have a root directory for the application.
  • Directly under the root, I have stored copies of the "per machine" different files (including appsettings.json)
  • To publish a new version, I publish on my dev machine and then copy the \publish\ directory to the servers (under the root directory) and overwrite the stored files.
  • To have the correct config, I have created a simple .cmd, that copies the (server specific) config files from the root in the subdirectory \publish\ that I run after a fresh publish...

Notes to https and the certificate:

  • The certificate has to be stored in the \publish\ folder.
  • As the (my) public contoso certificate does secure a few domains, https only works properly, if the app is called over the domain (else, the good knowing “not secure” messages are showed).
  • To be able to test the app with https, I have opened the port 22224 on the windows- and the “real” firewall.
  • The DNS points to the public IP of our internet server.
    For testing, I call the App with https://www.Domain.xx:22224

And... it works...

like image 108
FredyWenger Avatar answered May 13 '23 10:05

FredyWenger


I am using a Dockerized deployment for my ASP.Net Core App v2.2 and have used the following guides to make it work (this should work as of v2.1, Jan. 2017):

  • This Stackoverflow question: Configure ASP.NET Core 2.0 Kestrel for HTTPS

  • This is a useful article which goes through certificate creation, trusting it on different machines and configuring the .Net Project (v2.0).

What I basically did was:

  • Store the certificate (in this example for localhost development) in a certificates folder: enter image description here
  • appsettings.json:
    "Kestrel": {
      "applicationUrl": "https://localhost:5051;http://localhost:5050",
      "Certificates": {
        "Default": {
          "Path": "certificates/localhost.pfx",
          "Password": "MySecret",
          "AllowInvalid": "true"
        }
      }
    }
  • Set the application URLs
    • via launchsettings.json (only local development)
    "kamapp-backend": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5051;http://localhost:5050",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
  • via environment ASPNETCORE_URLS="http://+:5050;https://+:5051", eg. ASPNETCORE_URLS="http://+:5050;https://+:5051" dotnet run

    • You don't have to code any settings, just use the config files.

Forcing HTTPS: app.UseHsts(); in your Startup.cs

It also seems to work without the "AllowInvalid": "true", but I don't understand why yet. Maybe someone can answer.

like image 21
Andrei Avatar answered May 13 '23 12:05

Andrei