Managing Azure Network Watcher with Terraform

Learn how to set up and manage Azure Network Watcher using Terraform, including flow logs, connection monitoring, and packet capture

Azure Network Watcher provides tools to monitor, diagnose, view metrics, and enable or disable logs for resources in an Azure virtual network. This guide demonstrates how to set up and manage Network Watcher using Terraform.

Video Tutorial

Learn more about managing Azure Network Watcher with Terraform in this comprehensive video tutorial:

Prerequisites

  • Azure CLI configured with appropriate permissions
  • Terraform installed (version 1.0.0 or later)
  • Resource group created
  • Understanding of networking concepts

Project Structure

terraform-azure-networkwatcher/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   └── networkwatcher/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── configs/
    └── monitoring.json

Network Watcher Configuration

Create modules/networkwatcher/main.tf:

# Network Watcher
resource "azurerm_network_watcher" "main" {
  name                = "${var.project_name}-nw"
  location            = var.location
  resource_group_name = var.resource_group_name

  tags = var.tags
}

# Storage Account for Logs
resource "azurerm_storage_account" "logs" {
  name                     = "${var.project_name}logs"
  resource_group_name      = var.resource_group_name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = var.tags
}

# Flow Logs
resource "azurerm_network_watcher_flow_log" "main" {
  network_watcher_name = azurerm_network_watcher.main.name
  resource_group_name  = var.resource_group_name

  network_security_group_id = var.network_security_group_id
  storage_account_id        = azurerm_storage_account.logs.id
  enabled                   = true
  version                   = 2

  retention_policy {
    enabled = true
    days    = 30
  }

  traffic_analytics {
    enabled               = true
    workspace_id          = var.log_analytics_workspace_id
    workspace_region      = var.location
    workspace_resource_id = var.log_analytics_workspace_resource_id
    interval_in_minutes   = 10
  }
}

# Connection Monitor
resource "azurerm_network_connection_monitor" "main" {
  name                = "${var.project_name}-monitor"
  network_watcher_id  = azurerm_network_watcher.main.id
  location            = var.location

  endpoint {
    name               = "source"
    target_resource_id = var.source_vm_id
  }

  endpoint {
    name               = "destination"
    target_resource_id = var.destination_vm_id
  }

  test_configuration {
    name                      = "http"
    protocol                  = "Http"
    test_frequency_in_seconds = 30

    http_configuration {
      port = 80
      method = "Get"
      path = "/"
      valid_status_code_ranges = ["200-299"]
    }

    success_threshold {
      checks_failed_percent = 50
      round_trip_time_ms   = 100
    }
  }

  test_group {
    name                     = "example"
    destination_endpoints    = ["destination"]
    source_endpoints        = ["source"]
    test_configuration_names = ["http"]
    enabled                 = true
  }

  output_workspace_resource_ids = [var.log_analytics_workspace_resource_id]

  tags = var.tags
}

# Packet Capture
resource "azurerm_network_packet_capture" "main" {
  name                 = "${var.project_name}-capture"
  network_watcher_name = azurerm_network_watcher.main.name
  resource_group_name  = var.resource_group_name
  target_resource_id   = var.target_vm_id

  storage_location {
    storage_account_id = azurerm_storage_account.logs.id
    file_path         = "/captures/example.cap"
  }

  filter {
    local_ip_address = "10.0.0.4"
    local_port       = "443"
    protocol         = "TCP"
  }
}

# For a second NSG's flow logs, declare another azurerm_network_watcher_flow_log
# resource (the one shown above under "Flow Logs") pointed at that NSG - there's
# no separate "flow log definition" resource.

# Connection Monitor v2's endpoints, test configurations, and test groups
# are all nested blocks on azurerm_network_connection_monitor itself (as
# shown above) - there are no standalone
# azurerm_network_watcher_connection_monitor_test_configuration /
# _test_group resources. To add a TCP test alongside the HTTP one already
# configured, add more blocks to azurerm_network_connection_monitor.main:
#
# test_configuration {
#   name                      = "${var.project_name}-tcp-test"
#   protocol                  = "Tcp"
#   test_frequency_in_seconds = 30
#
#   tcp_configuration {
#     port = 443
#   }
#
#   success_threshold {
#     checks_failed_percent = 50
#     round_trip_time_ms    = 100
#   }
# }
#
# test_group {
#   name                     = "tcp-group"
#   destination_endpoints    = ["destination"]
#   source_endpoints         = ["source"]
#   test_configuration_names = ["${var.project_name}-tcp-test"]
#   enabled                  = true
# }

Monitoring Configuration

  1. Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "networkwatcher" {
  name                       = "${var.project_name}-diag"
  target_resource_id        = azurerm_network_watcher.main.id
  log_analytics_workspace_id = var.log_analytics_workspace_id

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

# Network Watcher Alerts
resource "azurerm_monitor_metric_alert" "connection" {
  name                = "${var.project_name}-connection-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_network_connection_monitor.main.id]
  description         = "Alert when connection monitor detects issues"

  criteria {
    metric_namespace = "Microsoft.Network/networkWatchers/connectionMonitors"
    metric_name      = "ProbesFailedPercent"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 10
  }

  action {
    action_group_id = var.action_group_id
  }
}

Advanced Features

  1. Network Performance Monitor

Like the test configurations above, endpoints are endpoint blocks on azurerm_network_connection_monitor itself - not a standalone resource. To monitor another VM’s performance, add another endpoint block alongside the “source”/“destination” ones already on azurerm_network_connection_monitor.main:

endpoint {
  name                = "${var.project_name}-performance"
  target_resource_id  = var.target_vm_id
  target_resource_type = "AzureVM"
  coverage_level      = "Default"
}

Best Practices

  1. Monitoring

    • Enable flow logs
    • Configure alerts
    • Monitor connections
    • Track metrics
  2. Performance

    • Set appropriate intervals
    • Configure thresholds
    • Monitor latency
    • Track bandwidth
  3. Security

    • Enable NSG flow logs
    • Monitor traffic
    • Track connections
    • Review logs
  4. Cost Optimization

    • Optimize logging
    • Review usage

Conclusion

You’ve learned how to set up and manage Azure Network Watcher using Terraform. This setup provides:

  • Network monitoring
  • Traffic analysis
  • Connection tracking
  • Performance metrics

Remember to:

  • Monitor connections
  • Review logs
  • Update configurations
  • Maintain monitoring