Using SSL to secure incoming and outgoing traffic from your server is always recommended. When you are developing locally or testing on a server, whether it is Windows or Macintosh or some distribution of Linux like CentOS, fedora, Ubuntu etc, its easy to put the certificate in one of the local directories and then ask server to use the same. However this becomes a little bit different if you are using Containers. Since Docker is the most popular container technology, it has become almost synonymous with containers. When using containers, you can many choices:
1) Map a local volume containing certificate files to the container and then refer to it from inside container
2) Copy certificate directly inside Container during image build process and then refer to it
3) Use third party servers like Nginx or load balancer to do SSL offload. Those third party servers may themselves be containerized.
In this blog post, we’ll learn steps to use SSL certificates by .NET Core inside a Docker Container. We’ll be using .NET Core’s inbuilt server Kestrel for this purpose. Kestrel is a cross-platform web server for ASP.NET Core. More details on it can be found here.
Generating Self Signed Certificate
Since getting certificates from well known Certificate Authority’s require to undergo a certain process, we’ll be using self signed certificates for this post’s purpose. However, once you have generated the self signed certificate or using the certificate issued from an internal / external Certificate Authority, the process remains the same.
Generating Self Signed Certificate for Linux based Images
It is to be noted that Kestrel server requires the certificate to be in the PFX format. It does not recognize the certificate presented in the PEM or DER format.
First, we need to generate the CSR and a key pair. For this, we can use below openssl command:
openssl req \
-newkey rsa:2048 \
-keyout my_web_domain.key \
where my_web_domain is the name of the domain reserved for my application. The -newkey rsa:2048 option specifies that the key should be 2048-bit, generated using the RSA algorithm. The -nodes option specifies that the private key should not be encrypted with a pass phrase.
Once above command is input, OpenSSL will prompt few basic questions to fill the Organization specific information. You’ll need to provide the same for it to get completed.
If for some reason, this process seems too cumbersome, you can utilize the online OpenSSL CSR tool provided by DigiCert at this link. It will generate the OpenSSL command which you can run on a Linux OS to generate key and CSR.
Now we need to generate certificate using above key and CSR, which can be done by using below command:
openssl x509 \
-signkey my_web_domain.key \
-in my_web_domain.csr \
-days 365 \
Here, the -days 365 option specifies that the certificate will be valid for 365 days.
Once certificate is generated, it can be converted to PFX format using the below OpenSSL command:
openssl pkcs12 \
-inkey my_web_domain.key \
-in my_web_domain.crt \
It will ask for a password to export the certificate in PFX format. Provide the same and also note it down as we’ll need it for future use.
Generating Self Signed Certificate for Windows based Images
We can use the PowerShell commands to generate Self Signed Certificates for the Windows based .NET Core images. For this, we need to open a PowerShell prompt and then run the below commands:
|# Generates Certificate and import it to Current user's certificate Store|
|$certificate = New-SelfSignedCertificate `|
|–DnsName my_web_domain `|
|–KeyAlgorithm RSA `|
|–KeyLength 2048 `|
|–NotBefore (Get-Date) `|
|–NotAfter (Get-Date).AddYears(1) `|
|–CertStoreLocation "cert:CurrentUser\My" `|
|–FriendlyName "Localhost Certificate for .NET Core" `|
|–HashAlgorithm SHA256 `|
|–KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `|
|$certificatePath = 'Cert:\CurrentUser\My\' + ($certificate.ThumbPrint)|
|# Create temporary certificate path|
|$tmpPath = "C:\Certs"|
|New-Item –ItemType Directory –Force –Path $tmpPath|
|# Set certificate password here|
|$pfxPassword = ConvertTo-SecureString –String "YourSecurePassword" –Force –AsPlainText|
|$pfxFilePath = "C:\Certs\my_web_domain.pfx"|
|$cerFilePath = "C:\Certs\my_web_domain.cer"|
|# Create pfx certificate|
|Export-PfxCertificate –Cert $certificatePath –FilePath $pfxFilePath –Password $pfxPassword|
|Export-Certificate –Cert $certificatePath –FilePath $cerFilePath|
Here, -Subject and -DNS specifies the name of the web_domain for your web application, -KeyAlgorithm specifies the algorithm to be used, -KeyLength specifies the key length, -NotAfter specified duration for which certificate is valid. The certificate is finally exported to the path mentioned in the $pfxFilePath and password is mentioned in the -String “YourSecurePassword” part.
Other variations of this command can be found here. That should suffice to meet most of your needs.
Use Container with SSL Certificate
As discussed above, there are essentially two ways for container to work with SSL certificate:
1) Keep SSL at local directories and then map the volume containing the certificate inside the container.
2) Import certificate inside the container during image build process.
We’ll discuss these approaches one by one.
Map local volume containing SSL Certificate with container
This is easy, since we have gone through hard part of creating SSL certificate. We can utilize the -v switch while running docker run command to map the local directory with container. It can also be mentioned as part of the Docker Swarm or Kubernetes configuration.
Below is one of the samples for docker run command:
dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p crypticpassword dotnet dev-certs https --trust docker pull microsoft/dotnet-samples:aspnetapp 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="crypticpassword" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx -v %USERPROFILE%\.aspnet\https:/https/ microsoft/dotnet-samples:aspnetapp
Import Certificate inside build as part of image build process
For this, we can use well-known COPY command inside dockerfile. Below is one of the samples for same:
|COPY –from=build /app .|
|COPY my_web_domain.pfx .|
Maps Kestrel with Certificate
Perhaps, the most important part is how to use it with Kestrel web server. For this, we need to set below three environment variables:
ASPNETCORE_URLS – Specifies port to be used by Kestrel to listen for HTTP and HTTPS Configuration
ASPNETCORE_Kestrel__Certificates__Default__Password – Specifies the password to decrypt the certificate
ASPNETCORE_Kestrel__Certificates__Default__Path – Specifies the certificate path within container
Below example lists how to mention same as part of the Dockerfile:
For docker compose, they can be mentioned like:
It is not necessary that you need to mention your secure password directly as part of the environmental variables. It can also be mentioned as part of the source code like:
Once everything is setup properly, you can start docker container, hit the web request and check logs. It should be something like below:
If you happen to have an ASPNET Core web app, you can browse it fine although the browser is most likely to display an certificate invalid for self-signed certificates: