Skip to content

Commit

Permalink
Merge pull request #18 from quantum-sec/feat/XDR-4369
Browse files Browse the repository at this point in the history
XDR-4369: add DCR rule module (feat)
  • Loading branch information
chrisjaimon2012 authored May 4, 2023
2 parents 50ed167 + c27e97b commit 9031d17
Show file tree
Hide file tree
Showing 4 changed files with 483 additions and 0 deletions.
49 changes: 49 additions & 0 deletions modules/monitor-data-collection-rule/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.12 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 3.53 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.53.0 |
| <a name="provider_null"></a> [null](#provider\_null) | n/a |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azurerm_monitor_data_collection_rule.dcr](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_data_collection_rule) | resource |
| [null_resource.dcr_association](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_data_flow"></a> [data\_flow](#input\_data\_flow) | One or more data\_flow blocks. | <pre>list(object({<br> destinations = list(string)<br> streams = list(string)<br> built_in_transform = optional(string)<br> output_stream = optional(string)<br> transform_kql = optional(string)<br> }))</pre> | n/a | yes |
| <a name="input_data_sources"></a> [data\_sources](#input\_data\_sources) | A data\_sources block. | <pre>object({<br> data_import = optional(object({<br> event_hub_data_source = object({<br> name = string<br> stream = string<br> consumer_group = optional(string)<br> })<br> }))<br> extension = optional(list(object({<br> extension_name = string<br> name = string<br> streams = list(string)<br> extension_json = optional(string)<br> input_data_sources = optional(list(string))<br> })))<br> iis_log = optional(list(object({<br> name = string<br> streams = list(string)<br> log_directories = optional(list(string))<br> })))<br> log_file = optional(list(object({<br> name = string<br> streams = list(string)<br> file_patterns = list(string)<br> format = string<br> settings = optional(object({<br> text = object({<br> record_start_timestamp_format = string<br> })<br> }))<br> })))<br> performance_counter = optional(list(object({<br> name = string<br> counter_specifiers = list(string)<br> sampling_frequency_in_seconds = number<br> streams = list(string)<br> })))<br> platform_telemetry = optional(list(object({<br> name = string<br> streams = list(string)<br> })))<br> prometheus_forwarder = optional(list(object({<br> name = string<br> streams = list(string)<br> label_include_filter = optional(list(object({<br> label = string<br> value = string<br> })))<br> })))<br> syslog = optional(list(object({<br> name = string<br> log_levels = list(string)<br> facility_names = list(string)<br> streams = optional(list(string)) # After provider version 4.0, this will be required.<br> })))<br> windows_event_log = optional(list(object({<br> name = string<br> streams = list(string)<br> x_path_queries = list(string)<br> })))<br> windows_firewall_log = optional(list(object({<br> name = string<br> streams = list(string)<br> })))<br> })</pre> | `{}` | no |
| <a name="input_description"></a> [description](#input\_description) | The description of the Data Collection Rule | `string` | `""` | no |
| <a name="input_destinations"></a> [destinations](#input\_destinations) | A destinations block. | <pre>object({<br> azure_monitor_metrics = optional(object({<br> name = string<br> }))<br> event_hub = optional(list(object({<br> name = string<br> event_hub_id = string<br> })))<br> event_hub_direct = optional(list(object({<br> name = string<br> event_hub_id = string<br> })))<br> log_analytics = optional(list(object({<br> name = string<br> workspace_resource_id = string<br> })))<br> monitor_account = optional(list(object({<br> name = string<br> monitor_account_id = string<br> })))<br> storage_blob = optional(list(object({<br> name = string<br> storage_account_id = string<br> container_name = string<br> })))<br> storage_blob_direct = optional(list(object({<br> name = string<br> storage_account_id = string<br> container_name = string<br> })))<br> storage_table_direct = optional(list(object({<br> name = string<br> table_name = string<br> storage_account_id = string<br> })))<br> })</pre> | n/a | yes |
| <a name="input_identity"></a> [identity](#input\_identity) | An identity block. | <pre>object({<br> type = string<br> identity_ids = optional(list(string))<br> })</pre> | `null` | no |
| <a name="input_kind"></a> [kind](#input\_kind) | The kind of the Data Collection Rule. | `string` | `null` | no |
| <a name="input_location"></a> [location](#input\_location) | The Azure Region where the Data Collection Rule should exist | `string` | n/a | yes |
| <a name="input_name"></a> [name](#input\_name) | The name which should be used for this Data Collection Rule | `string` | n/a | yes |
| <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | The name of the Resource Group where the Data Collection Rule should exist | `string` | n/a | yes |
| <a name="input_stream_declaration"></a> [stream\_declaration](#input\_stream\_declaration) | A stream\_declaration block. | <pre>object({<br> stream_name = string<br> column = list(object({<br> name = string<br> type = string<br> }))<br> })</pre> | `null` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to the resource | `map(string)` | `{}` | no |
| <a name="input_target_resource_id"></a> [target\_resource\_id](#input\_target\_resource\_id) | The ID of the Azure Resource which to associate to a Data Collection Rule or a Data Collection Endpoint. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | The ID of the Data Collection Rule. |
<!-- END_TF_DOCS -->
249 changes: 249 additions & 0 deletions modules/monitor-data-collection-rule/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AN AZURE MONITOR DATA COLLECTION RULE (DCR)
# ---------------------------------------------------------------------------------------------------------------------

terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.53"
}
null = {
source = "hashicorp/null"
version = "~> 3.2"
}
}
required_version = ">= 0.12"
experiments = [module_variable_optional_attrs]
}

resource "azurerm_monitor_data_collection_rule" "dcr" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
description = var.description
kind = var.kind
tags = var.tags

dynamic "data_sources" {
for_each = var.data_sources != {} ? [var.data_sources] : []
content {
dynamic "data_import" {
for_each = data_sources.value["data_import"] != null ? [data_sources.value["data_import"]] : []
content {
event_hub_data_source {
name = data_import.value["event_hub_data_source"]["name"]
stream = data_import.value["event_hub_data_source"]["stream"]
consumer_group = data_import.value["event_hub_data_source"]["consumer_group"]
}
}
}
dynamic "extension" {
for_each = data_sources.value["extension"] != null ? data_sources.value["extension"] : []
content {
extension_name = extension.value["extension_name"]
name = extension.value["name"]
streams = extension.value["streams"]
extension_json = extension.value["extension_json"]
input_data_sources = extension.value["input_data_sources"]
}
}
dynamic "iis_log" {
for_each = data_sources.value["iis_log"] != null ? data_sources.value["iis_log"] : []
content {
name = iis_log.value["name"]
streams = iis_log.value["streams"]
log_directories = iis_log.value["log_directories"]
}
}
dynamic "log_file" {
for_each = data_sources.value["log_file"] != null ? data_sources.value["log_file"] : []
content {
name = log_file.value["name"]
streams = log_file.value["streams"]
file_patterns = log_file.value["file_patterns"]
format = log_file.value["format"]
dynamic "settings" {
for_each = log_file.value["settings"] != null ? [log_file.value["settings"]] : []
content {
text {
record_start_timestamp_format = settings.value["text"]["record_start_timestamp_format"]
}
}
}
}
}
dynamic "performance_counter" {
for_each = data_sources.value["performance_counter"] != null ? data_sources.value["performance_counter"] : []
content {
name = performance_counter.value["name"]
counter_specifiers = performance_counter.value["counter_specifiers"]
sampling_frequency_in_seconds = performance_counter.value["sampling_frequency_in_seconds"]
streams = performance_counter.value["streams"]
}
}
dynamic "platform_telemetry" {
for_each = data_sources.value["platform_telemetry"] != null ? data_sources.value["platform_telemetry"] : []
content {
name = platform_telemetry.value["name"]
streams = platform_telemetry.value["streams"]
}
}
dynamic "prometheus_forwarder" {
for_each = data_sources.value["prometheus_forwarder"] != null ? data_sources.value["prometheus_forwarder"] : []
content {
name = prometheus_forwarder.value["name"]
streams = prometheus_forwarder.value["streams"]
dynamic "label_include_filter" {
for_each = prometheus_forwarder.value["label_include_filter"] != null ? prometheus_forwarder.value["label_include_filter"] : []
content {
label = label_include_filter.value["label"]
value = label_include_filter.value["value"]
}
}
}
}
dynamic "syslog" {
for_each = data_sources.value["syslog"] != null ? data_sources.value["syslog"] : []
content {
name = syslog.value["name"]
log_levels = syslog.value["log_levels"]
facility_names = syslog.value["facility_names"]
streams = syslog.value["streams"]
}
}
dynamic "windows_event_log" {
for_each = data_sources.value["windows_event_log"] != null ? data_sources.value["windows_event_log"] : []
content {
name = windows_event_log.value["name"]
streams = windows_event_log.value["streams"]
x_path_queries = windows_event_log.value["x_path_queries"]
}
}
dynamic "windows_firewall_log" {
for_each = data_sources.value["windows_firewall_log"] != null ? data_sources.value["windows_firewall_log"] : []
content {
name = windows_firewall_log.value["name"]
streams = windows_firewall_log.value["streams"]
}
}
}
}

dynamic "data_flow" {
for_each = var.data_flow
content {
destinations = data_flow.value["destinations"]
streams = data_flow.value["streams"]
built_in_transform = data_flow.value["built_in_transform"]
output_stream = data_flow.value["output_stream"]
transform_kql = data_flow.value["transform_kql"]
}
}

destinations {
dynamic "azure_monitor_metrics" {
for_each = var.destinations["azure_monitor_metrics"] != null ? [var.destinations["azure_monitor_metrics"]] : []
content {
name = azure_monitor_metrics.value["name"]
}
}
dynamic "event_hub" {
for_each = var.destinations["event_hub"] != null ? var.destinations["event_hub"] : []
content {
name = event_hub.value["name"]
event_hub_id = event_hub.value["event_hub_id"]
}
}
dynamic "event_hub_direct" {
for_each = var.destinations["event_hub_direct"] != null ? var.destinations["event_hub_direct"] : []
content {
name = event_hub_direct.value["name"]
event_hub_id = event_hub_direct.value["event_hub_id"]
}
}
dynamic "log_analytics" {
for_each = var.destinations["log_analytics"] != null ? var.destinations["log_analytics"] : []
content {
name = log_analytics.value["name"]
workspace_resource_id = log_analytics.value["workspace_resource_id"]
}
}
dynamic "monitor_account" {
for_each = var.destinations["monitor_account"] != null ? var.destinations["monitor_account"] : []
content {
name = monitor_account.value["name"]
monitor_account_id = monitor_account.value["monitor_account_id"]
}
}
dynamic "storage_blob" {
for_each = var.destinations["storage_blob"] != null ? var.destinations["storage_blob"] : []
content {
name = storage_blob.value["name"]
storage_account_id = storage_blob.value["storage_account_id"]
container_name = storage_blob.value["container_name"]
}
}
dynamic "storage_blob_direct" {
for_each = var.destinations["storage_blob_direct"] != null ? var.destinations["storage_blob_direct"] : []
content {
name = storage_blob_direct.value["name"]
storage_account_id = storage_blob_direct.value["storage_account_id"]
container_name = storage_blob_direct.value["container_name"]
}
}
dynamic "storage_table_direct" {
for_each = var.destinations["storage_table_direct"] != null ? var.destinations["storage_table_direct"] : []
content {
name = storage_table_direct.value["name"]
table_name = storage_table_direct.value["table_name"]
storage_account_id = storage_table_direct.value["storage_account_id"]
}
}
}

dynamic "stream_declaration" {
for_each = var.stream_declaration != null ? [var.stream_declaration] : []
content {
stream_name = stream_declaration.value["stream_name"]
dynamic "column" {
for_each = stream_declaration.value["column"]
content {
name = column.value["name"]
type = column.value["type"]
}
}
}
}

dynamic "identity" {
for_each = var.identity != null ? [var.identity] : []
content {
type = identity.value["type"]
identity_ids = identity.value["identity_ids"]
}
}
}

# azurerm_monitor_data_collection_rule_association doesn't support resource of type
# 'Microsoft.OperationalInsights/workspaces'
# https://github.com/hashicorp/terraform-provider-azurerm/issues/20637

#resource "azurerm_monitor_data_collection_rule_association" "dcr_association" {
# name = "${var.name}-association"
# description = var.description
# target_resource_id = var.target_resource_id
# data_collection_rule_id = azurerm_monitor_data_collection_rule.dcr.id
#}

# TODO: add validations for resource_group_name and target_resource_id to prevent potential CLI injection.
# DCR needs to be linked to a Log Analytics workspace
# https://learn.microsoft.com/en-gb/azure/azure-monitor/logs/tutorial-workspace-transformations-api#link-workspace-to-dcr
resource "null_resource" "dcr_association" {
provisioner "local-exec" {
command = "az monitor log-analytics workspace update --resource-group ${var.resource_group_name} --workspace-name ${var.target_resource_id} --data-collection-rule \"${azurerm_monitor_data_collection_rule.dcr.id}\""
}
depends_on = [
azurerm_monitor_data_collection_rule.dcr
]
}
4 changes: 4 additions & 0 deletions modules/monitor-data-collection-rule/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "id" {
description = "The ID of the Data Collection Rule."
value = azurerm_monitor_data_collection_rule.dcr.id
}
Loading

0 comments on commit 9031d17

Please sign in to comment.