I've had to make some services that make HTTP requests to endpoints that require authentication via certificates. These services run fine when testing them locally or running them in a local container. But as soon as they are deployed to production, they start taking 15 seconds more than normal to finish their HTTP requests that use certificates.
This turns out to be because the TLS handshake times out trying to find out whether or not the certificate is to be trusted. Interestingly, it does not seem to occur when the request method uses SNI.
In my case this certificate I was trying to use for authentication was issued by OATI, a CA that is used by system operators in the United States. This is not a trusted CA by default in a .NET Linux container. I can see there is an ongoing bug report to get it added to Mozilla's trusted records - but at the time of writing this is still not in effect.
That's all fine and dandy, how do I fix it?
Well, to the point.
In order to fix it, I had to find the specific root certificate of the certificate I was using. For my case, I was already in posession of the root certificate.
But if you don't have it. In Windows, you can open the certificate you are expecting to authenticate with and find the root certificates in the certificate path tab.
and select each of the parent certificates in the certificate path tab. Press "View certificate" > "Details" > "Copy to file".
Select the Base64 encoded cert file type.
This should export a compatible certificate type for the linux container to load it. Make sure to rename the file to the
.crt file type extension.
Now, place the new file next to your Dockerfile that builds your container.
In the Dockerfile, add the following to import the certificate and make the container trust it:
ADD cert.crt /usr/local/share/ca-certificates/cert.crt
RUN chmod 644 /usr/local/share/ca-certificates/cert.crt
You can also find the snippet here on Bitbucket.
If you found additional root certificates, simply export them all individually and place them in the directory and repeat like so:
ADD cert1.crt /usr/local/share/ca-certificates/cert1.crt
ADD cert2.crt /usr/local/share/ca-certificates/cert2.crt
RUN chmod 644 /usr/local/share/ca-certificates/cert1.crt
RUN chmod 644 /usr/local/share/ca-certificates/cert2.crt
Now you should be good to go, and the service should no longer have the 15 second timeout during TLS handshake negotiation! 🥳