3

I am using SendGrid to send emails .net5 windows service, it works as expected when I run the application locally from Visual Studio. But it gives an exception on SendEmailAsync when I run the application in Docker.

Exception:

The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

List<Personalization> personalizations = new List<Personalization>();
Personalization personalization = new Personalization();

personalization.From = new EmailAddress(emailDetails.SenderMailID);
personalization.Tos = GetRecipientsList(emailDetails.RecipientMailID);
personalization.Subject = emailDetails.Subject;
personalizations.Add(personalization);
var msg = new SendGridMessage
{
    From = new EmailAddress(emailDetails.SenderMailID),
    Subject = emailDetails.Subject
};
msg.AddContent(MimeType.Html, emailDetails.Message);
msg.Personalizations = personalizations;
var sendGridClient = new SendGridClient(apiKey);
var sendGridResponse = await sendGridClient.SendEmailAsync(msg);

Docker file:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["src/service/MyWindowsService/MyWindowsService.csproj", "src/service/MyWindowsService/"]
RUN dotnet restore "src/service/MyWindowsService/MyWindowsService.csproj"
COPY . .
WORKDIR "/src/src/service/MyWindowsService"
RUN dotnet build "MyWindowsService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyWindowsService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWindowsService.dll"]
Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197

1 Answers1

5

It appears the issue here is an untrusted certificate. It might happens when a certificate is self signed or with a non public CA root, for example.

In this case what I would do is copy the cert or CA to the path "/etc/ssl/certs/" of your base/final docker stage.

For example in the second line of your docker file:

COPY ./server-certificate.pem /etc/ssl/certs/server-certificate.pem

The previous way will show to you if that is your problem. Assuming that is the solution I advise you to no copy directly the certificate in your docker file. In a production environment you should do it as a Secret in case of you are using Kubernetes or trought docker-compose and volumes, for example.

Edit: Obtain the certificate you need to trust and place it on the same path of your Dockerfile. Then edit you dockerfile like as follow:

FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
COPY ./server-certificate.pem /etc/ssl/certs/server-certificate.pem
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["src/service/MyWindowsService/MyWindowsService.csproj", "src/service/MyWindowsService/"]
RUN dotnet restore "src/service/MyWindowsService/MyWindowsService.csproj"
COPY . .
WORKDIR "/src/src/service/MyWindowsService"
RUN dotnet build "MyWindowsService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyWindowsService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWindowsService.dll"]
m.lucas
  • 169
  • 6
  • I have added the line `COPY ./server-certificate.pem /etc/ssl/certs/server-certificate.pem` in the DockerFile but `RUN dotnet build "FXPayments.Service.FxCloudEmailService.csproj" -c Release -o /app/build` line, but its giving the same exception. Di I need to do anything else? – Vivek Nuna Dec 07 '21 at 13:49
  • If the COPY command ran well your docker container should be able to trust in the certificate or CA you added to the path **/etc/ssl/certs** . I recommend you to check if your container can establish a secure connection with the server your application is trying to connect. It can be done thought _bash_ from your running docker container and/or verifying if the certificate you copied is on the expected path. – m.lucas Dec 07 '21 at 14:08
  • what will be my certificate name? also I cannot find file on the path `/etc/ssl/certs` – Vivek Nuna Dec 07 '21 at 14:51
  • Will be the same of you named at COPY command (e.g. server-certificate.pem). In the command example you need to have the right certificate from the server that you want to connect at the same level of your Dockerfile. Replace the name server-certificate.pem as you want. – m.lucas Dec 07 '21 at 16:04
  • Sorry, I didn’t get this comment **In the command example you need to have the right certificate from the server that you want to connect at the same level of your Dockerfile**. – Vivek Nuna Dec 07 '21 at 16:07
  • I tried with `FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base COPY ./server-certificate.pem /etc/ssl/certs/server-certificate.pem WORKDIR /app` but it gives error Docker command failed with exit code 1.. your solution is not working at all. – Vivek Nuna Dec 08 '21 at 05:15
  • how to get server-certificate.pem file? – Vivek Nuna Dec 08 '21 at 05:22
  • The COPY command must work properly if the cert name and path matches between the instruction and the local file. BTW to get a PEM from a certificate there are many ways, look for openssl CLI or take a look at the follow link (I have not tried it with smtp servers) https://www.checktls.com/ and https://stackoverflow.com/questions/7885785/using-openssl-to-get-the-certificate-from-a-server – m.lucas Dec 08 '21 at 13:48
  • I don’t even know how to generate certificate – Vivek Nuna Dec 08 '21 at 13:51