diff --git a/quickstart/101-network-watcher-vnet-flow-logs/README.md b/quickstart/101-network-watcher-vnet-flow-logs/README.md new file mode 100644 index 000000000..00f28dbfc --- /dev/null +++ b/quickstart/101-network-watcher-vnet-flow-logs/README.md @@ -0,0 +1,55 @@ +# Enable virtual network flow logs + +This template creates a virtual network flow log for an existing virtual network. It uses the regional Network Watcher instance and creates a dedicated storage account in the Network Watcher resource group. The storage account is dedicated to the flow log because the flow-log resource manages and might overwrite its lifecycle management rules. + +## Prerequisites + +- Network Watcher is enabled in the virtual network's region. +- The `Microsoft.Insights` resource provider is registered in the subscription. +- An existing virtual network is in the same region as the Network Watcher instance. +- The deploying account can create a flow log and storage account in the Network Watcher resource group. + +## Terraform resource types + +- [azurerm_network_watcher](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/network_watcher) +- [azurerm_storage_account](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) +- [azurerm_network_watcher_flow_log](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_watcher_flow_log) +- [random_string](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) + +## Variables + +| Name | Description | Default | +| --- | --- | --- | +| `network_watcher_name` | Name of the existing regional Network Watcher instance. | `NetworkWatcher_eastus` | +| `network_watcher_resource_group_name` | Name of the resource group that contains the Network Watcher instance. | `NetworkWatcherRG` | +| `virtual_network_id` | Resource ID of the existing virtual network to monitor. | n/a | +| `flow_log_name` | Name of the virtual network flow log. | `vnet-flow-log` | +| `flow_log_version` | Flow log format version. | `2` | +| `retention_days` | Number of days to retain flow log data. Use `0` to retain data indefinitely. | `0` | +| `storage_account_replication_type` | Replication type for the flow log storage account. | `LRS` | + +When `retention_days` is `0`, automatic deletion based on age is disabled. Flow logs continue to be stored and accumulate in the storage account until you manually delete them or delete the storage account. Set a value from `1` through `365` to automatically delete logs after that number of days. + +## Example + +Create a `terraform.tfvars` file with values for your existing resources: + +```hcl +network_watcher_name = "NetworkWatcher_eastus" +network_watcher_resource_group_name = "NetworkWatcherRG" +virtual_network_id = "/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks/" +``` + +The default Network Watcher name is for East US. To use another region, set `network_watcher_name` to the existing Network Watcher instance for the virtual network's region. For example, use `NetworkWatcher_westus2` for West US 2. If the instance is in a custom resource group, also set `network_watcher_resource_group_name`. The storage account and flow log use the selected Network Watcher instance's region. + +Run the following commands: + +```bash +terraform init +terraform plan +terraform apply +``` + +## Clean up resources + +Run `terraform destroy` to delete the flow log and its dedicated storage account. Deleting the storage account permanently deletes all flow logs stored in it. Terraform doesn't delete the existing virtual network or Network Watcher instance. diff --git a/quickstart/101-network-watcher-vnet-flow-logs/main.tf b/quickstart/101-network-watcher-vnet-flow-logs/main.tf new file mode 100644 index 000000000..702ccc3f2 --- /dev/null +++ b/quickstart/101-network-watcher-vnet-flow-logs/main.tf @@ -0,0 +1,38 @@ +data "azurerm_network_watcher" "network_watcher" { + name = var.network_watcher_name + resource_group_name = var.network_watcher_resource_group_name +} + +resource "random_string" "storage_account_suffix" { + length = 8 + lower = true + numeric = true + special = false + upper = false +} + +resource "azurerm_storage_account" "flow_logs" { + name = "flowlogs${random_string.storage_account_suffix.result}" + resource_group_name = data.azurerm_network_watcher.network_watcher.resource_group_name + location = data.azurerm_network_watcher.network_watcher.location + account_tier = "Standard" + account_kind = "StorageV2" + account_replication_type = var.storage_account_replication_type +} + +resource "azurerm_network_watcher_flow_log" "vnet_flow_log" { + name = var.flow_log_name + network_watcher_name = data.azurerm_network_watcher.network_watcher.name + resource_group_name = data.azurerm_network_watcher.network_watcher.resource_group_name + location = data.azurerm_network_watcher.network_watcher.location + + target_resource_id = var.virtual_network_id + storage_account_id = azurerm_storage_account.flow_logs.id + enabled = true + version = var.flow_log_version + + retention_policy { + enabled = var.retention_days > 0 + days = var.retention_days + } +} \ No newline at end of file diff --git a/quickstart/101-network-watcher-vnet-flow-logs/outputs.tf b/quickstart/101-network-watcher-vnet-flow-logs/outputs.tf new file mode 100644 index 000000000..66b14bf9b --- /dev/null +++ b/quickstart/101-network-watcher-vnet-flow-logs/outputs.tf @@ -0,0 +1,14 @@ +output "flow_log_id" { + description = "Resource ID of the virtual network flow log." + value = azurerm_network_watcher_flow_log.vnet_flow_log.id +} + +output "flow_log_name" { + description = "Name of the virtual network flow log." + value = azurerm_network_watcher_flow_log.vnet_flow_log.name +} + +output "storage_account_name" { + description = "Name of the storage account that contains the flow log data." + value = azurerm_storage_account.flow_logs.name +} \ No newline at end of file diff --git a/quickstart/101-network-watcher-vnet-flow-logs/providers.tf b/quickstart/101-network-watcher-vnet-flow-logs/providers.tf new file mode 100644 index 000000000..0c4e8c05e --- /dev/null +++ b/quickstart/101-network-watcher-vnet-flow-logs/providers.tf @@ -0,0 +1,18 @@ +terraform { + required_version = ">= 1.5.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 5.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.7" + } + } +} + +provider "azurerm" { + features {} +} \ No newline at end of file diff --git a/quickstart/101-network-watcher-vnet-flow-logs/variables.tf b/quickstart/101-network-watcher-vnet-flow-logs/variables.tf new file mode 100644 index 000000000..924e3413c --- /dev/null +++ b/quickstart/101-network-watcher-vnet-flow-logs/variables.tf @@ -0,0 +1,60 @@ +variable "network_watcher_name" { + type = string + default = "NetworkWatcher_eastus" + description = "Name of the existing regional Network Watcher instance." +} + +variable "network_watcher_resource_group_name" { + type = string + default = "NetworkWatcherRG" + description = "Name of the resource group that contains the Network Watcher instance." +} + +variable "virtual_network_id" { + type = string + description = "Resource ID of the existing virtual network to monitor." + + validation { + condition = can(regex("(?i)^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft.Network/virtualNetworks/[^/]+$", var.virtual_network_id)) + error_message = "The virtual_network_id value must be a full Azure virtual network resource ID." + } +} + +variable "flow_log_name" { + type = string + default = "vnet-flow-log" + description = "Name of the virtual network flow log." +} + +variable "flow_log_version" { + type = number + default = 2 + description = "Flow log format version. Valid values are 1 and 2." + + validation { + condition = contains([1, 2], var.flow_log_version) + error_message = "The flow_log_version value must be 1 or 2." + } +} + +variable "retention_days" { + type = number + default = 0 + description = "Number of days to retain flow log data. Use 0 to retain data indefinitely." + + validation { + condition = var.retention_days >= 0 && var.retention_days <= 365 + error_message = "The retention_days value must be between 0 and 365." + } +} + +variable "storage_account_replication_type" { + type = string + default = "LRS" + description = "Replication type for the flow log storage account." + + validation { + condition = contains(["LRS", "GRS", "ZRS"], var.storage_account_replication_type) + error_message = "The storage_account_replication_type value must be LRS, GRS, or ZRS." + } +} \ No newline at end of file