Back to Checks
azure

Network Watcher has flow logs enabled and sent to a Log Analytics workspace

network_flow_log_captured_sent
Service: networkSeverity: high
OfficialBuilt-inVerified
Categories:loggingforensics-ready
Resource Type:microsoft.network/networkwatchers

Azure Network Watcher has flow logs enabled for supported targets, such as virtual networks and network security groups, and configured with Traffic Analytics to forward records to a centralized Log Analytics workspace

Risk

Missing, disabled, or non-centralized flow logging blinds visibility into network behavior, hindering detection of:

  • Lateral movement and internal scanning
  • C2 beacons and exfiltration patterns This degrades incident response and correlation, impacting confidentiality and integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks network_flow_log_captured_sent

Recommendation

Enable and centrally aggregate flow logs for supported Network Watcher targets, including virtual networks and network security groups, to a Log Analytics workspace.

  • Enforce least privilege on log data
  • Define retention and secure storage
  • Use layered monitoring (e.g., Traffic Analytics)
  • Ensure coverage across regions, subscriptions, and critical network segments

Remediation

CLI

az network watcher flow-log create --location <REGION> --name <FLOW_LOG_NAME> --resource-group <RESOURCE_GROUP> --target-resource-id <TARGET_RESOURCE_ID> --storage-account <STORAGE_ACCOUNT_ID> --enabled true --workspace <LOG_ANALYTICS_WORKSPACE_ID>

Terraform

# Enable flow logs for a supported target and send analytics to Log Analytics
resource "azurerm_network_watcher_flow_log" "<example_resource_name>" {
  name                 = "<example_resource_name>"
  network_watcher_name = "<example_network_watcher_name>"
  resource_group_name  = "<example_resource_group_name>"
  target_resource_id   = "<example_target_resource_id>"
  storage_account_id   = "<example_storage_account_id>"

  enabled = true

  traffic_analytics {
    enabled               = true
    workspace_id          = "<example_workspace_id>"
    workspace_region      = "<REGION>"
    workspace_resource_id = "<example_log_analytics_workspace_id>"
  }
}

NativeIaC

// Enable flow logs for a supported target (for example, a virtual network or NSG)
resource flowLog 'Microsoft.Network/networkWatchers/flowLogs@2023-09-01' = {
  name: '<example_network_watcher_name>/<example_flow_log_name>'
  location: '<REGION>'
  properties: {
    enabled: true
    targetResourceId: '<example_target_resource_id>'
    storageId: '<example_storage_account_id>'
    flowAnalyticsConfiguration: {
      networkWatcherFlowAnalyticsConfiguration: {
        enabled: true
        workspaceResourceId: '<example_log_analytics_workspace_id>'
      }
    }
  }
}

Other

1In Azure portal, go to Network Watcher > Flow logs
2Click + Create
3Select the subscription and region
4Choose the appropriate flow log type and target resource, such as a virtual network or network security group
5Set Status to On
6Select a Storage account
7Enable Traffic analytics and select the Log Analytics workspace
8Click Review + create, then Create

Check Code

from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.network.network_client import network_client


class network_flow_log_captured_sent(Check):
    def execute(self) -> Check_Report_Azure:
        findings = []
        for subscription, network_watchers in network_client.network_watchers.items():
            subscription_name = network_client.subscriptions.get(
                subscription, subscription
            )
            for network_watcher in network_watchers:
                report = Check_Report_Azure(
                    metadata=self.metadata(), resource=network_watcher
                )
                report.subscription = subscription
                if network_watcher.flow_logs:
                    report.status = "PASS"
                    report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription_name} ({subscription}) has flow logs that are captured and sent to Log Analytics workspace"
                    has_failed = False
                    for flow_log in network_watcher.flow_logs:
                        if not has_failed:
                            if not flow_log.enabled:
                                report.status = "FAIL"
                                report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription_name} ({subscription}) has flow logs disabled"
                                has_failed = True
                            elif not (
                                flow_log.traffic_analytics_enabled
                                and flow_log.workspace_resource_id
                            ):
                                report.status = "FAIL"
                                report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription_name} ({subscription}) has enabled flow logs that are not configured to send traffic analytics to a Log Analytics workspace"
                                has_failed = True
                else:
                    report.status = "FAIL"
                    report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription_name} ({subscription}) has no flow logs"

                findings.append(report)

        return findings