Scenario 10.3: mTLS Deployment

Category: TLS/mTLS
Complexity: ⭐⭐⭐⭐ (High)
Prerequisites: Server and client certificates, PKI
Estimated Time: 30-45 Minutes


Description

This scenario describes the complete deployment of an mTLS infrastructure for mutual authentication between clients and servers.

Use Cases:

  • Zero-Trust Architectures
  • Service Mesh (Istio, Linkerd)
  • API Security
  • Microservices Communication
  • IoT Device Authentication

Architecture

flowchart TD subgraph PKI ROOT[Root CA] --> INT_SRV[Intermediate CA Server] ROOT --> INT_CLI[Intermediate CA Clients] end subgraph Server INT_SRV --> SRV_CERT[Server Certificate] SRV_CERT --> API[API Server] end subgraph Clients INT_CLI --> CLI1[Client 1] INT_CLI --> CLI2[Client 2] INT_CLI --> CLI3[Service A] end CLI1 <-->|mTLS| API CLI2 <-->|mTLS| API CLI3 <-->|mTLS| API


1. PKI Structure for mTLS

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
public class MtlsPkiSetup
{
    public void CreateMtlsPki(string basePath)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Root CA
        using var rootKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
        var rootCert = ctx.CreateSelfSignedCertificate(
            rootKey,
            new DnBuilder().AddCN("mTLS Root CA").AddO("Example").Build(),
            validDays: 3650,
            extensions: new ExtBuilder()
                .BasicConstraints(ca: true, pathLengthConstraint: 2, critical: true)
                .KeyUsage(KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true)
                .Build()
        );
        SaveCertAndKey(basePath, "root-ca", rootCert, rootKey);
 
        // Server Intermediate CA
        using var serverIntKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
        var serverIntCert = CreateIntermediateCa(
            ctx, rootCert, rootKey, serverIntKey,
            "mTLS Server Intermediate CA",
            new[] { "dns:.example.com" }  // Name Constraint
        );
        SaveCertAndKey(basePath, "server-int-ca", serverIntCert, serverIntKey);
 
        // Client Intermediate CA
        using var clientIntKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
        var clientIntCert = CreateIntermediateCa(
            ctx, rootCert, rootKey, clientIntKey,
            "mTLS Client Intermediate CA",
            null  // No name constraints for clients
        );
        SaveCertAndKey(basePath, "client-int-ca", clientIntCert, clientIntKey);
 
        Console.WriteLine("mTLS PKI created");
    }
}

2. Server Configuration

// ASP.NET Core Kestrel mTLS
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(443, listenOptions =>
    {
        listenOptions.UseHttps(httpsOptions =>
        {
            // Server certificate
            httpsOptions.ServerCertificate = new X509Certificate2(
                "server.pfx", "ServerPassword!");
 
            // Require client certificate
            httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
 
            // Accepted client CAs
            httpsOptions.ClientCertificateValidation = (cert, chain, errors) =>
            {
                // Only accept certificates from our client CA
                return ValidateClientCertificate(cert, chain);
            };
        });
    });
});
 
bool ValidateClientCertificate(X509Certificate2 cert, X509Chain? chain)
{
    // Load trusted client CA
    var trustedClientCa = new X509Certificate2("client-int-ca.crt.pem");
 
    // Build custom chain
    var customChain = new X509Chain();
    customChain.ChainPolicy.CustomTrustStore.Add(trustedClientCa);
    customChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
    customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
 
    // Check Extended Key Usage: clientAuth
    customChain.ChainPolicy.ApplicationPolicy.Add(
        new Oid("1.3.6.1.5.5.7.3.2"));
 
    return customChain.Build(cert);
}

3. Client Configuration

