.NET Core 3.x Docker app hangs on opening a SQL server database connection

This is searchable on the internet, but a little write-up might be useful if you are running into the same problem.
Recently we upgraded some .NET Core applications running in a Docker container to .NET Core 3.1. A funny thing happened when we tested those apps, which is they simply stopped working and didn’t throw any errors to make us wiser on what the issue was.

That funny thing wasn’t so funny to be frank.

When figuring out what was going on we noticed that the app seemed to be hanging on creating a database connection. No exception was thrown, we didn’t get a timeout, it just got stuck on opening the connection.
After searching around a bit we ran into a number of GitHub issues related to this on .NET Core repos, where this one (https://github.com/dotnet/SqlClient/issues/201) sums it all up.

It turns out that the Docker image used for 3.1 is a Debian based image. On this image the OpenSSL TLS restrictions have been increased only allowing TLS 1.2 connections with a strong cipher, compared to the image used to build a 2.1 app. If your SQL server does not meet all of these requirements the .NET Core 3.x app will hang on trying to set up the database connection.

Great, but how do you fix this? Well there are 2 workarounds you can apply.

#1 Use the Ubuntu image instead of the Debian one.

By default, the Debian image is used if you let Visual Studio generate the Dockerfile. If you change this to one of the Ubuntu images, you are fine.

So instead of this in your Dockerfile:

FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base

You can use this:

FROM mcr.microsoft.com/dotnet/core/runtime:3.1-bionic AS base

If you don’t like using the Ubuntu image for some reason, you can still go for door number 2.

#2 Update the OpenSSL configuration

That OpenSSL configuration is stored in /etc/ssl/openssl.cnf. The lines that are the culprit are the MinProtocol setting and the CipherString.
Depending on what your issue is (TSL 1.2 not available, or your cipher strength) you can change one, or both of these lines.
The Debian config currently looks like:

MinProtocol = TLSv1.2
CipherString = DEFAULT@SECLEVEL=2

Depending on what you need, you can lower the SECLEVEL to allow not-so-good ciphers, or lower the minimum protocol level if you can’t use TLS 1.2.
That would look like this if you’d have to change both lines:

MinProtocol = TLSv1
CipherString = DEFAULT@SECLEVEL=1

In your Dockerfile you can do this with the following statements:

RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/' /etc/ssl/openssl.cnf
RUN sed -i 's/CipherString = DEFAULT@SECLEVEL=2/CipherString = DEFAULT@SECLEVEL=1/' /etc/ssl/openssl.cnf

The best idea is to get the SQL guys to upgrade security on the SQL server itself and make sure the default works. But in corporate environments this is something that can take a while and you probably need to get that app running yesterday, so…

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.