skip to Main Content

I’ve searched for hours trying to solve this issue and I just cannot seem to make it work. I believe I understand what is going wrong but I don’t know how to solve it.

My app contains an API container, Front end container, and a database container that both rely on. I have the following docker compose file:

version: '3.4'

services:
  invoicing.api:
    image: ${DOCKER_REGISTRY-}invoicingapi
    build:
      context: .
      dockerfile: invoicing.api/Dockerfile
    ports:
     - 5000:80
     - 5001:443
    links:
      - db
    depends_on:
      db:
        condition: service_healthy
        required: true
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
      - ASPNETCORE_Kestrel__Certificates__Default__Password=somepass
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
    volumes:
      - ~/.aspnet/https:/https:ro
    networks:
      - mybackend-network

  invoicing.webapp:
    image: ${DOCKER_REGISTRY-}invoicingwebapp
    build:
      context: .
      dockerfile: invoicing.webapp/Dockerfile
    ports:
     - 5002:80
     - 5003:443
    depends_on:
      db:
        condition: service_healthy
        required: true
    networks:
      - mybackend-network

  db:
    image: postgres:latest
    restart: always
    container_name: 'db'
    environment:
      POSTGRES_USERNAME: postgres
      POSTGRES_PASSWORD: somepass
      POSTGRES_DB: invoicing
    ports: 
      - "5433:5432"
    volumes:
      - local_postgres_data:/var/lib/postgresql/data
    networks:
      - mybackend-network
    healthcheck:
      test: pg_isready -U postgres
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  local_postgres_data: {}

networks:
  mybackend-network:
    driver: bridge

My API dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base

WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Invoicing.API/Invoicing.API.csproj", "Invoicing.API/"]
COPY ["Invoicing.Business/Invoicing.Business.csproj", "Invoicing.Business/"]
COPY ["Invoicing.Data/Invoicing.Data.csproj", "Invoicing.Data/"]
RUN dotnet restore "Invoicing.API/Invoicing.API.csproj"
COPY . .
WORKDIR "/src/Invoicing.API"
RUN dotnet build "Invoicing.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Invoicing.API.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "Invoicing.API.dll"]

My webapp dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Invoicing.WebApp/Invoicing.WebApp.csproj", "Invoicing.WebApp/"]
COPY ["Invoicing.Data/Invoicing.Data.csproj", "Invoicing.Data/"]
RUN dotnet restore "Invoicing.WebApp/Invoicing.WebApp.csproj"
COPY . .
WORKDIR "/src/Invoicing.WebApp"
RUN dotnet build "Invoicing.WebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Invoicing.WebApp.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Invoicing.WebApp.dll"]

When I try to run an HttpClient Post (or any) call from the web app to the api app using the below code, I get the below exception.

HttpResponseMessage response = await _client.PostAsync(uri, cont);

Message:

The SSL connection could not be established, see inner exception.

InnerException:

The remote certificate is invalid according to the validation
procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors

My uri:
https://invoicing.api:443/api/v1/Stripe/CreateCustomer

I have created a self signed certificate locally aspnetapp.pfx, trusted it, and import it to the api docker environment, without error, but when I call the API from within the webapp running from docker compose, I get this error. My belief is that within the Linux container running the API, the certificate is not trusted. It’s only trusted in my local environment.

I wouldn’t mind calling the API over HTTP to avoid the issue since this is just my dev environment, but it seems Docker is being forced to HTTPS even if I only expose the 80 port.

I’m only interested in making this work for development purposes. I’ll focus on Production when I reach that point. What should I do? Should I try trust the development certificate on the Linux container, override HTTPS and just go with HTTP if possible, or create a certificate from a certificate authority to replace my development certificate?

2

Answers


  1. Chosen as BEST ANSWER

    I ended up forcing the HttpClient to allow untrusted certificates while in debug mode. In release mode (production) I will have valid certificates anyway so this should not be a problem.

    #if DEBUG
                // if in debug mode (i.e. local docker compose), allows untrusted SSL certificates with HttpClient
                var handler = new HttpClientHandler()
                {
                    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                };
    
                _client = new HttpClient(handler);
    #else
                _client = new HttpClient();
    #endif
    

  2. Bypass the cert validation in net core http client service registering.
    If use Httpclient directly.

    var httpClientHandler = new HttpClientHandler();
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>{return true;};
    builder.Services.AddScoped(sp => new HttpClient(httpClientHandler));
    

    If use IHttpClientFactory

    builder.Services.AddHttpClient("Myclient").ConfigurePrimaryHttpMessageHandler(() =>
            {
                var handler = new HttpClientHandler();
                handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
                return handler;
            });
    

    Or you could add same validation

    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
        if (cert.GetCertHashString() == "A7E2BA992F4F2BE220559B8A5371F05A00A6E750") //FingerPrint of the certificate
        {
            return true;
        }
        return false;
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search