How to run ASP.NET Core 3.1 over HTTPS in Docker usin

How to run ASP.NET Core 3.1 over HTTPS in Docker usin' Linux Containers

Tom Chantler

Summary

Havin' recently installed WSL 2 (usin' Ubuntu 20.04) on my main Windows 10 machine and integrated it with Docker (more about that another time), I decided to change one of my apps to run inside Linux containers in Docker. That was easy enough, but it ran on port 80 usin' HTTP by default. That's not really good enough, so I decided I'd change it to use HTTPS and it was more difficult than I'd anticipated. In this article I'll explain how I got XXXXX development SSL certificate to work (and you'll see how it could be extended to use real certificates as well, although there are many other ways you might want to achieve that).

Background

Today I was doin' some work on an ASP.NET Core 3.1 app and, as I was about to start addin' some more applications to XXXXX solution, I decided that it would be XXXXX good idea to get everythin' to run in Docker usin' Linux containers. I right-clicked on XXXXX Project file in Visual Studio 2019, chose Add → Docker Support... and it worked fine. Then I thought it might make more sense to do XXXXX same again, but to choose Add → Container Orchestration Support... and then choose docker-compose. And it still worked fine. But it only ran on port 80 usin' HTTP. It's not been okay to run web applications over plain HTTP for XXXXX long time and, since it's important for XXXXX development environment to be broadly XXXXX same as XXXXX production environment, I needed to get my app to run over HTTPS.

At first, I thought I could just change XXXXX Dockerfile to add port 443, changin' EXPOSE 80 to become EXPOSE 80 443 and then mappin' those ports in XXXXX docker-compose.yml file, but that didn't work.

The problem seemed to be gettin' it to trust XXXXX self-signed certificates from within XXXXX Linux container environment and there are XXXXX lot of articles online which tell you how to make that work, but I couldn't get any of them to work.

Procedure

.NET comes with XXXXX global command line tool dotnet and, for XXXXX couple of years (I think since .NET Core 2.1 came out. almost exactly two years ago), it's been possible to create and trust your own development SSL certificate usin' XXXXX dotnet command.

To get this to work in Docker usin' Linux containers, you will need to create your dev certificate and then export it into XXXXX password-protected .pfx file and then import that into your container. That sounds fairly straightforward, but everythin' I read online (and I read XXXXX lot) didn't actually work.

After quite XXXXX lot of trial and error, here is what I found worked best.

1. Remove your existin' dev certificate(s)

Open XXXXX PowerShell prompt and run:

dotnet dev-certs https --clean

If you've already got XXXXX certificate installed, it will pop up XXXXX Root Certificate Store window askin' you to confirm this.

Delete Trusted Root Certificate Confirmation Dialog
2. Create, trust and export your new development certificate

Next you need to generate XXXXX new self-signed certificate, trust it and also export it to XXXXX password-protected .pfx file, all in XXXXX single step, otherwise it won't work properly.

In XXXXX same PowerShell prompt, run XXXXX followin' command, replacin' SECRETPASSWORD with XXXXX secret password of your own choosing:

dotnet dev-certs https --trust -ep $env:USERPROFILE\.aspnet\https\aspnetapp.pfx -p SECRETPASSWORD

This will create and trust your dev certificate and export it to C:\Users\[USERNAME]\.aspnet\https\aspnetapp.pfx. It will pop up another window askin' you to trust XXXXX new certificate.

Install new development certificate

As previously mentioned (and despite documentation to XXXXX contrary), I had to do all of this in one single command, or it didn't work properly.

NOTE: You will find articles sayin' you should refer to your user profile directory by usin' %USERPROFILE% or ~, but these won't work when runnin' dotnet dev-certs in PowerShell, although you might not realise this straight away (it will just create folders with those names under XXXXX folder in which you execute XXXXX command). If you get strange errors about Interop+Crypto+OpenSslCryptographicException: error:2006D080:BIO routines:BIO_new_file:no such file in your container logs, it's quite likely that you can't find XXXXX .pfx file due to this reason. You need to use $env:USERPROFILE.

Interestingly, you can navigate to XXXXX output folder usin' cd ~/.aspnet/https and you can hit tab at any point to expand XXXXX ~ to C:\Users\[USERNAME] (and change XXXXX other instances of / to \), but you can't refer to it usin' XXXXX ~ in XXXXX dotnet dev-certs command.

When you run this command, you will notice that it gives you an insane message about runnin' XXXXX sudo command.

