Search code examples
c#docker.net-coresendgrid.net-5

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


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"]

Solution

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

    In this case, you can copy the certificate or CA to the specified 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 you if that is your problem. Assuming that is the solution I advise you to not 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 with docker-compose volumes, for example.

    Edit: To obtain the certificate you need to trust and place it on the same path as your Dockerfile. Then edit your dockerfile 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"]