From 67653fafe74f30e2e636d21658b4b6cb51f6e70a Mon Sep 17 00:00:00 2001 From: Andriy Knysh Date: Tue, 3 Jan 2023 14:43:53 -0500 Subject: [PATCH] Fix Network Firewall logging configuration (#3) * Update Network Firewall logging configuration * Update Network Firewall logging configuration --- LICENSE | 2 +- README.md | 20 ++++++++++++++------ README.yaml | 16 ++++++++++++---- docs/terraform.md | 2 +- examples/complete/main.tf | 16 ++++++++++++---- main.tf | 37 +++++++++++++++++++++---------------- variables.tf | 2 +- 7 files changed, 62 insertions(+), 33 deletions(-) diff --git a/LICENSE b/LICENSE index e2b9d71..0313fae 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 Cloud Posse, LLC + Copyright 2022-2023 Cloud Posse, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e0e6e27..b7c4986 100644 --- a/README.md +++ b/README.md @@ -158,16 +158,24 @@ module "network_firewall" { firewall_policy_change_protection = var.firewall_policy_change_protection subnet_change_protection = var.subnet_change_protection - logging_config = [ - { + logging_config = { + flow = { log_destination_type = "S3" log_type = "FLOW" log_destination = { bucketName = module.s3_log_storage.bucket_id - prefix = "/network-firewall-logs" + prefix = "/flow" + } + }, + alert = { + log_destination_type = "S3" + log_type = "ALERT" + log_destination = { + bucketName = module.s3_log_storage.bucket_id + prefix = "/alert" } } - ] + } rule_group_config = { stateful-inspection-for-blocking-packets-from-going-to-destination = { @@ -269,7 +277,7 @@ Available targets: | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | | [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | -| [logging\_config](#input\_logging\_config) | Logging configuration | `any` | `{}` | no | +| [logging\_config](#input\_logging\_config) | Logging configuration | `map(any)` | `{}` | no | | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | | [network\_firewall\_description](#input\_network\_firewall\_description) | AWS Network Firewall description. If not provided, the Network Firewall name will be used | `string` | `null` | no | @@ -391,7 +399,7 @@ In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. ## Copyright -Copyright © 2017-2022 [Cloud Posse, LLC](https://cpco.io/copyright) +Copyright © 2017-2023 [Cloud Posse, LLC](https://cpco.io/copyright) diff --git a/README.yaml b/README.yaml index 79df20c..0f3644e 100644 --- a/README.yaml +++ b/README.yaml @@ -123,16 +123,24 @@ usage: |2- firewall_policy_change_protection = var.firewall_policy_change_protection subnet_change_protection = var.subnet_change_protection - logging_config = [ - { + logging_config = { + flow = { log_destination_type = "S3" log_type = "FLOW" log_destination = { bucketName = module.s3_log_storage.bucket_id - prefix = "/network-firewall-logs" + prefix = "/flow" + } + }, + alert = { + log_destination_type = "S3" + log_type = "ALERT" + log_destination = { + bucketName = module.s3_log_storage.bucket_id + prefix = "/alert" } } - ] + } rule_group_config = { stateful-inspection-for-blocking-packets-from-going-to-destination = { diff --git a/docs/terraform.md b/docs/terraform.md index b700216..d04334e 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -45,7 +45,7 @@ | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | | [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | -| [logging\_config](#input\_logging\_config) | Logging configuration | `any` | `{}` | no | +| [logging\_config](#input\_logging\_config) | Logging configuration | `map(any)` | `{}` | no | | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | | [network\_firewall\_description](#input\_network\_firewall\_description) | AWS Network Firewall description. If not provided, the Network Firewall name will be used | `string` | `null` | no | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index e7cad03..b09291e 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -54,16 +54,24 @@ module "network_firewall" { subnet_change_protection = var.subnet_change_protection # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_logging_configuration - logging_config = [ - { + logging_config = { + flow = { log_destination_type = "S3" log_type = "FLOW" log_destination = { bucketName = module.s3_log_storage.bucket_id - prefix = "/network-firewall-logs" + prefix = "/flow" + } + }, + alert = { + log_destination_type = "S3" + log_type = "ALERT" + log_destination = { + bucketName = module.s3_log_storage.bucket_id + prefix = "/alert" } } - ] + } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group rule_group_config = { diff --git a/main.tf b/main.tf index 4d43173..e18c463 100644 --- a/main.tf +++ b/main.tf @@ -5,6 +5,7 @@ locals { network_firewall_policy_name = var.network_firewall_policy_name != null && var.network_firewall_policy_name != "" ? var.network_firewall_policy_name : module.this.id rule_group_config = { for k, v in var.rule_group_config : k => v if local.enabled } logging_config = { for k, v in var.logging_config : k => v if local.enabled } + logging_enabled = length(keys(local.logging_config)) > 0 } # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_firewall @@ -253,26 +254,30 @@ resource "aws_networkfirewall_firewall_policy" "default" { # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_logging_configuration resource "aws_networkfirewall_logging_configuration" "default" { - for_each = local.logging_config + count = local.logging_enabled ? 1 : 0 firewall_arn = one(aws_networkfirewall_firewall.default.*.arn) logging_configuration { - log_destination_config { - # The location to send logs to. Valid values: S3, CloudWatchLogs, KinesisDataFirehose - log_destination_type = each.value.log_destination_type - # The type of log to send. Valid values: ALERT or FLOW - # Alert logs report traffic that matches a StatefulRule with an action setting that sends a log message - # Flow logs are standard network traffic flow logs - log_type = each.value.log_type - log_destination = { - # For log_destination_type = "CloudWatchLogs" - logGroup = lookup(each.value.log_destination, "logGroup", null) - # For log_destination_type = "S3" - bucketName = lookup(each.value.log_destination, "bucketName", null) - prefix = lookup(each.value.log_destination, "prefix", null) - # For log_destination_type = "KinesisDataFirehose" - deliveryStream = lookup(each.value.log_destination, "deliveryStream", null) + dynamic "log_destination_config" { + for_each = local.logging_config + + content { + # The location to send logs to. Valid values: S3, CloudWatchLogs, KinesisDataFirehose + log_destination_type = log_destination_config.value.log_destination_type + # The type of log to send. Valid values: ALERT or FLOW + # Alert logs report traffic that matches a StatefulRule with an action setting that sends a log message + # Flow logs are standard network traffic flow logs + log_type = log_destination_config.value.log_type + log_destination = { + # For log_destination_type = "CloudWatchLogs" + logGroup = lookup(log_destination_config.value.log_destination, "logGroup", null) + # For log_destination_type = "S3" + bucketName = lookup(log_destination_config.value.log_destination, "bucketName", null) + prefix = lookup(log_destination_config.value.log_destination, "prefix", null) + # For log_destination_type = "KinesisDataFirehose" + deliveryStream = lookup(log_destination_config.value.log_destination, "deliveryStream", null) + } } } } diff --git a/variables.tf b/variables.tf index 22e9c38..122579e 100644 --- a/variables.tf +++ b/variables.tf @@ -83,7 +83,7 @@ variable "rule_group_config" { } variable "logging_config" { - type = any + type = map(any) description = "Logging configuration" default = {} }