From a3f93b8af6f4f3585124fcd3e2d24b02ba20ba53 Mon Sep 17 00:00:00 2001 From: Kelly Faessen Date: Wed, 19 Aug 2026 11:06:13 +0200 Subject: [PATCH] feat: add data collection endpoint and rule modules (AB#9312) Both modules are needed to send custom logs through the Logs Ingestion API, which replaces the HTTP Data Collector API that Azure Monitor retires on 14 September 2026. The rule module takes a list of custom streams. Each stream gets a stream declaration describing the incoming payload and a data flow that transforms it into an existing custom table, so a caller can keep the column names of a table that was previously fed by the Data Collector API. --- .../azure/data_collection_endpoint/main.tf | 26 ++++++++ .../azure/data_collection_endpoint/outputs.tf | 15 +++++ .../data_collection_endpoint/variables.tf | 38 +++++++++++ modules/azure/data_collection_rule/main.tf | 64 +++++++++++++++++++ modules/azure/data_collection_rule/outputs.tf | 11 ++++ .../azure/data_collection_rule/variables.tf | 55 ++++++++++++++++ 6 files changed, 209 insertions(+) create mode 100644 modules/azure/data_collection_endpoint/main.tf create mode 100644 modules/azure/data_collection_endpoint/outputs.tf create mode 100644 modules/azure/data_collection_endpoint/variables.tf create mode 100644 modules/azure/data_collection_rule/main.tf create mode 100644 modules/azure/data_collection_rule/outputs.tf create mode 100644 modules/azure/data_collection_rule/variables.tf diff --git a/modules/azure/data_collection_endpoint/main.tf b/modules/azure/data_collection_endpoint/main.tf new file mode 100644 index 00000000..be571616 --- /dev/null +++ b/modules/azure/data_collection_endpoint/main.tf @@ -0,0 +1,26 @@ +terraform { + required_version = "~> 1.12" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.117" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} +} + +resource "azurerm_monitor_data_collection_endpoint" "data_collection_endpoint" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + kind = var.kind + public_network_access_enabled = var.public_network_access_enabled + description = var.description + tags = var.tags +} diff --git a/modules/azure/data_collection_endpoint/outputs.tf b/modules/azure/data_collection_endpoint/outputs.tf new file mode 100644 index 00000000..0414e38d --- /dev/null +++ b/modules/azure/data_collection_endpoint/outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = azurerm_monitor_data_collection_endpoint.data_collection_endpoint.id +} + +output "name" { + value = azurerm_monitor_data_collection_endpoint.data_collection_endpoint.name +} + +output "logs_ingestion_endpoint" { + value = azurerm_monitor_data_collection_endpoint.data_collection_endpoint.logs_ingestion_endpoint +} + +output "configuration_access_endpoint" { + value = azurerm_monitor_data_collection_endpoint.data_collection_endpoint.configuration_access_endpoint +} diff --git a/modules/azure/data_collection_endpoint/variables.tf b/modules/azure/data_collection_endpoint/variables.tf new file mode 100644 index 00000000..e3af8575 --- /dev/null +++ b/modules/azure/data_collection_endpoint/variables.tf @@ -0,0 +1,38 @@ +variable "location" { + type = string + description = "A datacenter location in Azure." +} + +variable "resource_group_name" { + type = string + description = "Name of the resource group." +} + +variable "name" { + type = string + description = "Specifies the name of the Data Collection Endpoint." +} + +variable "kind" { + type = string + description = "The kind of the Data Collection Endpoint. Possible values are Linux and Windows." + default = "Linux" +} + +variable "public_network_access_enabled" { + type = bool + description = "Whether network access from public internet to the endpoint is allowed." + default = true +} + +variable "description" { + type = string + description = "Specifies a description for the Data Collection Endpoint." + default = null +} + +variable "tags" { + type = map(string) + description = "A mapping of tags to assign to the resource." + default = null +} diff --git a/modules/azure/data_collection_rule/main.tf b/modules/azure/data_collection_rule/main.tf new file mode 100644 index 00000000..3c38494f --- /dev/null +++ b/modules/azure/data_collection_rule/main.tf @@ -0,0 +1,64 @@ +terraform { + required_version = "~> 1.12" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.117" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} +} + +locals { + streams = { for stream in var.streams : stream.name => stream } +} + +resource "azurerm_monitor_data_collection_rule" "data_collection_rule" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + data_collection_endpoint_id = var.data_collection_endpoint_id + description = var.description + tags = var.tags + + destinations { + log_analytics { + name = var.destination_name + workspace_resource_id = var.log_analytics_workspace_id + } + } + + dynamic "stream_declaration" { + for_each = local.streams + + content { + stream_name = stream_declaration.value.name + + dynamic "column" { + for_each = stream_declaration.value.columns + + content { + name = column.value.name + type = column.value.type + } + } + } + } + + dynamic "data_flow" { + for_each = local.streams + + content { + streams = [data_flow.value.name] + destinations = [var.destination_name] + transform_kql = data_flow.value.transform_kql + output_stream = data_flow.value.output_stream + } + } +} diff --git a/modules/azure/data_collection_rule/outputs.tf b/modules/azure/data_collection_rule/outputs.tf new file mode 100644 index 00000000..9efa05c3 --- /dev/null +++ b/modules/azure/data_collection_rule/outputs.tf @@ -0,0 +1,11 @@ +output "id" { + value = azurerm_monitor_data_collection_rule.data_collection_rule.id +} + +output "name" { + value = azurerm_monitor_data_collection_rule.data_collection_rule.name +} + +output "immutable_id" { + value = azurerm_monitor_data_collection_rule.data_collection_rule.immutable_id +} diff --git a/modules/azure/data_collection_rule/variables.tf b/modules/azure/data_collection_rule/variables.tf new file mode 100644 index 00000000..eb26e4c8 --- /dev/null +++ b/modules/azure/data_collection_rule/variables.tf @@ -0,0 +1,55 @@ +variable "location" { + type = string + description = "A datacenter location in Azure." +} + +variable "resource_group_name" { + type = string + description = "Name of the resource group." +} + +variable "name" { + type = string + description = "Specifies the name of the Data Collection Rule." +} + +variable "log_analytics_workspace_id" { + type = string + description = "Resource id of the Log Analytics Workspace the collected data is sent to." +} + +variable "data_collection_endpoint_id" { + type = string + description = "Resource id of the Data Collection Endpoint that receives the data." +} + +variable "streams" { + type = list(object({ + name = string + output_stream = string + transform_kql = string + columns = list(object({ + name = string + type = string + })) + })) + description = "The custom streams accepted by this rule. Every stream gets a stream declaration describing the incoming data and a data flow that transforms it into the output stream. Stream names must start with Custom-, and the output stream must reference a table that already exists in the workspace." +} + +variable "destination_name" { + type = string + description = "Name used to reference the Log Analytics destination inside the rule." + default = "logAnalytics" +} + +variable "description" { + type = string + description = "Specifies a description for the Data Collection Rule." + default = null +} + +variable "tags" { + type = map(string) + description = "A mapping of tags to assign to the resource." + default = null +}