How to Configure Windows Server 2019 Container Security

Securing Windows containers on Windows Server 2019 involves hardening the container runtime, securing container images, isolating workloads, controlling network access, and monitoring for anomalous behavior. The default Docker installation is functional but not hardened for production use. This guide covers the key security controls available for Windows containers on Windows Server 2019 and the specific configurations required to implement them.

Choosing the Right Isolation Mode

The first and most fundamental security decision is choosing between process isolation and Hyper-V isolation. Process-isolated containers share the host kernel — a kernel exploit in a container can potentially compromise the host. Hyper-V containers run with a dedicated kernel in a lightweight VM, providing strong isolation. For security-sensitive workloads, always use Hyper-V isolation:

docker run --isolation=hyperv --name secure_app mcr.microsoft.com/windows/servercore:ltsc2019 cmd

Enforce Hyper-V isolation as the default in the Docker daemon configuration:

$config = @{ "exec-opts" = @("isolation=hyperv") } | ConvertTo-Json
Set-Content "C:ProgramDatadockerconfigdaemon.json" $config
Restart-Service docker

Running Containers as Non-Administrator

By default, Windows containers run processes as ContainerAdministrator, which has elevated privileges inside the container. Use ContainerUser for non-privileged containers where possible:

docker run --user ContainerUser --isolation=hyperv mcr.microsoft.com/windows/servercore:ltsc2019 whoami

In a Dockerfile, switch to ContainerUser for the application process:

FROM mcr.microsoft.com/windows/servercore:ltsc2019

# Create a dedicated service account
RUN net user appservice /add /passwordreq:yes
RUN net localgroup "IIS_IUSRS" appservice /add

# Copy application
COPY ./app C:/app

# Drop to non-admin user
USER appservice
WORKDIR C:/app
ENTRYPOINT ["C:/app/MyApp.exe"]

Securing the Docker Daemon

The Docker daemon socket (named pipe on Windows) provides root-equivalent access. Restrict access to the Docker pipe to the Administrators group only and enable TLS for remote Docker API access:

$acl = Get-Acl "\.pipedocker_engine"
$acl | Format-List

Enable TLS for the Docker daemon to secure remote management. Generate TLS certificates and configure the daemon:

@"
{
    "tlsverify": true,
    "tlscacert": "C:/docker-tls/ca.pem",
    "tlscert": "C:/docker-tls/server-cert.pem",
    "tlskey": "C:/docker-tls/server-key.pem",
    "hosts": ["tcp://0.0.0.0:2376", "npipe://"],
    "exec-opts": ["isolation=hyperv"]
}
"@ | Set-Content "C:ProgramDatadockerconfigdaemon.json"
Restart-Service docker

Implementing Read-Only Container Filesystems

Running containers with a read-only root filesystem prevents attackers from writing malicious files or modifying application binaries. Mount only specific paths as writable:

docker run `
    --read-only `
    --isolation=hyperv `
    --tmpfs C:/Temp `
    -v AppLogs:C:/Logs `
    --name readonly_app `
    contoso/myapp:v1

Network Security for Containers

Isolate container networks to restrict lateral movement. Create separate networks for frontend and backend tiers:

docker network create --driver nat --subnet 172.21.0.0/24 frontend-net
docker network create --driver nat --subnet 172.22.0.0/24 backend-net

Apply Windows Firewall rules to restrict outbound traffic from the container network. Block all outbound connections from the container subnet except required services:

New-NetFirewallRule `
    -DisplayName "Container Outbound - Block Default" `
    -Direction Outbound `
    -RemoteAddress "172.21.0.0/24" `
    -Action Block `
    -Priority 1000

New-NetFirewallRule `
    -DisplayName "Container Outbound - Allow HTTPS" `
    -Direction Outbound `
    -RemoteAddress "172.21.0.0/24" `
    -RemotePort 443 `
    -Protocol TCP `
    -Action Allow `
    -Priority 900

Image Security Scanning

Scan container images for known vulnerabilities before deploying them to production. Use Trivy, the open-source vulnerability scanner, to scan Windows images:

Invoke-WebRequest -Uri "https://github.com/aquasecurity/trivy/releases/download/v0.48.0/trivy_0.48.0_windows-64bit.zip" -OutFile "C:trivy.zip"
Expand-Archive "C:trivy.zip" -DestinationPath "C:trivy"

C:trivytrivy.exe image --severity HIGH,CRITICAL mcr.microsoft.com/windows/servercore:ltsc2019
C:trivytrivy.exe image --format json --output C:scan-results.json contoso/myapp:v1

Group Managed Service Accounts for Containers

Group Managed Service Accounts (gMSA) allow Windows containers to authenticate to Active Directory resources like SQL Server and file shares without storing credentials in environment variables. Configure gMSA for containers:

Install-Module -Name CredentialSpec -Force

New-GMSACredentialSpec `
    -Name "WebApp_gMSA" `
    -AccountName "svc_webapp$" `
    -Domain contoso.local `
    -Path "C:ProgramDatadockercredentialspecswebapp_credspec.json"

Run a container with the gMSA credential spec:

docker run `
    --security-opt "credentialspec=file://webapp_credspec.json" `
    --hostname webapp01 `
    --isolation=hyperv `
    -d contoso/webapp:v1

Security Auditing and Logging

Enable Docker audit logging to record all Docker daemon activity. Configure comprehensive logging in the daemon:

@"
{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "5"
    },
    "debug": false,
    "log-level": "warn",
    "exec-opts": ["isolation=hyperv"],
    "no-new-privileges": true
}
"@ | Set-Content "C:ProgramDatadockerconfigdaemon.json"

Monitor Docker events for security-relevant activities:

docker events `
    --filter "type=container" `
    --filter "event=exec_start" `
    --filter "event=exec_create" `
    --format "{{json .}}"

Container security on Windows Server 2019 is a multi-layered discipline. Using Hyper-V isolation for strong boundaries, gMSA for AD integration, non-admin users for least privilege, read-only filesystems where possible, and continuous image scanning creates a defense-in-depth posture that significantly reduces your container attack surface.