How to allow HTTPS connections from both localhost

2020-07-23 08:44发布

问题:

I am trying to use Docker for an existing application and I have the following issue. When the API is trying to get the Identity Server metadata from the container, it fails with the following:

web_api          | System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://host.docker.internal:5500/.well-known/openid-configuration'.
web_api          |  ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://host.docker.internal:5500/.well-known/openid-configuration'.
web_api          |  ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
web_api          |  ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. 

This is indeed confirmed by the host browser (certification error in Chrome).

If I access the same metadata using localhost instead of host.docker.internal, it works as expected.

I have used the instructions from here in order to create and trust a localhost certificate that it is also used by the identity server:

dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p { password here }
dotnet dev-certs https --trust

I assume these instructions create the certificate only for localhost, but I am trying to get a solution that also works for host.docker.internal.

Question: How to allow HTTPS connections from both localhost and container towards an ASP.NET Core Web API application?

回答1:

I think you are right - dotnet dev-certs only generates certs for localhost. And as far as I can tell is not configurable. So it seems you will have to generate your own self-signed cert and trust it. Assuming you're on Windows, one way to do it is with Powershell's New-SelfSignedCertificate:

#create a SAN cert for both host.docker.internal and localhost
$cert = New-SelfSignedCertificate -DnsName "host.docker.internal", "localhost" -CertStoreLocation cert:\localmachine\my

#export it for docker container to pick up later
$password = ConvertTo-SecureString -String "123123" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath C:\https\aspnetapp.pfx -Password $password

# trust it on your host machine
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "TrustedPublisher","LocalMachine"
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()

Assuming you use Microsoft-supplied base images for your apps, to hint Kestrel to pick the new cert up you will probably have to run docker like so:

docker pull your_docker_image
docker run --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_Kestrel__Certificates__Default__Password="123123" -e ASPNETCORE_Kestrel__Certificates__Default__Path=\https\aspnetapp.pfx -v %USERPROFILE%\.aspnet\https:C:\https\ your_docker_image

docker run <your image> --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_Kestrel__Certificates__Default__Password="123123" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx

Note I'm exporting the cert to C:\https which then gets mounted onto the container.

You might have to play around with paths and domain names but hopefully that gives you a starting point.

OpenSSL is another possible solution here that would be cross-platform as well

UPD Since Docker machines are often Linux, this answer might not be a complete solution. Check out my other answer on the same topic - that one leverages off OpenSSL to perform the task and goes into how to embed self-signed certs into Docker images on build.