Skip to main content

Hardening Veeam Backup & Replication v13: A practical Windows Server security baseline for a smaller, Windows-focused environment

  • August 11, 2026
  • 0 comments
  • 107 views

Forum|alt.badge.img+2

One of the things I enjoy about designing Veeam environments is that the best architecture on paper is not always the best architecture for the people who have to operate it every day.

This project was a smaller Veeam Backup & Replication v13 environment. The system administrators were very comfortable with Windows Server. Linux was another story. They had limited Linux experience and were hesitant to own a Linux-based system after implementation.

That became part of the architecture decision. We could have introduced Linux simply because it gives us attractive security options, but doing that would also introduce another operating system the team would need to patch, monitor, troubleshoot, and secure. In a larger organization with dedicated Linux resources, that conversation is different. Here, operational capability mattered.

So the question became: how secure can we make a Windows-based Veeam v13 deployment while keeping it manageable for the administrators who will own it?

Figure 1 - Two layers of the hardening effort

Veeam Backup & Replication v13

Credentials • Access • Configuration • Repository Protection

Windows Server

Defender • Credential Guard • LSA • Firewall • SMB • Accounts

 

Security vs. Operational Reality

It's easy to design infrastructure in a vacuum. Someone still has to operate that design after the implementation team leaves. They have to patch it, troubleshoot it, recognize what normal looks like, and be willing to log in when something breaks at 2:00 AM.

For this environment, we made operational capability part of the security design. That did not mean accepting the default Windows configuration. It meant starting with a platform the administrators understood and deliberately reducing its attack surface.

Assess, Harden, Validate

I did not want to run a large script that changed dozens of settings and then hope the backup jobs still worked. The approach was intentionally more boring - and more supportable.

Figure 2 - Change workflow

BASELINE

Identify Findings

Review Impact

Apply Change

Test Veeam

VALIDATE

Document Result

 

Windows Controls We Reviewed

WDigest Credential Caching

Check first rather than assuming the setting is correct.

$Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest'
$WDigest = Get-ItemProperty $Path -ErrorAction SilentlyContinue
if ($WDigest.UseLogonCredential -eq 1) { "FAIL - WDigest enabled" }
else { "PASS - WDigest disabled" }

 

LSA Protection

Protecting LSASS deserves attention on a backup server that interacts with privileged credentials.

$Lsa = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -ErrorAction SilentlyContinue
if ($Lsa.RunAsPPL -in 1,2) { "PASS - LSA Protection enabled" }
else { "REVIEW - LSA Protection not enabled" }

 

Credential Guard

Confirm platform support and test Veeam after enabling it.

$DG = Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard
if ($DG.SecurityServicesRunning -contains 1) { "PASS - Credential Guard running" }
else { "REVIEW - Credential Guard not running" }

 

SMB Configuration

Understand SMB repository dependencies before making server-wide changes.

Get-SmbServerConfiguration |
Select EnableSMB1Protocol,EnableSMB2Protocol,RequireSecuritySignature,EncryptData

 

Microsoft Defender

Keep exclusions deliberate, documented, and narrow.

Get-MpComputerStatus |
Select AntivirusEnabled,RealTimeProtectionEnabled,BehaviorMonitorEnabled,NISEnabled
Get-MpPreference

 

Windows Firewall

Ask which systems really need to communicate with VBR.

Get-NetFirewallProfile |
Select Name,Enabled,DefaultInboundAction,DefaultOutboundAction
Get-NetFirewallRule -Direction Inbound -Enabled True |
Select DisplayName,Profile,Action

 

Local Administrators

Every account or group should have a documented reason to be there.

Get-LocalGroupMember -Group Administrators

 

The Veeam Side Matters Too

Separate Administrative Accounts

Where practical, separate normal user, server administration, and backup administration accounts.

Protect the Configuration Backup

Store the Veeam configuration backup somewhere appropriate, encrypt it, control access, and know how it will be used during recovery.

Review Stored Credentials

Periodically review credentials stored for hypervisors, repositories, guest processing, application-aware processing, object storage, and other infrastructure.

Repository Protection and Immutability

Hardening VBR is one layer. At least one backup copy should be protected from simple deletion through an appropriate supported design.

Reusable PowerShell Assessment with HTML Reporting

This sample favors readability over cleverness. Run it before hardening, make approved changes, test Veeam, and run it again with a different phase name.

