Back to Checks
azure

Network Watcher has all flow logs enabled with retention set to 0 or at least 90 days

network_flow_log_more_than_90_days
Service: networkSeverity: medium
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 to retain for at least 90 days (or 0 for unlimited). The evaluation checks that flow logging is enabled and that the retention policy meets the required duration for each configured log.

Risk

Absent or short-retained flow logs reduce visibility into IP flows, delaying detection of port scans, brute force, data exfiltration, and lateral movement.

Forensics and accountability degrade, threatening confidentiality and integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks network_flow_log_more_than_90_days

Recommendation

Enable flow logs and keep retention 90 days (0 for unlimited) for supported targets, including virtual networks and network security groups. Restrict and monitor access to logs, store immutably, and stream to a SIEM to detect anomalies. Apply defense in depth and least privilege. Prefer virtual network flow logs for new deployments as NSG flow logs are being retired.

Remediation

CLI

az network watcher flow-log create --location <LOCATION> --name <example_flow_log_name> --target-resource-id <example_target_resource_id> --storage-account <example_storage_account_id> --enabled true --retention 90

Terraform

# Enable flow logs with retention >= 90 days
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

  retention_policy {
    enabled = true
    days    = 90
  }
}

NativeIaC

// Enable flow logs with retention >= 90 days for a supported target
resource flowlog 'Microsoft.Network/networkWatchers/flowLogs@2023-09-01' = {
  name: '<example_network_watcher_name>/<example_flow_log_name>'
  location: '<LOCATION>'
  properties: {
    targetResourceId: '<example_target_resource_id>'
    storageId: '<example_storage_account_id>'
    enabled: true
    retentionPolicy: {
      enabled: true
      days: 90
    }
  }
}

Other

1In Azure Portal, go to Network Watcher > Flow logs
2Select the relevant flow log or create one for the target resource, such as a virtual network or network security group
3Set Status to On
4Set Retention (days) to 0 (unlimited) or at least 90
5Select a Storage account
6Click Save or Review + 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_more_than_90_days(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 enabled for more than 90 days"
                    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 (
                                flow_log.retention_policy.days < 90
                                and flow_log.retention_policy.days != 0
                            ) and not has_failed:
                                report.status = "FAIL"
                                report.status_extended = f"Network Watcher {network_watcher.name} from subscription {subscription_name} ({subscription}) flow logs retention policy is less than 90 days"
                                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