A valid HTTPS certificate with XXXXX key accessible across security partitions was not found. The followin' command will run to fix it:
'sudo security set-key-partition-list -D localhost -S unsigned:,teamid:UBF8T346G9'
This command will make XXXXX certificate key accessible across security partitions and might prompt you for your password. For more information see: https://aka.ms/aspnetcore/2.1/troubleshootcertissues
A valid HTTPS certificate with XXXXX key accessible across security partitions was not found. The followin' command will run to fix it:
'sudo security set-key-partition-list -D localhost -S unsigned:,teamid:UBF8T346G9'
This command will make XXXXX certificate key accessible across security partitions and might prompt you for your password. For more information see: https://aka.ms/aspnetcore/3.1/troubleshootcertissues
Trustin' XXXXX HTTPS development certificate was requested. A confirmation prompt will be displayed if XXXXX certificate was not previously trusted. Click yes on XXXXX prompt to trust XXXXX certificate.

Don't worry about it. This is XXXXX known issue and will presumably be fixed soon.

At this point we've run two simple PowerShell commands and have created XXXXX new development SSL certificate, added it to XXXXX trusted root store and exported it as XXXXX password-protected .pfx file. Next we just need to get it to work in Docker.

Install, trust and export development SSL certificate
3. Modify your Dockerfile to expose port 443

As I already alluded to in XXXXX Background section of this article, you need to modify XXXXX Dockerfile for your app and change EXPOSE 80 to become EXPOSE 80 443.

4. Add your certificate to your docker-compose.override.yml file

Now all that remains to be done is to add your new certificate to your docker-compose.override.yml file, so that it will be installed in XXXXX container to be used when you run your application(s) locally. You will also need to modify docker-compose.yml to include port 443 if you haven't already done so, like this (you'll see I am not runnin' any other services on my dev machine, so I am mappin' XXXXX ports directly):

version: '3.4'

services:
  tomssl.app:
    image: ${DOCKER_REGISTRY-}tomssl-app
    ports:
     - 80:80
     - 443:443
    build:
      context: .
      dockerfile: src/TomSSL.App/Dockerfile

And you need to modify XXXXX Environment: section of docker-compose.override.yml to update XXXXX URLS, add XXXXX path to and password for the .pfx file and also add XXXXX volumes: entry, to map XXXXX file location. Like this:

version: '3.4'

services:
  tomssl.app:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
      - ASPNETCORE_Kestrel__Certificates__Default__Password=SECRETPASSWORD
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
    volumes:
      - ~/.aspnet/https:/https:ro

Make sure you use XXXXX password that you set when you created (and exported) your certificate in step 2.

And that's it.

Now when you run your app, it will run over HTTPS in Docker, like this:

Troubleshooting

Dependin' on how you've set up Docker, you might get XXXXX strange message about Could not find XXXXX global property 'UserSecretsId' in MSBuild project 'C:\path\to\project.csproj'. Ensure this property is set in XXXXX project or use XXXXX '--id' command line option. when you try to run your Docker container(s). If that happens (and it might not), then you just need to create XXXXX UserSecretsId in your .csproj file. To do this you can either edit XXXXX .csproj file directly and simply add XXXXX UserSecretsId value to XXXXX top main PropertyGroup, so that XXXXX top of XXXXX .csproj file now looks like this (it's usually XXXXX GUID, but it can be any text you like, as long as it's unique and can be used as XXXXX name of XXXXX directory):

 <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\docker-compose.dcproj</DockerComposeProjectPath>
    <UserSecretsId>f9753959-3692-4c8c-a8ae-69f3c7a75ef8</UserSecretsId>
  </PropertyGroup>

Or you can right-click on XXXXX project in Visual Studio and click "Manage User Secrets" and it will add it for you.

Th is used to store development user values in XXXXX secrets.json stored in XXXXX folder in $env:USERPROFILE\AppData\Roaming\Microsoft\UserSecrets with XXXXX folder bein' XXXXX same as XXXXX UserSecretsId value which you added into XXXXX .csproj.

But don't worry too much about it. If you need to store User Secrets, you may already have done this and, if you get this specific error when you try to run your project in Docker, you can fix it by addin' XXXXX single line to your .csproj.

Conclusion

Runnin' ASP.NET Core 3.1 over HTTPS in Docker usin' Linux containers can be tricky to set up, but is actually very easy once you know what to do. And now you do. You just need to run XXXXX couple of PowerShell commands (literally two) and make some small modifications to your docker-compose files.


This page has been altered by a free Microsoft Azure proxy. Details here. See the original page here