param(
  [string]$OutputFolder = "C:\VeeamHardeningReports",
  [string]$Phase = "Baseline"
)
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
$Results = @()
function Add-Check($Control,$Status,$Observed,$Recommendation) {
  $script:Results += [pscustomobject]@{
    Control=$Control; Status=$Status; Observed=$Observed; Recommendation=$Recommendation
  }
}
$wd=Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest' -ErrorAction SilentlyContinue
if($wd.UseLogonCredential -eq 1){Add-Check "WDigest" "FAIL" "Enabled" "Disable credential caching."}
else{Add-Check "WDigest" "PASS" "Disabled/not configured" "No change."}

$lsa=Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -ErrorAction SilentlyContinue
if($lsa.RunAsPPL -in 1,2){Add-Check "LSA Protection" "PASS" "RunAsPPL=$($lsa.RunAsPPL)" "No change."}
else{Add-Check "LSA Protection" "REVIEW" "Not enabled" "Evaluate and test LSA protection."}

try {
 $dg=Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard
 if($dg.SecurityServicesRunning -contains 1){Add-Check "Credential Guard" "PASS" "Running" "No change."}
 else{Add-Check "Credential Guard" "REVIEW" "Not running" "Confirm support and evaluate enabling."}
} catch {Add-Check "Credential Guard" "REVIEW" "Unable to query" "Investigate VBS support."}

$smb=Get-SmbServerConfiguration
Add-Check "SMB1" $(if($smb.EnableSMB1Protocol){"FAIL"}else{"PASS"}) `
  "Enabled=$($smb.EnableSMB1Protocol)" "Disable unless a documented dependency exists."

try {
 $mp=Get-MpComputerStatus
 Add-Check "Defender Real-Time Protection" $(if($mp.RealTimeProtectionEnabled){"PASS"}else{"FAIL"}) `
  "Enabled=$($mp.RealTimeProtectionEnabled)" "Enable or document approved alternate protection."
} catch {Add-Check "Defender" "REVIEW" "Unable to query" "Confirm endpoint protection."}

foreach($profile in Get-NetFirewallProfile){
 Add-Check "Firewall - $($profile.Name)" $(if($profile.Enabled){"PASS"}else{"REVIEW"}) `
  "Enabled=$($profile.Enabled); Inbound=$($profile.DefaultInboundAction)" `
  "Review against documented Veeam communication requirements."
}

$admins=(Get-LocalGroupMember -Group Administrators -ErrorAction SilentlyContinue |
 Select-Object -ExpandProperty Name) -join "; "
Add-Check "Local Administrators" "REVIEW" $admins "Confirm every member is required."

$stamp=Get-Date -Format "yyyy-MM-dd_HHmmss"
$report=Join-Path $OutputFolder "$env:COMPUTERNAME-$Phase-$stamp.html"
$css=@"
<style>
body{font-family:Segoe UI,Arial;margin:32px;color:#222}
h1{color:#235678} table{border-collapse:collapse;width:100%}
th{background:#235678;color:white;text-align:left;padding:8px}
td{border:1px solid #ddd;padding:8px;vertical-align:top}
tr:nth-child(even){background:#f5f7f8}
</style>
"@
$rows=foreach($r in $Results){
 "<tr><td>$($r.Control)</td><td><b>$($r.Status)</b></td><td>$($r.Observed)</td><td>$($r.Recommendation)</td></tr>"
}
$body="<h1>Veeam v13 Windows Hardening Assessment</h1>
<p>Computer: $env:COMPUTERNAME<br>Phase: $Phase<br>Generated: $(Get-Date)</p>
<table><tr><th>Control</th><th>Status</th><th>Observed</th><th>Recommendation</th></tr>
$($rows -join "`n")</table>
<p><b>Important:</b> Review proposed changes against current Veeam requirements and test them in your environment.</p>"
ConvertTo-Html -Head $css -Body $body | Out-File $report -Encoding UTF8
Write-Host "Report written to $report"

 

Example usage:

.\Test-VeeamVBRHardening.ps1 -Phase Baseline
# Apply only reviewed/approved changes, reboot if required, and test Veeam.
.\Test-VeeamVBRHardening.ps1 -Phase After

 

The Bigger Lesson

The biggest lesson from this project was not a particular registry value or PowerShell command. Security architecture has to account for the people operating the environment.

We could have deployed something technically impressive that the administrators did not understand. Instead, we started with an operating system they knew well and asked how far we could harden it while keeping it supportable.

Sometimes the best design is not the one with the most controls or the most interesting technology. It is the one that balances security, recoverability, complexity, and the capabilities of the people who will be responsible for it after the implementation team leaves.

What's Next

This work led directly into another area I have been spending more time with: Linux XFS repositories for Veeam. A follow-up can cover SAN-presented storage, DM-Multipath, XFS/reflink, Fast Clone, mount configuration, repository permissions, storage expansion, and practical troubleshooting for Windows-focused Veeam administrators