NSG flow logs retire on 30 September 2027, and you can no longer create new ones. After that date, Azure deletes the remaining NSG flow log resources and stops supporting traffic analytics for them. Records already in storage stay there and follow their retention settings.
Moving the logs is the easy part. The work that gets missed is in the queries and alerts, which use a different table and different column names.
Step 1: Inventory what you have
This lists every NSG flow log in each enabled subscription and region. The columns are name, target, enabled, storage account and retention days.
for sub in $(az account list --query "[?state=='Enabled'].id" -o tsv); do
for loc in $(az network watcher list --subscription "$sub" --query "[].location" -o tsv); do
az network watcher flow-log list --subscription "$sub" --location "$loc" \
--query "[].[name, targetResourceId, enabled, storageId, retentionPolicy.days]" -o tsv \
| grep -i networksecuritygroups
done
done
Then find the alert rules that query the old table:
az monitor scheduled-query list \
--query "[?contains(to_string(criteria), 'AzureNetworkAnalytics_CL')].{name:name, rg:resourceGroup}" \
-o table
Search your workbooks, dashboards and saved queries for AzureNetworkAnalytics_CL as well. Also search your Bicep, Terraform and ARM templates for flow logs that target an NSG, because a template that tries to create a new one will now fail.
Step 2: Choose how to migrate
| Your situation | Use |
|---|---|
| Flow logging is on only some NICs or subnets in a VNet, or the configurations differ | Microsoft's migration script |
| The same configuration applies to all NICs and subnets, or you want VNet-level logging | Azure Policy |
| A handful of VNets, or you want a change you can review line by line | Azure CLI |
You can set a flow log at three levels. If more than one applies, the order is NIC > subnet > VNet. Use the VNet level unless a subnet needs a different storage account, workspace or retention period.
Before you start, check these:
- Region: the storage account must be in the same region as the VNet.
- Retention: the retention setting only works with Standard general-purpose v2 storage accounts.
- Cost: VNet flow logs are charged per GB collected, with traffic analytics and storage charged separately. Logging a whole VNet can capture more traffic than your old NSG logs did, so check current pricing and estimate from a pilot VNet.
Option A: Migrate with the script
In the portal, go to Network Watcher > Logs > Migrate flow logs, select your subscriptions and regions, then select Download script and JSON file. You need PowerShell 7, the Az module and RBAC permissions on the flow log and workspace subscriptions.
Connect-AzAccount
Expand-Archive .\MigrateFlowLogs.zip -DestinationPath .\flowlog-migration
cd .\flowlog-migration
.\MigrationFromNsgToAzureFlowLogging.ps1
- Choose 1. Run analysis.
- Enter the config path:
.\RegionSubscriptionConfig.json. - Enter a thread count, or leave it blank for the default of 16.
- Read the report, saved as
AnalysisReport-<subscriptionId>-<region>-<time>.html. - Choose migration with or without aggregation.
- Check the result in the portal before you answer the rollback prompt.
Caution
Once you answer
nat "Do you want to rollback?", you can't revert the changes. Don't change the network topology in those regions and subscriptions while the script runs. Keep the script and the report files, and run it on a non-production subscription first.
The script doesn't support PaaS environments where the NSG flow logs are in your subscription but the target resources are in a different one.
Option B: Migrate with the CLI
Microsoft recommends disabling the NSG flow log first, to avoid duplicate records and extra cost. That leaves a short gap in your logs, so do it in a change window.
# Traffic analytics must be off before the flow log can be disabled
az network watcher flow-log update --location westeurope --name nsg-snet-app-fl \
--nsg nsg-snet-app --resource-group rg-net --storage-account stflowlogsweu01 \
--traffic-analytics false
az network watcher flow-log update --location westeurope --name nsg-snet-app-fl \
--nsg nsg-snet-app --resource-group rg-net --storage-account stflowlogsweu01 \
--enabled false
# Create the VNet flow log
az network watcher flow-log create --location westeurope --name vnet-spoke-app-fl \
--resource-group rg-net --vnet vnet-spoke-app \
--storage-account stflowlogsweu01 --retention 30 \
--traffic-analytics true --workspace law-network-weu --interval 10
If the storage account or workspace is in another resource group, pass its full resource ID. A subscription that has never used flow logs may also need az provider register --namespace Microsoft.Insights.
Leave the old NSG flow log disabled until you've finished Steps 3 and 4. It's your way back if the new log doesn't work.
Warning
Deleting a flow log resource doesn't delete its data from storage. If your compliance rules need the old records, check the lifecycle and retention settings on the storage account before you clean up. Old NSG records stay in the
insights-logs-networksecuritygroupfloweventcontainer.
Step 3: Confirm data is arriving
az network watcher flow-log list --location westeurope \
--query "[].{name:name, enabled:enabled, target:targetResourceId, state:provisioningState}" -o table
az storage blob list --account-name stflowlogsweu01 --auth-mode login \
--container-name insights-logs-flowlogflowevent --num-results 5 --query "[].name" -o tsv
Then check traffic analytics. With a 10-minute interval, allow some time for processing.
NTANetAnalytics
| where TimeGenerated > ago(1h)
| where SubType == "FlowLog"
| summarize Records = count(), Latest = max(TimeGenerated) by FlowLogResourceId
| Symptom | Likely cause | Fix |
|---|---|---|
| Flow log create fails on the storage account | Account is in a different region | Use a storage account in the VNet's region |
| No blobs after normal traffic | Microsoft.Insights not registered, or the log isn't enabled | Register the provider and check enabled |
Blobs exist but NTANetAnalytics is empty | Traffic analytics not enabled, processing delay, or its data collection resources were removed | Check the setting. Traffic analytics manages a DCR and DCE prefixed NWTA in the workspace's resource group, so don't delete them |
| Duplicate records | NSG flow log still on for the same subnet | Disable the NSG flow log |
Step 4: Rewrite queries and alerts
The new table drops the type suffixes on column names.
AzureNetworkAnalytics_CL | NTANetAnalytics |
|---|---|
SubType_s | SubType |
SrcIP_s, DestIP_s | SrcIp, DestIp |
DestPort_d | DestPort |
L4Protocol_s | L4Protocol |
FlowDirection_s | FlowDirection |
FlowStatus_s | FlowStatus |
FlowType_s | FlowType |
NSGList_s | AclGroup |
NSGRule_s | AclRule |
AllowedInFlows_d, DeniedInFlows_d | AllowedInFlows, DeniedInFlows |
AllowedOutFlows_d, DeniedOutFlows_d | AllowedOutFlows, DeniedOutFlows |
A converted query:
NTANetAnalytics
| where TimeGenerated > ago(1h)
| where SubType == "FlowLog" and FlowStatus == "D"
| summarize Denied = sum(DeniedInFlows + DeniedOutFlows)
by SrcIp, DestIp, DestPort, AclRule
| top 20 by Denied
To test a rewrite, compare the old query's results from before cutover with the new query's results after it. Totals won't match exactly, because the logging scope is different. You're looking for missing sources, rules or ports. An alert query that silently returns nothing will never fire, so test each alert by generating a denied flow.
Step 5: Clean up
You can't create a new NSG flow log, so deleting the old one is one-way. Wait until the new log has run through at least one full reporting cycle, then delete it:
az network watcher flow-log delete --name nsg-snet-app-fl --location westeurope
Run the Step 1 inventory again. It should return nothing.
Prevent it next time
- Assign the built-in policy Audit flow logs configuration for every virtual network to find gaps.
- Use Deploy a flow log resource with target virtual network (
DeployIfNotExists) for new VNets, and create a remediation task for existing ones. It needs a storage account in each VNet's region. - Remove NSG flow logs from your IaC modules now, so nobody copies the old pattern.
- Add a heartbeat alert that fires when
NTANetAnalyticshas no recent records for a production flow log.