Zero Trust Principles on Windows Server 2019
Zero Trust is a security philosophy that abandons the assumption of implicit trust inside a network perimeter. Instead, every access request—whether from inside or outside the datacenter—must be verified, authorized, and continuously validated. On Windows Server 2019, Zero Trust is implemented through a layered set of controls: strong identity verification, device health attestation, least-privilege access, network micro-segmentation, encryption in transit, and continuous monitoring. This guide covers the concrete technical steps to deploy each layer.
Pillar 1: Verify Identity — Multi-Factor Authentication and Protected Users
Start by ensuring that administrative accounts can never be authenticated with only a password. Enroll all privileged accounts in Azure AD Conditional Access MFA or configure AD FS with an MFA adapter for on-premises resources:
# Enforce MFA for admin accounts via Protected Users group
Add-ADGroupMember -Identity 'Protected Users' -Members (
Get-ADUser -Filter * -SearchBase 'OU=Accounts,OU=Admin,DC=corp,DC=local' |
Select-Object -ExpandProperty SamAccountName
)
# Configure fine-grained password policy for admin accounts
# Requires a Password Settings Object (PSO)
New-ADFineGrainedPasswordPolicy `
-Name 'PSO-AdminAccounts' `
-Precedence 1 `
-MinPasswordLength 16 `
-PasswordHistoryCount 24 `
-ComplexityEnabled $true `
-ReversibleEncryptionEnabled $false `
-MaxPasswordAge '60.00:00:00' `
-MinPasswordAge '1.00:00:00' `
-LockoutThreshold 3 `
-LockoutDuration '00:30:00' `
-LockoutObservationWindow '00:30:00'
Add-ADFineGrainedPasswordPolicySubject `
-Identity 'PSO-AdminAccounts' `
-Subjects (Get-ADGroup 'Domain Admins'), (Get-ADGroup 'Tier0-AdminAccounts')
Pillar 2: Verify Devices — Windows Defender Credential Guard and TPM Attestation
Zero Trust requires that devices be healthy before granting access. Enable Credential Guard on Windows Server 2019 to protect NTLM hashes and Kerberos tickets from extraction by credential-theft tools like Mimikatz:
# Enable Credential Guard via registry (GPO is preferred for fleet deployment)
$devGuardPath = 'HKLM:SYSTEMCurrentControlSetControlDeviceGuard'
Set-ItemProperty $devGuardPath -Name 'EnableVirtualizationBasedSecurity' -Value 1
Set-ItemProperty $devGuardPath -Name 'RequirePlatformSecurityFeatures' -Value 3 # Secure Boot + DMA
$lsaPath = 'HKLM:SYSTEMCurrentControlSetControlLsa'
Set-ItemProperty $lsaPath -Name 'LsaCfgFlags' -Value 1 # 1=enabled, 2=enabled+UEFI lock
# Verify after reboot
$cg = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace rootMicrosoftWindowsDeviceGuard
$cg.SecurityServicesRunning # should include 1 (Credential Guard)
$cg.VirtualizationBasedSecurityStatus # 2 = running
# Enable Windows Defender Exploit Guard - Attack Surface Reduction
# ASR rules prevent credential theft via LSASS
Add-MpPreference -AttackSurfaceReductionRules_Ids '9e6c4e1f-7d60-472f-ba1a-a39ef669e4b3' `
-AttackSurfaceReductionRules_Actions Enabled # Block credential stealing from LSASS
# Verify ASR rules
Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids
Pillar 3: Least Privilege Access — JEA and RBAC
Remove standing administrative access and enforce just-enough privilege through Just Enough Administration (JEA) endpoints and Role-Based Access Control:
# Remove Domain Users from local Administrators on servers via GPO
# Computer Configuration > Preferences > Windows Settings > Groups
# Action: Update, Group name: Administrators
# Delete all member users, add only specific service accounts
# Verify local admins on a server
$computer = 'SRV-APP01'
Invoke-Command -ComputerName $computer -ScriptBlock {
Get-LocalGroupMember -Group 'Administrators'
}
# Deploy JEA endpoint (see post228 for full JEA setup)
# Confirm only the constrained endpoint is accessible
Get-PSSessionConfiguration | Select-Object Name, Enabled, Permission
# Audit privileged group membership changes (Event ID 4728, 4732, 4756)
Get-WinEvent -LogName Security -FilterXPath `
"*[System[(EventID=4728 or EventID=4732 or EventID=4756)]]" |
Select-Object TimeCreated, Message -First 20
Pillar 4: Network Micro-Segmentation with Windows Firewall
In a Zero Trust model, servers should only accept connections from explicitly authorized sources. Use Windows Firewall with Advanced Security to enforce host-level micro-segmentation, eliminating implicit east-west trust:
# Enable Windows Firewall on all profiles
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
# Block all inbound by default (whitelist only what is needed)
Set-NetFirewallProfile -Profile Domain -DefaultInboundAction Block -DefaultOutboundAction Allow
# Allow RDP only from management VLAN (192.168.100.0/24)
New-NetFirewallRule -DisplayName 'Allow RDP from Mgmt VLAN' `
-Direction Inbound -Protocol TCP -LocalPort 3389 `
-RemoteAddress '192.168.100.0/24' -Action Allow -Profile Domain
# Allow WinRM only from management hosts
New-NetFirewallRule -DisplayName 'Allow WinRM from Mgmt VLAN' `
-Direction Inbound -Protocol TCP -LocalPort 5985,5986 `
-RemoteAddress '192.168.100.0/24' -Action Allow -Profile Domain
# Block SMB between servers (prevent lateral movement via file shares)
New-NetFirewallRule -DisplayName 'Block SMB inbound from servers' `
-Direction Inbound -Protocol TCP -LocalPort 445 `
-RemoteAddress '10.0.0.0/8' -Action Block -Profile Domain
# Allow SMB only from specific management server
New-NetFirewallRule -DisplayName 'Allow SMB from file server' `
-Direction Inbound -Protocol TCP -LocalPort 445 `
-RemoteAddress '10.0.1.5' -Action Allow -Profile Domain
# Export current firewall rules for auditing
Get-NetFirewallRule | Where-Object { $_.Enabled -eq 'True' } |
Select-Object DisplayName, Direction, Action, Protocol |
Export-Csv 'C:ReportsFirewallRules.csv' -NoTypeInformation
Pillar 5: Encrypt All Communications
Zero Trust assumes the network is hostile. Enforce TLS for all management traffic and SMB signing/encryption for file communications:
# Enforce WinRM over HTTPS only
winrm delete winrm/config/listener?Address=*+Transport=HTTP 2>$null
$httpsListenerCert = (Get-ChildItem 'Cert:LocalMachineMy' |
Where-Object { $_.Subject -like "*$env:COMPUTERNAME*" })[0]
New-Item -Path WSMan:localhostListener -Transport HTTPS `
-Address * `
-CertificateThumbPrint $httpsListenerCert.Thumbprint -Force
# Enforce SMB signing (prevents relay attacks)
Set-SmbServerConfiguration -RequireSecuritySignature $true -Force
Set-SmbClientConfiguration -RequireSecuritySignature $true -Force
# Enforce SMB encryption for all shares (Server 2019)
Set-SmbServerConfiguration -EncryptData $true -Force
# Disable obsolete protocols via registry
# Disable SSL 3.0
New-Item 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -Force
Set-ItemProperty 'HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0Server' -Name 'Enabled' -Value 0
# Disable TLS 1.0 and 1.1
foreach ($ver in '1.0','1.1') {
$path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS $verServer"
New-Item $path -Force
Set-ItemProperty $path -Name 'Enabled' -Value 0
Set-ItemProperty $path -Name 'DisabledByDefault' -Value 1
}
# Verify using SSL Labs or PowerShell
[Net.ServicePointManager]::SecurityProtocol
Pillar 6: Continuous Monitoring and Audit Logging
# Enable comprehensive audit policy
auditpol /set /category:"Account Logon" /success:enable /failure:enable
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable
auditpol /set /category:"Object Access" /success:enable /failure:enable
auditpol /set /category:"Privilege Use" /success:enable /failure:enable
auditpol /set /category:"Policy Change" /success:enable /failure:enable
auditpol /set /category:"Account Management" /success:enable /failure:enable
auditpol /set /category:"DS Access" /success:enable /failure:enable
auditpol /set /category:"System" /success:enable /failure:enable
auditpol /get /category:*
# Increase security event log size
Limit-EventLog -LogName Security -MaximumSize 500MB
wevtutil sl Security /ms:524288000 /rt:false
# Forward events to a SIEM (Windows Event Collector)
wecutil qc /quiet # configure WEC
# Create a subscription to collect security events from all servers
# wecutil cs subscription.xml
# PowerShell monitoring: alert on Event ID 4625 brute force attempts
$threshold = 10
$timeWindow = (Get-Date).AddMinutes(-15)
$failedLogons = Get-WinEvent -FilterHashtable @{
LogName = 'Security'; Id = 4625; StartTime = $timeWindow
} | Group-Object { ($_.Properties[5]).Value } |
Where-Object { $_.Count -ge $threshold }
if ($failedLogons) {
$failedLogons | ForEach-Object {
Write-Warning "Possible brute force: $($_.Name) - $($_.Count) failed attempts in 15 min"
}
}
Pillar 7: Application Control with AppLocker
# Configure AppLocker to allow only approved executables on servers
# Enable AppLocker service
Set-Service AppIDSvc -StartupType Automatic
Start-Service AppIDSvc
# Generate default rules (allows built-in OS executables)
Get-AppLockerPolicy -Local | Test-AppLockerPolicy -Path 'C:WindowsSystem32cmd.exe'
# Create an AppLocker policy that allows only signed Microsoft and trusted apps
$policy = New-Object -TypeName Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel.AppLockerPolicy
# Configure via GPO:
# Computer Configuration > Windows Settings > Security Settings > Application Control Policies > AppLocker
# Executable Rules > Create Default Rules > Add publisher conditions for approved software
# Audit mode first to identify what would be blocked
Set-AppLockerPolicy -XmlPolicy (Get-Content 'C:AppLockerPolicy.xml' -Raw) -Merge
Get-AppLockerFileInformation -Path 'C:Program Files' -Recurse |
Test-AppLockerPolicy -XmlPolicy (Get-AppLockerPolicy -Local -Xml)
Conclusion
Zero Trust on Windows Server 2019 is not a single product or feature—it is the combination of identity protection via Protected Users and MFA, device hardening through Credential Guard, host-level micro-segmentation with Windows Firewall, encryption enforcement for all management traffic, comprehensive audit logging, and application control via AppLocker. Each layer independently reduces risk; together they create an architecture where a single compromised component cannot result in full environment compromise.