Ocelot + consul + 我的网站 api (.Net 5) 在 docker 中通过 HTTPS

Ocelot + consul + my web api (.Net 5) via HTTPS in docker

我正在尝试通过 HTTPS 在 docker;

中使用 Ocelot(Api 网关)+ consul + 我的网站 api (.Net 5)

信任来自 Windows 子系统的 HTTPS 证书 Linux

来源: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.

我的docker-撰写:

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

我的配置文件“ocelot.json”(没有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-撰写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

案例 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

案例 2:

我在我的服务中添加了一个 https 重定向

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

案例 3

我在 https 和端口 9001

上更改了配置文件 ocelot.json
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
    {
        "Host": "license-service-web-api-01",
        "Port": 9001
    }
],

在我的服务中删除了行 app.UseHttpsRedirection();

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

我有问题,也许有人可以帮助我,请:

  1. 为什么 ocelot 不能通过 https 调用我的服务器?
  2. 如何在 docker 中为 Consul 启用 https - 撰写?

你在最后一个案例中遇到了 ssl 错误。这个问题你可以有 2 个选项

  1. best.option 您创建自己的证书,然后让您的本地或远程计算机信任它。

  2. 快速选项 您可以将此行添加到您的 ocelot.json

    "DangerousAcceptAnyServerCertificateValidator": true

您应该在 docker-compose 文件中添加 networks 标签。 如下所示:

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