Migrating from NSG Flow Logs to VNet Flow Logs in Azure: Implementation with Terraform
Author: Ibrahim Baig (Consultant)
Executive Summary
Microsoft is retiring Network Security Group (NSG) flow logs and recommends migrating to Virtual Network (VNet) flow logs. After June 30, 2025, new NSG flow logs cannot be created, and all NSG flow logs will be retired by September 30, 2027. Migrating to VNet flow logs ensures continued support and provides broader, simpler network visibility.
What Changed & Key Dates
- June 30, 2025: Creation of new NSG flow logs is blocked.
- September 30, 2027: NSG flow logs are retired (resources deleted; historical blobs remain per retention policy).
- Microsoft provides migration scripts and policy guidance for NSG→VNet flow logs.
Why Migrate? (Benefits)
Operational Simplicity & Coverage
- Enable logging at the VNet, subnet, or NIC scope—no dependency on NSG.
- Broader visibility across all workloads inside a VNet, not just NSG-governed traffic.
Security & Analytics
- Native integration with Traffic Analytics for enriched insights.
- Monitor Azure Virtual Network Manager (AVNM) security admin rules.
Continuity & Cost Parity
- VNet flow logs are priced the same as NSG flow logs (with 5 GB/month free).
What’s New in VNet Flow Logs
- Scopes: Enable at VNet, subnet, or NIC level.
- Storage: JSON logs to Azure Storage.
- At-scale enablement: Built-in Azure Policy for auditing and auto-deployment.
- Analytics: Traffic Analytics add-on for deep insights.
- AVNM awareness: Observe centrally managed security admin rules.
Traffic Analytics: Capabilities & Value
Traffic Analytics (TA) is a powerful add-on for VNet flow logs, providing:
- Automated Traffic Insights: Visualize traffic flows, identify top talkers, and detect anomalous patterns.
- Threat Detection: Surface suspicious flows, lateral movement, and communication with malicious IPs.
- Network Segmentation Validation: Confirm that segmentation policies are effective and spot unintended access.
- Performance Monitoring: Analyze bandwidth usage, latency, and flow volumes for troubleshooting.
- Customizable Dashboards: Drill down by subnet, region, or workload for targeted investigations.
- Integration: Seamless with Azure Monitor and Log Analytics for alerting and automation.
For practical recipes and advanced use cases, see https://blog.cloudtrooper.net/2024/05/08/vnet-flow-logs-recipes/.
GAP:
The Terraform Registry page for azurerm_network_watcher_flow_log does not yet provide an explicit VNet flow logs example. In practice, you use the same resource and set target_resource_id to the ID of the VNet (or Subnet/NIC).
Registry page (latest): https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_watcher_flow_log
Important notes:
- Same resource block: azurerm_network_watcher_flow_log
- Use target_resource_id = <resource ID of VNet/Subnet/NIC> (instead of legacy network_security_group_id)
- As of 30 July 2025, creating new NSG flow logs is no longer possible (provider notes); migrate to VNet/Subnet/NIC targets.
- Keep your azurerm provider up-to-date, earlier builds had validation gaps for subnet/NIC IDs; these were tracked and addressed in provider issues.
Implementation Guide
Option A — Terraform (Recommended for IaC)
Note: Use a dedicated Storage account for flow logs, as lifecycle rules may be overwritten.
terraform {
required_version = ">= 1.5"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.110.0" # or latest
}
}
}
provider "azurerm" {
features {}
}
data "azurerm_network_watcher" "this" {
name = "NetworkWatcher_${var.region}"
resource_group_name = "NetworkWatcherRG"
}
resource "azurerm_network_watcher_flow_log" "vnet_flow_log" {
name = "${var.vnet_name}-flowlog"
network_watcher_name = data.azurerm_network_watcher.this.name
resource_group_name = data.azurerm_network_watcher.this.resource_group_name
target_resource_id = azurerm_virtual_network.vnet.id
storage_account_id = azurerm_storage_account.flowlogs_sa.id
enabled = true
retention_policy {
enabled = true
days = 30
}
traffic_analytics {
enabled = true
workspace_id = azurerm_log_analytics_workspace.law.workspace_id
workspace_region = azurerm_log_analytics_workspace.law.location
workspace_resource_id = azurerm_log_analytics_workspace.law.id
interval_in_minutes = 60
}
tags = {
owner = "network-platform"
environment = var.env
}
}
Option B — Azure CLI
az network watcher flow-log create \
--location westus \
--resource-group MyResourceGroup \
--name myVNetFlowLog \
--vnet MyVNetName \
--storage-account mystorageaccount \
--workspace "/subscriptions/<subId>/resourceGroups/<rg>/providers/Microsoft.OperationalInsights/workspaces/<LAWName>" \
--traffic-analytics true \
--interval 60
Option C — Azure Portal
- Go to Network Watcher → Flow logs → + Create.
- Choose Flow log type = Virtual network; select VNet/Subnet/NIC, Storage account, and optionally enable Traffic Analytics.
Option D — At Scale via Azure Policy
- Use built-in policies to audit and auto-deploy VNet flow logs (DeployIfNotExists).
Migration Approach (NSG → VNet Flow Logs)
- Inventory existing NSG flow logs.
- Choose migration method: Microsoft script or Azure Policy.
- Run both in parallel temporarily to validate.
- Disable NSG flow logs before retirement.
Challenges & Mitigations
- Permissions: Ensure required roles on Log Analytics workspace.
- Terraform lifecycle: Use a dedicated Storage account.
- Tooling compatibility: Verify SIEM/NDR support.
- Provider/API maturity: Use current azurerm provider.
Validation Checklist
- Storage: New blobs appear in the configured Storage account.
- Traffic Analytics: Data visible in Log Analytics workspace.
- AVNM: Confirm traffic allowed/denied states appear in logs.
Cost Considerations
- VNet flow logs ingestion: $0.50/GB after 5 GB free/month.
- Traffic Analytics processing: $2.30/GB (60-min) or $3.50/GB (10-min).
Traffic Analytics Deep Dive:
VNet Flow Logs are stored in Azure Blob Storage. Optionally, you can enable Traffic Analytics, which will do two things: it will enrich the flow logs with additional information, and will send everything to a Log Analytics Workspace for easy querying. This “enrich and forward to Log Analytics” operation will happen in intervals, either every 10 minutes or every hour.
Table Structure: NTAIPDetails
This table will contain some enrichment data about public IP addresses, including whether they belong to Azure services and their region, and geolocation information for other public IPs. Here you can see a sample of what that table looks like:
NTAIpDetails
| distinct FlowType, PublicIpDetails, Location
Table Structure: NTATopologyDetails
This table contains information about different elements of your topology, including VNets, subnets, route tables, routes, NSGs, Application Gateways and much more. Here you cans see what it looks like:
Table Structure: NTANetAnalytics
Alright, now we are coming to more interesting things: this table is the one containing the flows we are looking for. Records in this table will contain the usual attributes you would expect such as source and destination IP, protocol, and destination port. Additionally, data will be enriched with information such as:
- Source and destination VM
- Source and destination NIC
- Source and destination subnet
- Source and destination load balancer
- Flow encryption (yes/no)
- Whether the flow is going over ExpressRoute
- And many more
Further below you can read some scenarios with detailed queries that will show you some examples of ways you can extract information from VNet Flow Logs and Traffic Analytics. Of course, these are just some of the scenarios that came to mind on my topology, the idea is that you can get inspiration from these queries to support your individual use case.
Example Scenario:
Imagine you want to see with which IP addresses a given virtual machine has been talking to in the last few days:
NTANetAnalytics
| where TimeGenerated > ago(10d)
| where SrcIp == "10.10.1.4" and strlen(DestIp)>0
| summarize TotalBytes=sum(BytesDestToSrc+BytesSrcToDest) by SrcIp, DestIp
Similarly, you can play around with such KQL queries in the workspace to deep dive into the Flow Logs.
References & Further Reading
https://learn.microsoft.com/en-us/azure/network-watcher/nsg-flow-logs-overview
https://learn.microsoft.com/en-us/azure/network-watcher/nsg-flow-logs-migrate
https://learn.microsoft.com/en-us/azure/network-watcher/vnet-flow-logs-overview
https://learn.microsoft.com/en-us/azure/network-watcher/vnet-flow-logs-manage
https://learn.microsoft.com/en-us/cli/azure/network/watcher/flow-log?view=azure-cli-latest
https://learn.microsoft.com/en-us/azure/network-watcher/vnet-flow-logs-policy
https://azure.microsoft.com/en-us/pricing/details/network-watcher/
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_watcher_flow_log
https://blog.cloudtrooper.net/2024/05/08/vnet-flow-logs-recipes/