Windows Authentication
Linux Docker
.NET 5
Cross-Platform Development
Container Security

Windows authentication in Linux Docker container .Net 5

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Windows Authentication (Kerberos/NTLM) in a Linux Docker container running .NET 5+ requires configuring the container to authenticate against Active Directory using Kerberos. Linux cannot use NTLM natively, so Kerberos is the path forward. This involves installing the krb5 package in the container, providing a krb5.conf configuration file, obtaining a Kerberos ticket, and configuring the ASP.NET Core application to use Negotiate authentication.

Prerequisites

  • An Active Directory domain controller accessible from the container
  • A service account (SPN) registered in AD for the application
  • A keytab file generated for the service account
  • .NET 5 or later

Dockerfile Setup

dockerfile
1FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
2
3# Install Kerberos client libraries
4RUN apt-get update && \
5    apt-get install -y krb5-user libgssapi-krb5-2 && \
6    rm -rf /var/lib/apt/lists/*
7
8# Copy Kerberos configuration
9COPY krb5.conf /etc/krb5.conf
10
11# Copy the keytab file
12COPY service.keytab /app/service.keytab
13
14WORKDIR /app
15COPY --from=build /app/publish .
16
17# Set the keytab environment variable
18ENV KRB5_KTNAME=/app/service.keytab
19
20ENTRYPOINT ["dotnet", "MyApp.dll"]

Kerberos Configuration (krb5.conf)

ini
1[libdefaults]
2    default_realm = MYCOMPANY.COM
3    dns_lookup_realm = false
4    dns_lookup_kdc = true
5    ticket_lifetime = 24h
6    renew_lifetime = 7d
7    forwardable = true
8
9[realms]
10    MYCOMPANY.COM = {
11        kdc = dc01.mycompany.com
12        admin_server = dc01.mycompany.com
13    }
14
15[domain_realm]
16    .mycompany.com = MYCOMPANY.COM
17    mycompany.com = MYCOMPANY.COM

Replace MYCOMPANY.COM with your AD domain (uppercase for the realm) and dc01.mycompany.com with your domain controller hostname.

Generating a Keytab File

Run this on a machine with access to Active Directory:

bash
1# On Windows (using ktpass)
2ktpass -princ HTTP/[email protected] \
3       -mapuser MYCOMPANY\svc-myapp \
4       -pass "ServiceAccountPassword" \
5       -crypto AES256-SHA1 \
6       -ptype KRB5_NT_PRINCIPAL \
7       -out service.keytab
8
9# On Linux (using ktutil)
10ktutil
11addent -password -p HTTP/[email protected] -k 1 -e aes256-cts-hmac-sha1-96
12# Enter password
13wkt service.keytab
14quit

The SPN (HTTP/myapp.mycompany.com) must match the hostname clients use to access the application.

ASP.NET Core Configuration

Install NuGet Package

xml
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="5.0.0" />

Program.cs / Startup.cs

csharp
1// .NET 5 Startup.cs
2public void ConfigureServices(IServiceCollection services)
3{
4    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
5        .AddNegotiate();
6
7    services.AddAuthorization(options =>
8    {
9        options.FallbackPolicy = options.DefaultPolicy;
10    });
11
12    services.AddControllers();
13}
14
15public void Configure(IApplicationBuilder app)
16{
17    app.UseAuthentication();
18    app.UseAuthorization();
19    app.UseEndpoints(endpoints => endpoints.MapControllers());
20}

.NET 6+ Minimal API

csharp
1var builder = WebApplication.CreateBuilder(args);
2
3builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
4    .AddNegotiate();
5
6builder.Services.AddAuthorization(options =>
7{
8    options.FallbackPolicy = options.DefaultPolicy;
9});
10
11var app = builder.Build();
12
13app.UseAuthentication();
14app.UseAuthorization();
15
16app.MapGet("/", (HttpContext context) =>
17    $"Hello, {context.User.Identity?.Name}!");
18
19app.Run();

Accessing the Authenticated User

csharp
1[Authorize]
2[ApiController]
3[Route("api/[controller]")]
4public class UserController : ControllerBase
5{
6    [HttpGet("whoami")]
7    public IActionResult WhoAmI()
8    {
9        var identity = HttpContext.User.Identity as System.Security.Claims.ClaimsIdentity;
10
11        return Ok(new
12        {
13            Name = identity?.Name,
14            IsAuthenticated = identity?.IsAuthenticated,
15            AuthType = identity?.AuthenticationType,
16            Claims = identity?.Claims.Select(c => new { c.Type, c.Value })
17        });
18    }
19}

Docker Compose Configuration

yaml
1version: '3.8'
2services:
3  webapp:
4    build: .
5    ports:
6      - "5000:80"
7    environment:
8      - KRB5_KTNAME=/app/service.keytab
9      - KRB5_CONFIG=/etc/krb5.conf
10    volumes:
11      - ./krb5.conf:/etc/krb5.conf:ro
12      - ./service.keytab:/app/service.keytab:ro
13    dns:
14      - 10.0.0.1  # Your AD DNS server
15    extra_hosts:
16      - "dc01.mycompany.com:10.0.0.1"

The container must be able to resolve the domain controller hostname. Set DNS to your AD DNS server.

Testing Kerberos from the Container

bash
1# Enter the container
2docker exec -it myapp bash
3
4# Test Kerberos ticket acquisition
5kinit [email protected]
6# Enter password
7
8# Verify the ticket
9klist
10# Should show a valid TGT
11
12# Test with the keytab (no password needed)
13kinit -kt /app/service.keytab HTTP/[email protected]
14klist

If kinit fails, the issue is network connectivity, DNS resolution, or incorrect credentials — not the .NET application.

Troubleshooting

bash
1# Enable Kerberos debug logging
2export KRB5_TRACE=/dev/stdout
3kinit -kt /app/service.keytab HTTP/[email protected]
4
5# Check DNS resolution
6nslookup dc01.mycompany.com
7nslookup _kerberos._tcp.mycompany.com
8
9# Test connectivity to KDC (port 88)
10nc -zv dc01.mycompany.com 88
11
12# Check time synchronization (Kerberos requires <5 min skew)
13date
14ntpdate -q dc01.mycompany.com

Common Pitfalls

  • Clock skew: Kerberos requires the container clock to be within 5 minutes of the domain controller. Docker containers inherit the host clock, but if the host drifts, authentication fails with Clock skew too great. Use NTP synchronization on the Docker host.
  • DNS resolution: The container must resolve the domain controller by hostname, not just IP. Add dns entries in Docker Compose or use extra_hosts to map the DC hostname.
  • SPN mismatch: The SPN in the keytab must exactly match HTTP/hostname where hostname is what clients use in the URL. If clients access https://myapp.mycompany.com, the SPN must be HTTP/[email protected].
  • Keytab permissions: The keytab file contains credentials. Set restrictive permissions (chmod 600) and never commit it to source control. Use Docker secrets or a vault in production.
  • NTLM fallback: Linux does not support NTLM natively. If the client sends NTLM instead of Kerberos (common with older Windows clients or non-domain-joined machines), authentication fails. Ensure clients are configured for Kerberos.

Summary

  • Install krb5-user and libgssapi-krb5-2 in the container for Kerberos support
  • Provide krb5.conf with your AD realm and KDC hostname
  • Generate a keytab file for the service account SPN
  • Set KRB5_KTNAME environment variable to the keytab path
  • Use Microsoft.AspNetCore.Authentication.Negotiate in ASP.NET Core
  • Ensure DNS resolution and clock synchronization between the container and domain controller

Course illustration
Course illustration

All Rights Reserved.