Skip to content

Domain controller hardening: the DC baseline

A practical checklist for hardening domain controllers: security baselines, Print Spooler, logon rights, RDP, egress, and patch priorities.

Florian Amette6 min read

Domain controllers are the single highest-value target in most Windows environments: compromise one and an attacker effectively owns the domain. Yet DCs are frequently treated like ordinary member servers — left with default roles enabled, reachable over RDP by half the helpdesk, and allowed to browse the internet for "convenience." This guide walks through the concrete configuration steps that shrink a DC's attack surface to what it actually needs: authentication, replication, and DNS.

Everything below is additive to your existing patching cadence, not a replacement for it. Treat this as the minimum bar for any DC, whether you run two or two hundred.

Apply the Microsoft security baseline

Start from Microsoft's published Security Compliance Toolkit baseline for the Domain Controller role rather than inventing your own policy from scratch. The baseline GPOs encode Microsoft's current guidance for audit policy, User Rights Assignment, and security options, and they are versioned per Windows Server release.

  1. Download the current Security Compliance Toolkit (SCT) and the matching Windows Server security baseline for your DC OS version from Microsoft.
  2. Import the baseline GPOs into your domain (linked to a test OU first) using the package's Baseline-ADImport.ps1 script or the Group Policy Management Console (GPMC) Import Settings wizard. LGPO.exe only applies settings to the local policy of a single test machine.
  3. Diff the baseline against your current DC GPOs using Get-GPOReport -ReportType Html before rollout, so you know exactly what will change.
  4. Link the baseline GPO to an OU containing only domain controllers (normally the built-in Domain Controllers OU), never to the domain root.
PowerShell
# Export current DC-linked GPOs for comparison before importing the baseline
Get-GPO -All | Where-Object { (Get-GPInheritance -Target "OU=Domain Controllers,DC=corp,DC=example,DC=com").GpoLinks.DisplayName -contains $_.DisplayName } |
    ForEach-Object { Get-GPOReport -Guid $_.Id -ReportType Html -Path "C:\GPOBackup\$($_.DisplayName).html" }

Re-run the baseline import each time Microsoft ships an update; treat it like patch management, not a one-time project.

Disable the Print Spooler service on DCs

The Print Spooler service has been the entry point for multiple critical vulnerabilities, most notably PrintNightmare (CVE-2021-34527), plus a long tail of point-and-print driver-installation issues and coercion abuse (spooler-based RPC coercion feeding into NTLM relay). None of this functionality is needed on a domain controller.

PowerShell
# Disable and stop the Print Spooler on all DCs
Get-ADDomainController -Filter * | ForEach-Object {
    Invoke-Command -ComputerName $_.HostName -ScriptBlock {
        Stop-Service -Name Spooler -Force
        Set-Service -Name Spooler -StartupType Disabled
    }
}

Enforce this centrally via GPO so it survives reboots and re-provisioning:

  • Computer Configuration → Policies → Windows Settings → Security Settings → System Services → Print Spooler → set to Disabled.

Verify:

PowerShell
Get-ADDomainController -Filter * | ForEach-Object {
    Get-Service -ComputerName $_.HostName -Name Spooler | Select-Object MachineName, Status, StartType
}

If a legacy application genuinely requires print services on a server, that is a job for a dedicated, non-DC print server — never a domain controller.

Restrict local and RDP logon to Tier 0 only

Every account that can log on interactively or over RDP to a DC is, functionally, a Domain Admin. Apply the User Rights Assignment settings below through a GPO linked to the Domain Controllers OU, and populate them with a dedicated Tier 0 admin group rather than broad groups like Domain Admins or Server Admins.

RightGPO pathRecommended membership
Allow log on locallyComputer Configuration → Windows Settings → Security Settings → Local Policies → User Rights AssignmentTier 0 Admins only
Allow log on through Remote Desktop Services(same path)Tier 0 Admins only (small, named group)
Deny log on through Remote Desktop Services(same path)All non-Tier-0 admin groups (not Domain Users: Tier 0 admins are members too, and deny overrides allow)
Deny access to this computer from the network(same path)Local accounts and Tier 1/Tier 2 admin groups (never Domain Users: every user and computer needs network logon to DCs for SYSVOL and Group Policy)
PowerShell
# Verify current Allow log on through RDS membership on a DC
$dc = "DC01"
secedit /export /cfg C:\Temp\dc01-secpol.cfg /areas USER_RIGHTS
Select-String -Path C:\Temp\dc01-secpol.cfg -Pattern "SeRemoteInteractiveLogonRight"

Pair this with the Tier 0 & privileged access model: Tier 0 admins should connect from Privileged Access Workstations, not from their day-to-day laptops, and standing RDP access should be replaced with just-in-time elevation where possible.

Block outbound internet access from domain controllers

A DC has no legitimate reason to browse arbitrary internet hosts. Outbound access is a common post-compromise channel for command-and-control callbacks and data staging. Restrict DC egress at the network firewall to only what is operationally required:

  • Windows Update / WSUS or a patch management endpoint
  • NTP/time sync sources (if not using an internal time hierarchy)
  • Certificate revocation/OCSP endpoints if publicly hosted
  • Any required directory-sync endpoints (e.g., Entra Connect, if not co-located)
