3

I have a .net core API project with the following dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:5.0.0-buster-slim AS base
WORKDIR /app
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["API/API.csproj", ""]
RUN dotnet restore "./API.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "API/API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "API/API.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "API.dll"]

I have successfully pushed this image to the Google Cloud Artifact Registry and have created a Google Cloud Compute Engine instance with it. I have set it up with https only and am failing to call it. Postman says Error: connect ECONNREFUSED XX.XXX.XXX.X:443. If I switch from https to http only I can reach the instance and it works as expected but is of course not as secure so I don't want to stick with it. It's set up with a static IP so that I can point my subdomain to it. What am I missing?

James Anderbard
  • 374
  • 2
  • 6
  • 20

2 Answers2

2

Your problem may be related to your container HTTPS configuration.

Please, consider review the documentation provided by Microsoft when describing how to develop ASP.NET Core Applications with Docker over HTTPS and Hosting ASP.NET Core images with Docker Compose over HTTPS. This related question could be of help as well.

Basically, you need to provide different environment configuration properties that define, respectivelly, the URLs valid for your application, the HTTPS listen port, the path to the SSL certificate to use, and the password that protects that certificate:

ASPNETCORE_URLS="https://+;http://+"
ASPNETCORE_HTTPS_PORT=8001
ASPNETCORE_Kestrel__Certificates__Default__Password="password"
ASPNETCORE_Kestrel__Certificates__Default__Path=\https\aspnetapp.pfx

As indicated in the GCP documentation, you could provide this environment information using the GCP Web Console or the gcloud CLI, in the later case using either the --container-env or the --container-env-file flags.

As indicated in the aforementioned SO question, I think you could take advantage of the multi stage Docker build process to pass this environment information as well.

Due to the fact that the containers deployed in Compute Engine share the host network, please, be sure that you have configured the necessary firewall rules to allow access to your container ports.

In order to access your certificate from your container I think you probably have two options.

On one hand, you can include the certificate in your image as part of the build process. It has the obvious drawback that it will make the certificate more accessible, it is a less secure solution, although it can be mitigated if you deploy your image to a non public repository; in addition, take into account that you still need the password for the pfx, so, with caution, it could be a valid solution.

In addition, as described in the GCP documentation, you can mount a host directory and make it accessible as a volume to your container, and store the certificate in that directory. In certain images, in order to automate the distribution progress, you can use the --metadata flag and the startup-script key for instance to provide the necessary information about how to access the certificate. But... where to obtain the certificate in first place? Ideally it may be stored in Google KMS in an encrypted form or perhaps within Google Secrets. This approach is suggested for instance in this article, although I personally have never tried it.

Having said that, in my opinion, instead of trying to customize your container, a better solution will be to configure a HTTPS load balancer in front of your VMs: in addition to high availability and scalability, ease of maintenance, etcetera, regarding the HTTPS configuration, you only need to provide your certificate details when configuring your load balancer frontend; you can request a Google managed certificate as well if necessary.

