Answer a question

I'm trying to use Ocelot (Api gateway) + consul + my web api (.Net 5) via HTTPS in docker;

  • ocelot - v17.0.0
  • consul - latest https://hub.docker.com/_/consul
  • my service - ASP.NET 5 Web Api

Trust HTTPS certificate from Windows Subsystem for Linux

source: https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-5.0&tabs=visual-studio#trust-https-certificate-from-windows-subsystem-for-linux

MY_SECRET_PROJECT_PATH\LicenseServiceWebApi> dotnet dev-certs https --clean
Cleaning HTTPS development certificates from the machine. A prompt might get displayed to confirm the removal of some of the certificates.
HTTPS development certificates successfully removed from the machine.

MY_SECRET_PROJECT_PATH\LicenseServiceWebApi> dotnet dev-certs https -ep $env:USERPROFILE\.aspnet\https\aspnetdev.pfx -p <водкабалалайка>
The HTTPS developer certificate was generated successfully.

MY_SECRET_PROJECT_PATH\LicenseServiceWebApi> dotnet dev-certs https --trust
Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed if the certificate was not previously trusted. Click yes on the prompt to trust the certificate.
A valid HTTPS certificate is already present.

My docker-compose:

version: '3'

services:
  license-service-web-api-01:
    image: license-service-web-api
    container_name: license-service-01
    build: 
      context: .
      dockerfile: Services/LicenseServiceWebApi/Dockerfile
    environment:                      
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:9001;http://+:9000    
      - ASPNETCORE_Kestrel__Certificates__Default__Password=${Kestrel_Certificate_Password}
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/root/.aspnet/https/aspnetdev.pfx
    volumes:
      - ${USERPROFILE}\.aspnet\https:/root/.aspnet/https/:ro
    ports:
      - 9000:9000
      - 9001:9001
    depends_on:
      - consul
                     
  gateway:
    image: gateway
    container_name: gateway
    build: 
      context: .
      dockerfile: ApiGateway/gateway/Dockerfile                  
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:5001;http://+:5000
      - ASPNETCORE_Kestrel__Certificates__Default__Password=${Kestrel_Certificate_Password}
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/root/.aspnet/https/aspnetdev.pfx
    volumes:
      - ${USERPROFILE}\.aspnet\https:/root/.aspnet/https/:ro 
    ports:
      - 5001:5001
      - 5000:5000
    depends_on:
      - consul

  consul:
    image: consul
    container_name: consul
    command: agent -server -ui -node=server-1 -bootstrap-expect=1 -client=0.0.0.0
    environment: 
      - 'CONSUL_LOCAL_CONFIG= {"connect": {"enabled": true}}'
    ports: 
      - 8500:8500

My configuration file "ocelot.json" (version without Consul)

{
  "Routes": [
    {
      "SwaggerKey": "License Service",
      "DownstreamPathTemplate": "/api/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "license-service-web-api-01",
          "Port": 9000
        }
      ],
      "UpstreamHttpMethod": [ "Put", "Post", "GET" ],
      "UpstreamPathTemplate": "/{everything}",
      "LoadBalancerOptions": {
        "Type": "LeastConnection"
      },
      "FileCacheOption": {
        "TtlSeconds": 30
      }
    },
    {
      "DownstreamPathTemplate": "/swagger/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "license-service-web-api-01",
          "Port": 9000
        }
      ],
      "UpstreamPathTemplate": "/swagger/{everything}",
      "FileCacheOption": {
        "TtlSeconds": 666
      }
    }
  ],
  "SwaggerEndPoints": [
    {
      "Key": "License Service",
      "Config": [
        {
          "Name": "License Service API",
          "Version": "v1",
          "Service": {
            "Name": "License Service",
            "Path": "/swagger/v1/swagger.json"
          }
        }
      ]
    }
  ]
}

docker-compose ps

       Name                     Command               State                                              Ports
----------------------------------------------------------------------------------------------------------------------------------------------------------
consul               docker-entrypoint.sh agent ...   Up      8300/tcp, 8301/tcp, 8301/udp, 8302/tcp, 8302/udp, 0.0.0.0:8500->8500/tcp, 8600/tcp, 8600/udp
gateway              dotnet gateway.dll               Up      443/tcp, 0.0.0.0:5000->5000/tcp, 0.0.0.0:5001->5001/tcp
license-service-01   dotnet LicenseServiceWebAp ...   Up      443/tcp, 0.0.0.0:9000->9000/tcp, 0.0.0.0:9001->9001/tcp

CASE 1:

PS C:\Users\tim> curl http://localhost:9000/api/HealthCheck/GetMachineName
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=2a429d520129
RawContent        : HTTP/1.1 200 OK

PS C:\Users\tim> curl https://localhost:9001/api/HealthCheck/GetMachineName
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=2a429d520129
RawContent        : HTTP/1.1 200 OK

PS C:\Users\tim> curl http://localhost:5000/HealthCheck/GetMachineName
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=2a429d520129
RawContent        : HTTP/1.1 200 OK

PS C:\Users\tim> curl https://localhost:5001/HealthCheck/GetMachineName
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=2a429d520129
RawContent        : HTTP/1.1 200 OK

CASE 2:

I added an https redirect in my service

app.UseHttpsRedirection();
PS C:\Users\tim> curl http://localhost:9000/api/HealthCheck/GetMachineName
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=345437c4c182
RawContent        : HTTP/1.1 200 OK

