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

如何让Docker Desktop中Windows容器的.NET 8 Minimal API适配gMSA?

问题

我们组织刚接触容器技术,深度投入微软生态,使用本地Active Directory而非Azure Active Directory。当前基于.NET 8构建微服务,计划用gMSA实现Windows容器内API对接AD,目前处于调研阶段,搭建了基础Minimal API并配置Windows认证,但在Docker Desktop中运行时遇到问题:

  • 访问API(如https://localhost:53300/weatherforecast)会弹出登录窗口,输入凭据后陷入循环,始终返回401未授权
  • Swagger可正常打开,但调用GET接口时同样出现上述问题

已配置的认证代码

using Microsoft.AspNetCore.Authentication.Negotiate;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
   .AddNegotiate();
builder.Services.AddAuthorization(opt => opt.FallbackPolicy = opt.DefaultPolicy);

builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy.
    options.FallbackPolicy = options.DefaultPolicy;
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", (HttpContext context) =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.UseAuthentication();
app.UseAuthorization();
app.Run();

internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

关键日志信息

dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HN0JF74G3G36" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HN0JF74G3G36" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[3]
      Connection 0HN0JF74G3G36 established using the following protocol: Tls12
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:53300/weatherforecast - - -
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
      1 candidate(s) found for the request path '/weatherforecast'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
      Request matched endpoint 'HTTP: GET /weatherforecast'
dbug: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[15]
      Static files was skipped as the request already matched an endpoint.
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[12]
      Negotiate is not supported with HTTP/2.
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[9]
      AuthenticationScheme: Negotiate was not authenticated.
dbug: Microsoft.AspNetCore.Authorization.AuthorizationMiddleware[0]
      Policy authentication schemes  did not succeed
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed. These requirements were not met:
      DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[6]
      Challenged 401 Negotiate.
info: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[12]
      AuthenticationScheme: Negotiate was challenged.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/2 GET https://localhost:53300/weatherforecast - 401 0 - 8.0066ms

目前尚未配置gMSA,想了解本地Docker Desktop开发环境中,除gMSA外还需进行哪些配置?


本地Docker Desktop开发环境的额外配置(除gMSA外)

1. 强制Kestrel使用HTTP/1.1

日志明确显示核心问题:Negotiate is not supported with HTTP/2。Negotiate认证(NTLM/Kerberos)不兼容HTTP/2,必须强制服务使用HTTP/1.1。

在Program.cs中添加Kestrel配置:

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(53300, listenOptions =>
    {
        listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1;
        listenOptions.UseHttps();
    });
});

或通过appsettings.json配置:

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://+:53300",
        "Protocols": "Http1"
      }
    }
  }
}

2. 确保容器网络能访问域控制器

  • 切换Docker Desktop至Windows容器模式(对接AD必须使用Windows容器)
  • 在Dockerfile中设置容器DNS服务器为域控制器IP,保证容器能解析域服务:
    FROM mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-ltsc2022 AS base
    WORKDIR /app
    EXPOSE 53300
    # 替换为实际域控制器IP
    RUN netsh interface ipv4 set dnsservers "Ethernet" static 192.168.1.10 primary
    
  • 测试容器内域解析:进入容器执行nslookup <你的域名>,确认能返回域控制器IP

3. 调整浏览器NTLM认证信任设置

对于Chrome/Edge浏览器,需将localhost加入本地Intranet信任区域:

  1. 打开浏览器设置,搜索「本地Intranet」
  2. 添加https://localhost到信任区域
  3. 启用「自动登录到本地Intranet区域」选项

4. 开发环境临时运行身份配置(替代gMSA的临时方案)

正式环境用gMSA,开发阶段可临时让容器以域用户身份运行:

  • Docker Run命令:
    docker run -it --rm --name weather-api -p 53300:53300 --user "DOMAIN\用户名" -e "PASSWORD=你的密码" weather-api-image
    
  • Docker Compose配置:
    services:
      weather-api:
        image: weather-api-image
        ports:
          - "53300:53300"
        user: "DOMAIN\用户名"
        environment:
          - PASSWORD=你的密码
    

5. 验证域服务连通性

  • 确保运行Docker Desktop的本地机器已加入AD域
  • 在容器内测试LDAP连通性:执行telnet <域控制器IP> 389,确认能正常连接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:57:01