Docker容器间ASP.NET Web API通信因SSL证书链不信任失败排查
我有两个ASP.NET Web API:一个Identity Server,一个普通Web API,计划部署在Docker容器中。为容器间HTTPS连接生成了自签名SSL证书,已手动添加到本地受信任根证书颁发机构。配置的docker-compose.yml如下:
services: identityserver: build: context: . dockerfile: src/IdentityServer/Dockerfile entrypoint: /bin/sh -c "update-ca-certificates && dotnet Duende.IdentityServer.dll" environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=https://+:7000 - ASPNETCORE_Kestrel__Certificates__Default__Password=******* - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/localhost.pfx ports: - "7000:7000" volumes: - ./localhost.pfx:/https/localhost.pfx:ro - ./localhost.crt:/usr/local/share/ca-certificates/localhost.crt:ro api: container_name: api build: context: . dockerfile: src/Web.Api/Dockerfile depends_on: - identityserver entrypoint: /bin/sh -c "update-ca-certificates && dotnet Web.Api.dll" environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=https://+:7001 - ASPNETCORE_Kestrel__Certificates__Default__Password=******* - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/localhost.pfx - AUTHENTICATION__AUTHORITY=https://identityserver:7000 - AUTHENTICATION__AUDIENCE=9fc33c2e-dbc1-4d0a-b212-68b9e07b3ba0 ports: - "7001:7001" volumes: - ./localhost.pfx:/https/localhost.pfx:ro - ./localhost.crt:/usr/local/share/ca-certificates/localhost.crt:ro
调用Web API的受保护端点(如https://api:7001/WeatherForecast)时出现错误:
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://identityserver:7000/.well-known/openid-configuration'.
System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://identityserver:7000/.well-known/openid-configuration'.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
浏览器访问https://identityserver:7000/.well-known/openid-configuration正常,确认问题出在Docker配置。
以下是针对性的修复方案,按优先级尝试:
1. 确认容器内证书更新生效
执行update-ca-certificates后,需验证证书是否被正确添加:
- 进入API容器查看更新日志:
输出需包含docker-compose exec api update-ca-certificates -vAdding localhost.crt的提示,若显示no certificates added,说明证书格式(需为PEM编码,不能是DER)或挂载路径有误。 - 检查容器内证书文件权限:确保
localhost.crt的权限为644,否则系统无法读取。
2. 配置.NET运行时信任系统CA证书
.NET在Linux容器中默认可能未完全信任系统证书池,需添加环境变量强制绑定:
在api服务的environment节点中新增:
- SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - SSL_CERT_DIR=/etc/ssl/certs - DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0
3. 验证证书包含容器服务名
API容器通过identityserver服务名访问Identity Server,需确保自签名证书的**Subject Alternative Name (SAN)**包含该主机名:
- 用以下命令检查证书:
openssl x509 -in localhost.crt -text -noout | grep -A 1 "Subject Alternative Name" - 若输出中没有
DNS:identityserver,需重新生成包含该主机名的证书(生成时添加-addext "subjectAltName=DNS:localhost,DNS:identityserver"参数)。
4. 优化容器启动顺序(可选)
depends_on仅保证容器启动顺序,不保证Identity Server服务就绪。可在API容器的entrypoint中添加等待逻辑:
entrypoint: /bin/sh -c "until curl -k -f https://identityserver:7000/.well-known/openid-configuration; do sleep 5; done; update-ca-certificates && dotnet Web.Api.dll"
注:-k参数用于curl临时绕过证书验证,仅用于等待服务就绪,核心信任问题仍需通过前几步修复。
5. 开发环境临时绕过验证(不推荐生产)
仅用于开发测试,在API的Program.cs中关闭证书验证:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = builder.Configuration["AUTHENTICATION__AUTHORITY"]; options.Audience = builder.Configuration["AUTHENTICATION__AUDIENCE"]; // 开发环境临时禁用证书验证 options.BackchannelHttpHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; });
生产环境禁止使用此方法。
内容的提问来源于stack exchange,提问作者west

