如何让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信任区域:
- 打开浏览器设置,搜索「本地Intranet」
- 添加
https://localhost到信任区域 - 启用「自动登录到本地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
相关产品推荐
相关产品推荐

