This check flags Azure NSG flow logs configured with a retention period under 90 days. Short retention means you lose the network traffic records needed for incident investigation and compliance. Fix it by bumping the retention to 90 days or more (or storing logs indefinitely with lifecycle management).
Network Security Group (NSG) flow logs are one of the most valuable forensic artifacts you have in Azure. They record the IP traffic flowing through an NSG: source and destination addresses, ports, protocols, and whether traffic was allowed or denied. When something goes wrong, these logs are often the only way to reconstruct what an attacker touched and when.
This Lensix check, networkwatcher_lowflowlogretention, fires when an NSG flow log is set to retain data for fewer than 90 days. That gap might seem minor, but it can quietly undermine both your incident response capability and your compliance posture.
What this check detects
Azure Network Watcher lets you enable flow logging on an NSG and configure how long the captured data is retained in the backing storage account. The retention setting accepts a value in days, where 0 means "retain forever" and any positive number sets an automatic deletion window.
Lensix evaluates the configured retention policy on each NSG flow log. The check is marked as failing when:
- The flow log has a retention policy enabled, and
- The number of days is set to a value greater than 0 but less than 90.
Note: A retention value of 0 means logs are never automatically deleted. That setting passes this check because the goal is to keep data long enough, not to enforce deletion. If your concern is cost rather than retention, see the warning further down.
So a flow log set to 30 or 60 days fails. A flow log set to 90, 365, or 0 days passes.
Why it matters
The 90-day threshold is not arbitrary. Most breaches are not detected immediately. The industry median dwell time, the gap between initial compromise and detection, has historically sat in the weeks-to-months range. If your flow logs only go back 30 days, an investigation that kicks off after a 45-day-old intrusion has nothing to work with. The evidence is already gone.
Here are the concrete scenarios where short retention hurts:
Incident investigation falls flat
Say your security team gets an alert that a VM was reaching out to a known command-and-control IP. You want to know how long that beaconing had been happening and what else the host talked to. With 30-day retention, you can only see the most recent activity. The original lateral movement, the initial inbound connection, the data exfiltration window, all of it may have aged out.
Compliance and audit failures
Several frameworks expect network activity logs to be retained for specific minimum windows:
- PCI DSS requires audit log history to be retained for at least one year, with at least three months immediately available for analysis.
- HIPAA expects audit records to be retained, with six years being a common interpretation for related documentation.
- SOC 2 auditors routinely ask for evidence that logging is enabled and retained long enough to support monitoring controls.
A 30-day retention policy will not satisfy the three-month minimum that PCI DSS sets, and that is a finding waiting to happen during an audit.
Detection of slow, low-and-slow attacks
Sophisticated attackers deliberately move slowly to stay under detection thresholds. A connection every few days, a small chunk of data at a time. Reconstructing that pattern requires a long lookback window. Short retention blinds you to exactly the threats that are hardest to catch.
Warning: Longer retention increases storage costs. Flow logs can grow quickly on busy NSGs. Before setting retention to a high value or to 0 (forever), estimate the volume and consider tiering older data to cool or archive storage. More on this in the cost section below.
How to fix it
You can update the retention period through the Azure Portal, the CLI, PowerShell, or infrastructure as code. The fix is to set retention to 90 days or more.
Option 1: Azure Portal
- Go to Network Watcher in the Azure Portal.
- Under Logs, select Flow logs.
- Click the flow log associated with the flagged NSG.
- In the configuration pane, locate Retention (days).
- Set the value to
90(or higher, or0for indefinite retention). - Click Save.
Option 2: Azure CLI
First, find the flow log name and its resource group:
az network watcher flow-log list \
--location eastus \
--query "[].{name:name, retention:retentionPolicy.days}" \
--output table
Then update the retention policy. This example sets it to 90 days:
az network watcher flow-log update \
--location eastus \
--name myFlowLog \
--resource-group NetworkWatcherRG \
--retention 90
Note: NSG flow log resources usually live in the NetworkWatcherRG resource group, which Azure creates automatically when Network Watcher is enabled in a region. The --location must match the region of the NSG, not the storage account.
Option 3: PowerShell
$nw = Get-AzNetworkWatcher -Location "eastus"
Set-AzNetworkWatcherConfigFlowLog `
-NetworkWatcher $nw `
-TargetResourceId "/subscriptions//resourceGroups//providers/Microsoft.Network/networkSecurityGroups/" `
-StorageAccountId "/subscriptions//resourceGroups//providers/Microsoft.Storage/storageAccounts/" `
-EnableFlowLog $true `
-EnableRetention $true `
-RetentionInDays 90
Option 4: Terraform
If you manage flow logs with Terraform, set the retention_policy block on the azurerm_network_watcher_flow_log resource:
resource "azurerm_network_watcher_flow_log" "example" {
network_watcher_name = azurerm_network_watcher.example.name
resource_group_name = azurerm_resource_group.example.name
name = "nsg-flow-log"
network_security_group_id = azurerm_network_security_group.example.id
storage_account_id = azurerm_storage_account.example.id
enabled = true
retention_policy {
enabled = true
days = 90
}
}
Tip: If you forward flow logs to a Log Analytics workspace through Traffic Analytics, you get a second, queryable copy of the data with its own retention controlled by the workspace. Setting the workspace retention to 90 or more days gives you searchable history in addition to the raw blobs in storage.
How to prevent it from happening again
Fixing one flow log by hand is fine. Stopping the misconfiguration from creeping back across dozens of NSGs requires automation.
Enforce with Azure Policy
Azure Policy can audit or deny flow log configurations that fall short. There is a built-in policy initiative for Network Watcher coverage, and you can author a custom policy to check retention specifically. Here is a custom policy definition that audits flow logs with retention under 90 days:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkWatchers/flowLogs"
},
{
"field": "Microsoft.Network/networkWatchers/flowLogs/retentionPolicy.days",
"less": 90
},
{
"field": "Microsoft.Network/networkWatchers/flowLogs/retentionPolicy.enabled",
"equals": "true"
}
]
},
"then": {
"effect": "audit"
}
}
Assign this at the management group or subscription scope so it covers every flow log you create. Start with the audit effect to find existing offenders, then consider tightening to deny once your estate is clean.
Danger: Setting the policy effect to deny will block deployments that do not comply, including legitimate ones that simply forgot the retention block. Roll out deny only after you have confirmed all existing pipelines set retention correctly, or you risk breaking infrastructure deployments.
Gate it in CI/CD
If you deploy networking through Terraform or Bicep, catch the problem before it reaches Azure. A policy-as-code scanner like Checkov, tfsec, or Lensix's own IaC scanning can flag a days value under 90 during the pull request stage. A simple Checkov custom check or a built-in rule keeps the threshold consistent across every module.
Standardize through modules
Wrap flow log creation in a shared Terraform module or Bicep template with retention defaulted to 90 days or your organization's standard. When teams consume the module, they inherit the correct setting without thinking about it.
Best practices
- Pick a retention value that matches your strictest obligation. If PCI DSS applies, you need at least 90 days hot and a year of total history. Default to 90 at minimum, and longer where regulation demands it.
- Use storage lifecycle management for cost control. Keep recent logs in hot or cool tiers and move older blobs to the archive tier. This lets you retain a year of data without paying hot-tier prices for the whole window.
- Prefer flow log version 2. Version 2 adds throughput data (bytes and packets per flow), which makes exfiltration and DDoS analysis far more useful than the connection-only data in version 1.
- Enable Traffic Analytics. Raw flow logs are dense and hard to read. Traffic Analytics processes them into a queryable, visual form in Log Analytics and makes investigations much faster.
- Monitor that logging stays enabled. Retention does no good if flow logging gets disabled. Pair this check with one that verifies flow logs are enabled on every NSG.
- Centralize storage accounts. Send flow logs to a dedicated, access-controlled storage account in a logging subscription rather than scattering them. This simplifies retention governance and protects the logs from being tampered with by a compromised workload account.
Tip: Combine a 30-day hot retention in Log Analytics for fast queries with 90-plus days of cheaper blob storage for compliance and deep investigations. You get speed where you need it and history where you need it, without paying premium rates across the board.
NSG flow logs are cheap insurance against the worst day your security team will have. Setting retention to 90 days or more costs very little and turns a blind spot into a usable record. Run this check across every subscription, fix the offenders, then lock the standard in with policy so it never drifts again.