Please, be aware that if you follow this second option, you do not longer need to configure HTTPS in your application itself, it can safely run on port 80. The idea is to delegate HTTPS handling to the load balancer and use the load balancer frontend to provide SSL termination, freeing your application from that responsibility.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • How do I include the SSL certificate in the container? – James Anderbard Oct 31 '21 at 05:37
  • Thank you very much for the feedback @JamesAnderbard. Yes, of course, sorry. I think you probably have two options. On one hand, of course, you can include the certificate in your image: it has the obvious drawback that it will make the certificate more accessible but if you deploy your image from a non public image repository and taking into account that you still need the password for the pfx it could be a valid solution. See next comment. – jccampanero Oct 31 '21 at 16:47
  • In addition, as described in the [GCP documentation](https://cloud.google.com/compute/docs/containers/configuring-options-to-run-containers#mounting_a_host_directory_as_a_data_volume), you can mount a host directory and make it accessible as a volume to your container, and store the certificate in that directory. In certain images, in order to automate the distribution progress, you can use the [`--metadata` flag](https://cloud.google.com/sdk/gcloud/reference/compute/instances/create-with-container#--metadata) and the `startup-script` key for instance to provide the necessary information... – jccampanero Oct 31 '21 at 16:52
  • ...about how to access the certificate. Ideally it may be stored in Google KMS in an encrypted form or within Google Secrets. This approach is suggested for instance [in this article](https://medium.com/@sachin.d.shinde/secrets-management-in-container-optimized-os-3341d5a2ee79), although I personally have never tried it. – jccampanero Oct 31 '21 at 16:55
  • @JamesAnderbard Having said that, in my opinion a better solution will be to configure an [HTTPS load balancer](https://cloud.google.com/iap/docs/load-balancer-howto) in front of your VMs: in addition to high availability, etc, if required, regarding the HTTPS configuration only is necessary to provide your certificate details when configuring your load balancer frontend; you can request a Google managed certificate as well. – jccampanero Oct 31 '21 at 17:20
  • I have set the environment variables: ASPNETCORE_URLS="https://+;http://+" ASPNETCORE_HTTPS_PORT=443 and have set up a load balancer ahead of the VMs and am now getting this error: Error: write EPROTO 140566936757448:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE – James Anderbard Nov 01 '21 at 02:03
  • Hi @JamesAnderbard. Sorry for the late reply and thank you for the feedback. Probably the problem has to do with the app configuration. You do not longer need to configure HTTPS in your application itself, it can safely run on port 80. The idea is to delegate HTTPS handling to the load balancer and use the load balancer frontend to provide SSL termination, freeing your application of that responsibility. The load balancer can communicate with the backend running on port 80. I think the problem can be related with that. James, please, if you use the load balancer approach, be aware of the ... – jccampanero Nov 01 '21 at 11:03
  • additional costs associated with the project. – jccampanero Nov 01 '21 at 11:08
  • Setting it up for the FE of the load balancer to handle https and the backend to be http is now working. I had to additionally fix an issue with the certificate which was causing issues. I fixed it by pointing my subdomain to the LB so that the certificate could be properly provisioned – James Anderbard Nov 01 '21 at 20:39
  • That is great @JamesAnderbard, I am happy to hear that the solution based in the load balancer is almost working properly: I understand that it is not a true answer to your problem, probably more related to the configuration of the .net core container, but as I told you, I think the LB based solution is better in terms of maintenance, configuration, services and scalability, etc. Please, do not hesitate to contact me if you think I can be of help. – jccampanero Nov 01 '21 at 22:44
  • @JamesAnderbard I summarized the different comments in the question to make the information more accessible. – jccampanero Nov 02 '21 at 11:26
  • @JamesAnderbard Were you able to finally successfully run your service over HTTPS? – jccampanero Nov 03 '21 at 23:13
  • Yes. I was able to finally get it working after setting up a load balancer – James Anderbard Nov 11 '21 at 01:51
  • I am very happy to hear that @JamesAnderbard. – jccampanero Nov 11 '21 at 10:49
1

You have to tell the webserver of the docker image where the asp.net app runs to use also the https protocol.

You should achieve this, by injecting the environment variable ASPNETCORE_URLS with the following value https://+;http://+.

Further information about this env variable is availabel in the docs

ddegasperi
  • 662
  • 9
  • 12
  • I added a .env file at the root of my .net core web api project and pushed it up. Still getting the same error. The file contains: "ASPNETCORE_URLS=https://+;http://+". Do I need to add it through the Google Cloud VM? Is there something more I might be missing? Should this work for local docker as well? – James Anderbard Oct 23 '21 at 20:22
  • I don't know if Google Cloud VM takes into account the .env file; maybe you have to specify the environment variables for it. Alternatively you can provide a default value in the Dockerfile: `ENV ASPNETCORE_URLS https://+;http://+`. – ddegasperi Oct 25 '21 at 07:37
  • I have added the environment variable to the docker file and am still getting the same connection refused error. Any other ideas? – James Anderbard Oct 26 '21 at 01:07
  • I looked in the Google documentation and found the following entry https://cloud.google.com/compute/docs/containers/configuring-options-to-run-containers#setting_environment_variables. I assume you start the container with the gcloud command line tool. Try adding `--container-env ASPNETCORE_URLS=https://+;http://+` when creating the container. – ddegasperi Oct 26 '21 at 12:03