You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6 Azure Linux App Service的gRPC mTLS配置问题求助

Azure Linux App Service上.NET 6 gRPC应用的mTLS配置问题

应用服务配置

应用设置

  • HTTP20_ONLY_PORT:gRPC使用的端口

常规设置

  • Http版本 = 2.0
  • HTTP 2.0代理 = 开启
  • 客户端证书模式 = 忽略(此时客户端可正常调用gRPC,设为其他值则抛出异常)

gRPC应用代码配置

builder.WebHost.ConfigureKestrel(options =>
{
   options.ConfigureHttpsDefaults(httpsOptions =>
   {
      //httpsOptions.ServerCertificate = certificate;
      httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
   });
}
    
builder.Services.AddGrpc(options =>
{
   options.EnableDetailedErrors = true;
   options.Interceptors.Add<AuthenticationInterceptor>(); // 拦截器仅包含日志逻辑
});

若修改代码中的ClientCertificateMode为其他值,调用可正常执行,但HttpContext中无法获取到客户端证书。

客户端代码

var certificate = new X509Certificate2("client.crt", "pwd");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);

using var channel = GrpcChannel.ForAddress("app-service-url", new GrpcChannelOptions
{
    HttpHandler = handler,
});
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });

自签名证书生成脚本

#CA
openssl genrsa -aes256 -out rootCA.key -passout pass:<pwd> 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt -passin pass:<pwd> -subj "//CN=MyRootCA"


#Server
openssl genrsa -aes256 -out server.key -passout pass:<pwd> 4096
openssl req -new -key server.key -out server.csr -passin pass:<pwd> -subj "//CN=app-service-url"
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 365 -sha256 -passin pass:<pwd>
openssl pkcs12 -passin pass:<pwd> -passout pass:<pwd> -export -out server.pfx -inkey server.key -in server.crt

#Client
openssl genrsa -aes256 -out client.key -passout pass:<pwd> 4096
openssl req -new -key client.key -out client.csr -passin pass:<pwd> -subj "//CN=Client"
openssl x509 -req -in client.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out client.crt -days 365 -sha256 -passin pass:<pwd>
openssl pkcs12 -passin pass:<pwd> -passout pass:<pwd> -export -out client.pfx -inkey client.key -in client.crt

问题现象

已在本地安装客户端证书,将服务器证书部署至App Service,也曾尝试在ConfigureHttpsDefaults中直接设置证书,但仍出现相同异常。还尝试配置转发头,但未成功。

核心问题出在App Service:当客户端证书模式设为忽略以外的值时,调用抛出如下异常:

Grpc.Core.RpcException: 'Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'ProtocolVersion'. Win32Exception: The message received was unexpected or badly formatted.", DebugException="System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'ProtocolVersion'. ---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted. --- End of inner exception stack trace --- at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm) at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken) --- End of inner exception stack trace ---

更新信息

已将TLS设置为1.2,本地操作系统为Win11。
若客户端指定使用TLS1.2:

handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;

则抛出异常:

Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: Authentication failed, see inner exception. Win32Exception: The function requested is not supported

使用Chrome访问App Service时,会弹出证书选择窗口且无异常,推测问题可能出在本地操作系统或客户端配置。

排查方向与解决方案

1. 客户端证书格式与存储问题

  • 确保客户端使用PFX格式证书而非CRT:当前代码加载的client.crt仅含公钥,缺少私钥,应加载生成的client.pfx,同时添加存储权限参数避免Win11下的权限问题:
    var certificate = new X509Certificate2("client.pfx", "pwd", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
    

2. Azure App Service的mTLS配置验证

  • 确认App Service的TLS/SSL设置中已启用“客户端证书(入站)”,若使用自定义域名,需确保服务器证书已正确绑定。
  • 检查WEBSITE_LOAD_CERTIFICATES应用设置,添加服务器证书的Thumbprint,让应用可以访问证书。

3. Kestrel转发头配置

  • 在Azure Linux App Service上,需启用证书转发,确保客户端证书能传递到应用:
    builder.Services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
        options.KnownProxies.Add(IPAddress.Parse("168.63.129.16")); // 添加App Service代理IP
    });
    
    并在app.UseRouting();之前添加app.UseForwardedHeaders();。

4. TLS协议协商调整

  • 检查App Service的TLS版本设置,仅启用TLS 1.2和TLS 1.3,避免旧协议冲突。
  • 客户端不要硬指定单一TLS版本,让系统自动协商;若必须指定,尝试同时包含TLS 1.3:
    handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
    

5. 根CA证书信任配置

  • 将rootCA.crt安装到本地“受信任的根证书颁发机构”存储区,确保客户端信任服务器证书,避免TLS握手失败。

6. 启用详细日志排查

  • 在客户端添加日志配置,查看TLS握手的具体细节:
    在appsettings.json中添加:
    "Logging": {
      "LogLevel": {
        "System.Net.Http.HttpClient": "Debug",
        "System.Net.Security": "Debug"
      }
    }
    

内容的提问来源于stack exchange,提问作者Flow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 12:40:15