public HttpClient CreateMtlsClient(string clientCertPath, string clientKeyPath, string password)
{
    using var ctx = PqCryptoContext.Initialize();
 
    // Load client certificate
    var clientCert = ctx.LoadCertificateWithPrivateKey(
        clientCertPath,
        clientKeyPath,
        password
    );
 
    // Server trust store
    var trustedServerCa = ctx.LoadCertificate("server-int-ca.crt.pem");
 
    var handler = new HttpClientHandler
    {
        ClientCertificateOptions = ClientCertificateOption.Manual,
        SslProtocols = SslProtocols.Tls13,
 
        ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
        {
            var customChain = new X509Chain();
            customChain.ChainPolicy.CustomTrustStore.Add(trustedServerCa);
            customChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
 
            // Extended Key Usage: serverAuth
            customChain.ChainPolicy.ApplicationPolicy.Add(
                new Oid("1.3.6.1.5.5.7.3.1"));
 
            return customChain.Build(cert);
        }
    };
 
    handler.ClientCertificates.Add(clientCert);
 
    return new HttpClient(handler)
    {
        DefaultRequestHeaders = { { "User-Agent", "mTLS-Client/1.0" } }
    };
}

4. Nginx mTLS Reverse Proxy

server {
    listen 443 ssl http2;
    server_name api.example.com;
 
    # Server certificate
    ssl_certificate     /etc/nginx/ssl/server-chain.pem;
    ssl_certificate_key /etc/nginx/ssl/server.key.pem;
 
    # Client authentication
    ssl_client_certificate /etc/nginx/ssl/client-ca-chain.pem;
    ssl_verify_client on;
    ssl_verify_depth 2;
 
    # CRL checking
    ssl_crl /etc/nginx/ssl/client-ca.crl;
 
    # TLS 1.3
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;
 
    # OCSP Stapling for server cert
    ssl_stapling on;
    ssl_stapling_verify on;
 
    location / {
        # Forward client info to backend
        proxy_set_header X-Client-Cert-Subject $ssl_client_s_dn;
        proxy_set_header X-Client-Cert-Issuer $ssl_client_i_dn;
        proxy_set_header X-Client-Cert-Serial $ssl_client_serial;
        proxy_set_header X-Client-Cert-Fingerprint $ssl_client_fingerprint;
        proxy_set_header X-Client-Verify $ssl_client_verify;
 
        proxy_pass http://backend:8080;
    }
}

5. Kubernetes mTLS (Istio)

# PeerAuthentication - mTLS for all services in namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT  # mTLS mandatory
---
# DestinationRule - mTLS for outgoing connections
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: default
  namespace: production
spec:
  host: "*.production.svc.cluster.local"
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL  # Istio-managed certificates
---
# AuthorizationPolicy - Certificate-based authorization
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: api-access
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-server
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/frontend-service"]
        namespaces: ["production"]

6. Monitoring and Logging

public class MtlsLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<MtlsLoggingMiddleware> _logger;
 
    public MtlsLoggingMiddleware(RequestDelegate next, ILogger<MtlsLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
 
    public async Task InvokeAsync(HttpContext context)
    {
        var clientCert = context.Connection.ClientCertificate;
 
        if (clientCert != null)
        {
            _logger.LogInformation(
                "mTLS Request: Subject={Subject}, Thumbprint={Thumbprint}, " +
                "Serial={Serial}, NotAfter={NotAfter}",
                clientCert.Subject,
                clientCert.Thumbprint,
                clientCert.SerialNumber,
                clientCert.NotAfter
            );
 
            // Warning for soon-expiring certificates
            var daysUntilExpiry = (clientCert.NotAfter - DateTime.UtcNow).Days;
            if (daysUntilExpiry < 30)
            {
                _logger.LogWarning(
                    "Client certificate expires in {Days} days: {Subject}",
                    daysUntilExpiry,
                    clientCert.Subject
                );
            }
        }
 
        await _next(context);
    }
}

Industry-Specific mTLS Deployments

Industry Infrastructure Certificate Rotation Special Feature
Cloud Native Istio/Linkerd Automatic (SPIFFE) Service Mesh
Financial Sector Hardware LB 90 days HSM-backed
Healthcare On-Premise 1 year Air-gap capable
IoT Edge Gateway 2-5 years Offline capable

Relationship Scenario Description
Prerequisite 10.1 TLS Server Server side
Prerequisite 10.2 TLS Client Client side
Related 9.1 mTLS Auth Authentication
Extension 10.4 Hybrid TLS PQ upgrade

« ← 10.2 TLS Client | ↑ TLS Overview | 10.4 Hybrid TLS → »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: on 2026/01/30 at 06:52 AM