How to Implement Zero Trust Architecture on Windows Server 2025
Zero Trust is a security philosophy built on a single, uncompromising premise: no user, device, or network location is implicitly trusted. In traditional perimeter-based security, once a user or device crossed the corporate firewall, they were trusted to access internal resources freely. Zero Trust inverts this model by requiring continuous verification of identity and device health for every access request — regardless of whether it originates inside or outside the corporate network. On Windows Server 2025, Microsoft has made meaningful investments in Zero Trust-enabling technologies: Credential Guard ships enabled by default, Windows Defender Application Control (WDAC) has improved manageability, and integration with Azure Conditional Access and Microsoft Sentinel enables the verification and monitoring pillars of the model. This guide walks through implementing Zero Trust principles concretely on a Windows Server 2025 infrastructure using PowerShell, Group Policy, and Microsoft security tooling.
Prerequisites
- Windows Server 2025 domain controllers and member servers
- Microsoft Entra ID (Azure AD) tenant connected via Azure AD Connect or Cloud Sync
- Microsoft Entra ID P2 licensing for Conditional Access and Privileged Identity Management
- Microsoft Defender for Identity deployed (optional but recommended for detection)
- Microsoft Sentinel workspace (for KQL hunting and SIEM integration)
- Active Directory Administrative Tier Model already implemented (see companion guide)
- Windows Server 2025 UEFI-based hardware with Secure Boot and TPM 2.0 for Credential Guard
Step 1: Verify Explicitly — Enforce MFA for Privileged Access
The first Zero Trust pillar — Verify Explicitly — requires that every access request be authenticated with strong identity verification. For administrator accounts on Windows Server 2025, this means enforcing multi-factor authentication (MFA) at every sign-in using either Azure MFA (Entra ID Conditional Access) or Windows Hello for Business (WHfB). Passwords alone are insufficient for privileged access.
# Check Windows Hello for Business deployment status on domain-joined machines
# WHfB requires Hybrid Azure AD Join or full Azure AD Join
dsregcmd /status | Select-String "AzureAdJoined|NgcSet|WorkplaceJoined"
# Verify Credential Guard (Virtualization Based Security) is enabled
# Windows Server 2025 enables Credential Guard by default on compatible hardware
$vbsStatus = (Get-CimInstance -ClassName Win32_DeviceGuard `
-Namespace "rootMicrosoftWindowsDeviceGuard")
Write-Host "VBS Running: $($vbsStatus.VirtualizationBasedSecurityStatus)"
Write-Host "Credential Guard Running: $($vbsStatus.SecurityServicesRunning -contains 1)"
Write-Host "HVCI Running: $($vbsStatus.SecurityServicesRunning -contains 2)"
# If Credential Guard is not running, enable it via DISM (requires restart + TPM 2.0 + Secure Boot)
# This enables both Credential Guard and HVCI (Hypervisor-Protected Code Integrity)
$dgArgs = @(
"/Online",
"/Enable-Feature",
"/FeatureName:IsolatedUserMode",
"/All",
"/NoRestart"
)
& "$env:SystemRootsystem32Dism.exe" @dgArgs
# Enable via registry (alternative method, requires reboot)
$lsaCfgPath = "HKLM:SYSTEMCurrentControlSetControlLSA"
Set-ItemProperty -Path $lsaCfgPath -Name "LsaCfgFlags" -Value 1 -Type DWord
Write-Host "Credential Guard registry flag set. Reboot required."
Step 2: Verify Explicitly — Configure Conditional Access for Server Management
Azure Conditional Access policies enforce context-aware MFA requirements at sign-in time. For server management scenarios — such as signing in to Azure portal, Windows Admin Center (cloud-connected), or Remote Desktop via Entra ID authentication — configure policies that require MFA, a compliant device, and restrict sign-in to approved locations or named networks.
# Install Microsoft Graph PowerShell for Conditional Access management
Install-Module Microsoft.Graph -Scope CurrentUser -Force
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess","Policy.Read.All"
# Create a Conditional Access policy requiring MFA for all admin roles
$caPolicy = @{
displayName = "Require MFA for Privileged Roles"
state = "enabled"
conditions = @{
users = @{
includeRoles = @(
"62e90394-69f5-4237-9190-012177145e10", # Global Administrator
"194ae4cb-b126-40b2-bd5b-6091b380977d", # Security Administrator
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c" # SharePoint Administrator
)
}
applications = @{
includeApplications = @("All")
}
platforms = @{
includePlatforms = @("all")
}
}
grantControls = @{
operator = "AND"
builtInControls = @("mfa", "compliantDevice")
}
}
$newPolicy = New-MgIdentityConditionalAccessPolicy -BodyParameter $caPolicy
Write-Host "Created CA Policy: $($newPolicy.Id) — $($newPolicy.DisplayName)"
# Verify the policy is in enabled state
Get-MgIdentityConditionalAccessPolicy |
Where-Object { $_.DisplayName -like "*MFA*" } |
Select-Object DisplayName, State, Id
Step 3: Use Least Privilege — Implement Just Enough Administration (JEA)
Just Enough Administration (JEA) is a PowerShell remoting technology that allows operators to run specific administrative commands on servers without being a local administrator. A JEA endpoint defines a constrained session that limits the user to a curated set of cmdlets and parameters. This enforces least-privilege access: a storage team member can manage disk volumes without being able to run arbitrary code or read sensitive files.
# Create a JEA Role Capability file defining allowed commands for storage admins
$roleCapPath = "C:Program FilesWindowsPowerShellModulesJEAStorageRoleCapabilities"
New-Item -ItemType Directory -Path $roleCapPath -Force
New-PSRoleCapabilityFile -Path "$roleCapPathStorageAdmin.psrc" `
-VisibleCmdlets @(
"Get-Disk", "Get-Partition", "Get-Volume",
"Initialize-Disk", "New-Partition", "Format-Volume",
@{ Name = "Set-Volume"; Parameters = @{ Name = "DriveLetter" } },
"Repair-Volume", "Get-StoragePool"
) `
-VisibleExternalCommands @("C:WindowsSystem32diskpart.exe") `
-Description "Storage management role for JEA — no general server admin access"
# Create the JEA Session Configuration file
$sessionConfigPath = "C:JEAStorageAdminSession.pssc"
New-Item -ItemType Directory -Path "C:JEA" -Force
New-PSSessionConfigurationFile -Path $sessionConfigPath `
-SessionType RestrictedRemoteServer `
-RunAsVirtualAccount $true `
-RoleDefinitions @{
"progressiverobotStorageAdmins" = @{ RoleCapabilities = "StorageAdmin" }
} `
-TranscriptDirectory "C:JEATranscripts" `
-Description "JEA endpoint for storage administration"
# Register the JEA endpoint
Register-PSSessionConfiguration -Name "StorageAdmin" `
-Path $sessionConfigPath `
-Force `
-RunAsCredential (Get-Credential -Message "JEA virtual account credential")
# Verify the endpoint is registered and accessible
Get-PSSessionConfiguration -Name "StorageAdmin" | Select-Object Name, Enabled, Permission
# Test the JEA session as a storage admin user
Enter-PSSession -ComputerName "SRV-Storage01" `
-ConfigurationName "StorageAdmin" `
-Credential (Get-Credential "progressiverobotT1-StorageAdmin")
Step 4: Use Least Privilege — Application Allow-Listing with WDAC
Windows Defender Application Control (WDAC) enforces code integrity policies that prevent unauthorized executables, scripts, and DLLs from running on your servers — even if an attacker gains a foothold. On Windows Server 2025, WDAC policies are deployed via GPO or MDM and can be set to Audit mode first, then enforced after reviewing logs.
# Create a WDAC policy based on the default Windows Allow rules + your trusted software
# Start with the built-in example policy
$examplePolicyPath = "C:WindowsschemasCodeIntegrityExamplePoliciesAllowMicrosoft.xml"
$newPolicyPath = "C:WDACServerBasePolicy.xml"
New-Item -ItemType Directory -Path "C:WDAC" -Force
Copy-Item $examplePolicyPath $newPolicyPath
# Add a rule allowing your organization's signed software (by publisher certificate)
$publisherLevel = "Publisher"
Add-SignerRule -FilePath $newPolicyPath `
-CertificatePath "C:CertsOrgCodeSigning.cer" `
-Kernel -User -Update
# Set policy to Audit mode first (EventID 3076 = would-have-blocked, 3077 = blocked)
Set-RuleOption -FilePath $newPolicyPath -Option 3 # Enabled:Audit Mode (Default)
# Convert XML policy to binary format for deployment
$binaryPolicyPath = "C:WDACServerBasePolicy.bin"
ConvertFrom-CIPolicy -XmlFilePath $newPolicyPath -BinaryFilePath $binaryPolicyPath
# Deploy via GPO (Computer Configuration → Windows Settings → Security Settings → Application Control)
# Or copy directly to the CI policy directory
$ciPolicyDir = "$env:SystemRootSystem32CodeIntegrityCiPoliciesActive"
Copy-Item $binaryPolicyPath "$ciPolicyDir{GUID}.cip"
# Review WDAC audit events (would-block events in audit mode)
Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" |
Where-Object { $_.Id -in @(3076, 3077) } |
Select-Object TimeCreated, Id, @{N="File";E={$_.Properties[1].Value}} |
Sort-Object TimeCreated -Descending |
Select-Object -First 20
Step 5: Assume Breach — Network Micro-Segmentation with Windows Defender Firewall
The Assume Breach pillar of Zero Trust requires that you design defenses as if an attacker is already inside your network. Host-based firewall rules on every Windows Server 2025 machine provide micro-segmentation without requiring network hardware changes. By restricting which source IPs and ports can connect to each server, you limit lateral movement even if a server is compromised.
# Enable Windows Defender Firewall on all profiles
Set-NetFirewallProfile -Profile Domain, Private, Public -Enabled True
# Block all inbound connections by default, then allow only what is needed
Set-NetFirewallProfile -Profile Domain -DefaultInboundAction Block -DefaultOutboundAction Allow
# Allow RDP only from PAW subnet (Tier 1 admin workstations at 10.10.1.0/24)
New-NetFirewallRule `
-DisplayName "Allow RDP from T1 PAW subnet only" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 3389 `
-RemoteAddress "10.10.1.0/24" `
-Action Allow `
-Profile Domain `
-Enabled True
# Allow WinRM (PowerShell remoting) only from management jump servers
New-NetFirewallRule `
-DisplayName "Allow WinRM from Jump Servers" `
-Direction Inbound `
-Protocol TCP `
-LocalPort @(5985, 5986) `
-RemoteAddress @("10.10.1.10", "10.10.1.11") `
-Action Allow `
-Profile Domain `
-Enabled True
# Block SMB lateral movement (prevent non-admin machines from connecting to file shares)
New-NetFirewallRule `
-DisplayName "Block SMB from Workstations" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 445 `
-RemoteAddress "10.20.0.0/16" `
-Action Block `
-Profile Domain `
-Enabled True
# Export current firewall rules for documentation/audit
Get-NetFirewallRule | Where-Object { $_.Enabled -eq "True" } |
Select-Object DisplayName, Direction, Action, Profile |
Export-Csv "C:ReportsFirewallRules-$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
Step 6: Assume Breach — Continuous Monitoring with Microsoft Sentinel KQL
Continuous monitoring is the operational backbone of Zero Trust. Microsoft Sentinel, connected to your Windows Security event logs via the Azure Monitor Agent (AMA), enables advanced threat hunting using KQL (Kusto Query Language). The following queries help detect common attack patterns on Windows Server 2025.
# Deploy Azure Monitor Agent on Windows Server 2025 for Sentinel data collection
# First, ensure the server is Azure Arc-enabled or Azure VM
$arcInstallUrl = "https://aka.ms/AzureConnectedMachineAgent"
# Download and install the Arc agent, then run:
# azcmagent connect --subscription-id --resource-group --location eastus
# Enable Security event log collection via DCR (Data Collection Rule)
# This is typically done via Azure portal or ARM template
# KQL Query 1: Detect Pass-the-Hash attacks (NTLM logon with no workstation name)
$kqlPtH = @'
SecurityEvent
| where EventID == 4624
| where LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where WorkstationName == "-"
| where TargetUserName !endswith "$"
| summarize Count = count(), Computers = make_set(Computer) by TargetUserName, IpAddress
| where Count > 5
| order by Count desc
'@
# KQL Query 2: Detect Kerberoasting (TGS requests for service accounts)
$kqlKerberoast = @'
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17" // RC4 — weak encryption used in Kerberoasting
| where ServiceName !endswith "$"
| where ServiceName != "krbtgt"
| summarize Count = count() by TargetUserName, ServiceName, IpAddress, Computer
| where Count > 3
| order by Count desc
'@
# KQL Query 3: Privileged group changes (additions to Domain Admins)
$kqlPrivGroupChange = @'
SecurityEvent
| where EventID == 4728 or EventID == 4732 or EventID == 4756
| where TargetUserName in ("Domain Admins","Enterprise Admins","Schema Admins","Administrators")
| project TimeGenerated, SubjectUserName, MemberName, TargetUserName, Computer
| order by TimeGenerated desc
'@
Write-Host "KQL queries ready for use in Microsoft Sentinel Hunting."
Write-Host "Navigate to: Sentinel → Hunting → New Query and paste each query."
# Local monitoring: audit privileged logons via event log
Get-WinEvent -LogName Security -FilterXPath `
"*[System[EventID=4624] and EventData[Data[@Name='LogonType']='2' or Data[@Name='LogonType']='10']]" `
-MaxEvents 100 |
Select-Object TimeCreated,
@{N="User";E={$_.Properties[5].Value}},
@{N="LogonType";E={$_.Properties[8].Value}},
@{N="SourceIP";E={$_.Properties[18].Value}}
Conclusion
Implementing Zero Trust on Windows Server 2025 is not a single product or switch — it is a combination of enforced MFA through Conditional Access, least-privilege access via JEA and WDAC application allow-listing, assumed-breach design through Credential Guard and host-based firewall micro-segmentation, and continuous monitoring via Microsoft Sentinel KQL hunting. Each layer independently reduces your attack surface; together they create a defense-in-depth architecture where compromising any single control does not result in a full breach. Start with Credential Guard and Conditional Access MFA for the fastest wins, then layer in JEA, WDAC in audit mode, and finally tighten firewall rules and activate Sentinel hunting queries over time. Zero Trust is a journey, not a destination — measure your progress against the CISA Zero Trust Maturity Model and revisit your controls as your environment and threat landscape evolve.