Text
# Example firewall intent (implement in your perimeter/NGFW, not just Windows Firewall)
DENY  DC-subnet -> ANY (0.0.0.0/0)  port 80,443   [default deny]
ALLOW DC-subnet -> WSUS-server      port 8530,8531
ALLOW DC-subnet -> approved-NTP     port 123

Do not rely solely on Windows Defender Firewall for this — enforce it at the network layer so a local policy change on the DC cannot silently reopen egress.

Patch priorities: ZeroLogon, PetitPotam/coercion, PrintNightmare

Three vulnerability classes deserve standing priority in your patch cycle because each one can lead directly to domain compromise:

ZeroLogon (CVE-2020-1472) — exploits a flaw in the Netlogon secure channel to reset a DC's machine account password. Patch fully (the initial 2020 patch plus the enforcement phase that requires all Netlogon clients to use secure RPC) and confirm enforcement mode:

PowerShell
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" -Name "FullSecureChannelProtection" -ErrorAction SilentlyContinue

See ZeroLogon for background on the vulnerability itself.

PetitPotam and other coercion techniques — abuse RPC/DCOM interfaces to coerce a DC into authenticating to an attacker-controlled endpoint, typically feeding an NTLM relay attack against AD CS or LDAP. Mitigations:

  • Enable Extended Protection for Authentication (EPA) on AD CS web enrollment endpoints and LDAP.
  • Disable NTLM where feasible, or at minimum enforce LDAP/LDAPS signing and channel binding.
  • Deploy RPC filters to block unauthenticated calls to EFSRPC/MS-RPRN-style interfaces from non-DC hosts where not required.

PrintNightmare — covered above via Spooler disablement; patch regardless, since some subsidiary print-driver CVEs affect non-spooler code paths too.

Track these three CVE families as "patch within 72 hours of release" items in your vulnerability management SLA, separate from routine Patch Tuesday cadence.

Secure time synchronization (w32time)

Kerberos depends on time synchronization within a 5-minute skew by default; an attacker who can manipulate a DC's clock can disrupt authentication or create conditions for ticket replay. Ensure your PDC Emulator syncs to a trusted external time source and all other DCs sync to the domain hierarchy — never let DCs sync independently to arbitrary internet NTP servers.

PowerShell
# On the PDC Emulator
w32tm /config /manualpeerlist:"time.windows.com,0x8 pool.ntp.org,0x8" /syncfromflags:manual /reliable:yes /update
Restart-Service w32time

# Verify
w32tm /query /status
w32tm /query /source

Disable unnecessary roles and features

Audit each DC with Get-WindowsFeature and remove anything beyond AD DS, DNS, and required management tools. Common offenders: IIS left installed from an old CA install, Telnet Client, SMB1, and unused file-sharing roles.

PowerShell
Get-WindowsFeature | Where-Object Installed -eq $true | Select-Object Name, InstallState
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart

Verification summary

PowerShell
# Quick DC hardening health check
Get-ADDomainController -Filter * | ForEach-Object {
    $dc = $_.HostName
    [PSCustomObject]@{
        DC              = $dc
        SpoolerRunning  = (Get-Service -ComputerName $dc -Name Spooler).Status
        SMB1Enabled     = (Get-SmbServerConfiguration -CimSession $dc).EnableSMB1Protocol
        TimeSource      = (w32tm /query /source /computer:$dc)
    }
}

What it breaks

  • Management tooling that RDPs directly to DCs. Some backup, monitoring, or patching agents assume interactive RDP or unrestricted local logon. Re-point these to service accounts with explicitly delegated rights, or move to agent-based management that doesn't require interactive logon rights.
  • Legacy print-dependent tooling that (incorrectly) used a DC as a fallback print server.
  • Third-party monitoring agents that phone home over the internet directly from the DC; these need to be routed through an approved proxy or moved off-box.
  • NTLM-relay-adjacent integrations that relied on unsigned LDAP or non-EPA-aware AD CS enrollment; these need to be updated to support signing/channel binding before you enforce it domain-wide.

Combine this hardening with the practices in Kerberos hardening and Object & ACL security — a hardened DC OS is only half the picture if the directory's ACLs and Kerberos configuration are still permissive.

Frequently asked questions

Should the Print Spooler service be disabled on all domain controllers?

Yes, unless a DC genuinely acts as a print server, which it should not. Disabling the Spooler service removes the PrintNightmare (CVE-2021-34527) and point-and-print driver-installation attack surface entirely, and is a standard Microsoft and CIS recommendation for DCs.

Can administrators still RDP to domain controllers after this hardening?

Only accounts explicitly granted the Allow log on through Remote Desktop Services right, which should be limited to a small Tier 0 admin group. Everyone else should manage DCs through Windows Admin Center, PowerShell remoting from a Privileged Access Workstation, or Just Enough Administration endpoints instead of interactive RDP.

Why do domain controllers need to be blocked from outbound internet access?

DCs hold the domain's credential material and have no legitimate need to browse the web or reach arbitrary internet hosts. Blocking outbound access (except to required Microsoft update or time endpoints) closes a common command-and-control and data-exfiltration path used once a DC is compromised.

Domain controller hardening: the DC baseline

Related guides

Group Policy & SYSVOL

Deploying Microsoft security baselines with GPO

Deploy Microsoft security baselines with Group Policy: SCT, Policy Analyzer gap analysis, LGPO testing, ring-based rollout, exceptions and drift checks.

Intermediate