Docker与Ocelot环境下自签名证书PartialChain错误排查求助
问题描述
本地部署两个Docker容器:
- 容器1:基于Ocelot实现的API网关,监听端口6001
- 容器2:后端服务,监听端口7001
已通过OpenSSL生成自签名证书,网关的Ocelot配置如下:
{ "Routes": [ { "DownstreamPathTemplate": "/api/Role", "DownstreamScheme": "https", "DownstreamHostAndPorts": [ { "Host": "192.168.0.101", "Port": 7001 } ], "UpstreamPathTemplate": "/api/role", "UpstreamHttpMethod": [ "get" ] } ], "GlobalConfiguration": { "BaseURL": "https://192.168.0.101:6001" } }
直接访问https://192.168.0.101:7001/api/role和https://192.168.0.101:6001/api/index时,浏览器无证书错误可正常访问,但通过网关访问https://192.168.0.101:6001/api/role时出现问题:
- 浏览器显示“This page isn’t working”
- 控制台报错:
gateway | info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0] gateway | requestId: 0HN0H1OSQDUEG:00000001, previousRequestId: No PreviousRequestId, message: 'EndpointRateLimiting is not enabled for /api/Role' gateway | info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0] gateway | requestId: 0HN0H1OSQDUEG:00000001, previousRequestId: No PreviousRequestId, message: 'No authentication needed for /api/role' gateway | info: Ocelot.Authorization.Middleware.AuthorizationMiddleware[0] gateway | requestId: 0HN0H1OSQDUEG:00000001, previousRequestId: No PreviousRequestId, message: '/api/Role route does not require user to be authorized' gateway | warn: Ocelot.Responder.Middleware.ResponderMiddleware[0] gateway | requestId: 0HN0H1OSQDUEG:00000001, previousRequestId: No PreviousRequestId, 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 because of errors in the certificate chain: PartialChain gateway | at System.Net.Security.SslStream.SendAuthResetSignal(ReadOnlySpan`1 alert, ExceptionDispatchInfo exception) gateway | at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions) gateway | at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken) gateway | at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
需求:在Docker Desktop上使用自签名证书部署SSL容器,请问遗漏了哪些配置?
解决方案
核心问题
错误日志中的PartialChain表明:浏览器已手动信任自签名证书,但网关容器内的.NET运行时环境未将该证书加入信任根存储,导致无法验证后端服务的证书链完整性。
遗漏的配置及修复步骤
1. 将自签名CA证书导入网关容器的信任存储
网关作为客户端访问后端HTTPS服务时,需要信任后端的自签名证书。需将生成的CA证书导入容器的系统信任根:
- Linux容器:修改网关Dockerfile,添加证书导入步骤:
# 假设CA证书文件为ca.crt,复制到容器证书目录 COPY ca.crt /usr/local/share/ca-certificates/ # 更新系统证书存储 RUN update-ca-certificates - Windows容器:导入到Windows根证书存储:
COPY ca.crt C:/temp/ RUN certutil -addstore -f "Root" C:/temp/ca.crt
2. 确保自签名证书包含正确的SAN字段
生成自签名证书时,必须添加Subject Alternative Name(SAN),包含后端服务的IP(192.168.0.101)或主机名,否则网关会认为证书标识不匹配。
- 创建OpenSSL配置文件
openssl.cnf:[req] distinguished_name = req_distinguished_name x509_extensions = v3_ca [req_distinguished_name] commonName = 192.168.0.101 [v3_ca] subjectAltName = IP:192.168.0.101 - 生成证书时指定配置文件:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -config openssl.cnf -nodes
3. 测试环境临时配置:跳过证书验证(生产禁用)
若仅为测试,可临时让Ocelot的HttpClient跳过证书验证:
- 修改Ocelot配置,添加
HttpHandlerOptions:{ "Routes": [ { "DownstreamPathTemplate": "/api/Role", "DownstreamScheme": "https", "DownstreamHostAndPorts": [ { "Host": "192.168.0.101", "Port": 7001 } ], "UpstreamPathTemplate": "/api/role", "UpstreamHttpMethod": [ "get" ], "HttpHandlerOptions": { "ServerCertificateCustomValidationCallback": "IgnoreCertificateError" } } ], "GlobalConfiguration": { "BaseURL": "https://192.168.0.101:6001" } } - 在网关代码中注册自定义验证逻辑:
services.AddOcelot() .AddDelegatingHandler(() => new HttpClientHandler { ServerCertificateCustomValidationCallback = (_, _, _, _) => true });
4. 验证容器网络互通
进入网关容器,测试是否能正常访问后端服务:
docker exec -it <gateway-container-id> curl https://192.168.0.101:7001/api/role
若curl返回相同证书错误,说明容器未信任证书,按步骤1修复即可。
内容的提问来源于stack exchange,提问作者Abhishek Vyas
相关产品推荐
相关产品推荐