PS C:\Users\tim> curl https://localhost:9001/api/HealthCheck/GetMachineName                                                                                                                                                                     
StatusCode        : 200
StatusDescription : OK
Content           : MachineName=345437c4c182
RawContent        : HTTP/1.1 200 OK

PS C:\Users\tim> curl http://localhost:5000/HealthCheck/GetMachineName
curl : Unable to resolve the remote name: 'license-service-web-api-01'

docker-compose logs ..
 
gateway                       | info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
gateway                       |       requestId: 0HM6VQAI1UTJU:00000002, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /api/{everything}
gateway                       | info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0]
gateway                       |       requestId: 0HM6VQAI1UTJU:00000002, previousRequestId: no previous request id, message: No authentication needed for /HealthCheck/GetMachineName
gateway                       | info: Ocelot.Authorization.Middleware.AuthorizationMiddleware[0]
gateway                       |       requestId: 0HM6VQAI1UTJU:00000002, previousRequestId: no previous request id, message: /api/{everything} route does not require user to be authorized
gateway                       | info: Ocelot.Requester.Middleware.HttpRequesterMiddleware[0]
gateway                       |       requestId: 0HM6VQAI1UTJU:00000002, previousRequestId: no previous request id, message: 307 (Temporary Redirect) status code, request uri: http://license-service-web-api-01:9000/api/HealthCheck/GetMachineName


PS C:\Users\tim> curl https://localhost:5001/HealthCheck/GetMachineName
curl : Unable to resolve the remote name: 'license-service-web-api-01'

..The logs are the same

CASE 3

I'm changed configuration file ocelot.json on https and port 9001

"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
    {
        "Host": "license-service-web-api-01",
        "Port": 9001
    }
],

AND

removed line app.UseHttpsRedirection(); in my service

GET https://localhost:5001/WeatherForecast
502
225 ms
Warning: Unable to verify the first certificate
GET /WeatherForecast HTTP/1.1
User-Agent: PostmanRuntime/7.26.8
Accept: */*
Postman-Token: 6cafa9e0-e195-4082-a7d4-daac4f58dff7
Host: localhost:5001
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
HTTP/1.1 502 Bad Gateway
Date: Fri, 05 Mar 2021 14:50:01 GMT
Server: Kestrel
Content-Length: 0

gateway                       | info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
gateway                       |       requestId: 0HM6VSNQ8J5GI:00000002, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /api/{everything}
gateway                       | info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0]
gateway                       |       requestId: 0HM6VSNQ8J5GI:00000002, previousRequestId: no previous request id, message: No authentication needed for /WeatherForecast
gateway                       | info: Ocelot.Authorization.Middleware.AuthorizationMiddleware[0]
gateway                       |       requestId: 0HM6VSNQ8J5GI:00000002, previousRequestId: no previous request id, message: /api/{everything} route does not require user to be authorized
gateway                       | warn: Ocelot.Responder.Middleware.ResponderMiddleware[0]
gateway                       |       requestId: 0HM6VSNQ8J5GI:00000002, previousRequestId: no previous request id, message: Error Code: ConnectionToDownstreamServiceError Message: Error connecting to downstream service, exception: System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
gateway                       |        ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors
gateway                       |          at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
gateway                       |          at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
gateway                       |          at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
gateway                       |          --- End of inner exception stack trace ---
gateway                       |          at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
gateway                       |          at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
gateway                       |          at Ocelot.Requester.HttpClientHttpRequester.GetResponse(HttpContext httpContext) errors found in ResponderMiddleware. Setting error response for request path:/WeatherForecast, request method: GET

I have questions, maybe someone can help me, please:

  1. Why ocelot can't call my serive over https?
  2. How i can https enabled for Consul inside docker - compose?

Answers

you have a ssl error last case. You may 2 options for this issue

  1. best.option you creating your own certificate and then getting it trusted by your local or remote machine.

  2. quick option you can add this line your ocelot.json

    "DangerousAcceptAnyServerCertificateValidator": true

you should add networks tag on your docker-compose file. like below:

version: '3'

networks:
  dockerapi:
    driver: bridge

services:
  license-service-web-api-01:
    image: license-service-web-api
    container_name: license-service-01
    build: 
      context: .
      dockerfile: Services/LicenseServiceWebApi/Dockerfile
    environment:                      
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:9001;http://+:9000    
      - ASPNETCORE_Kestrel__Certificates__Default__Password=${Kestrel_Certificate_Password}
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/root/.aspnet/https/aspnetdev.pfx
    volumes:
      - ${USERPROFILE}\.aspnet\https:/root/.aspnet/https/:ro
    ports:
      - 9000:9000
      - 9001:9001
    depends_on:
      - consul
    networks:
      - dockerapi   
                     
  gateway:
    image: gateway
    container_name: gateway
    build: 
      context: .
      dockerfile: ApiGateway/gateway/Dockerfile                  
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:5001;http://+:5000
      - ASPNETCORE_Kestrel__Certificates__Default__Password=${Kestrel_Certificate_Password}
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/root/.aspnet/https/aspnetdev.pfx
    volumes:
      - ${USERPROFILE}\.aspnet\https:/root/.aspnet/https/:ro 
    ports:
      - 5001:5001
      - 5000:5000
    depends_on:
      - consul
    networks:
      - dockerapi  
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