From 3f843ba5db4dcc4aafa3be882862ab29da797e7a Mon Sep 17 00:00:00 2001 From: roger-amorim-dv Date: Fri, 24 Jan 2025 19:01:31 -0300 Subject: [PATCH 1/5] feat: initial version to allow network firewall support --- main.tf | 178 +++++++++++++++++++++++++++- network-firewall.tf | 144 +++++++++++++++++++++++ outputs.tf | 59 ++++++++++ variables.tf | 278 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 network-firewall.tf diff --git a/main.tf b/main.tf index 77cba6715..34c74e6a1 100644 --- a/main.tf +++ b/main.tf @@ -6,6 +6,7 @@ locals { len_redshift_subnets = max(length(var.redshift_subnets), length(var.redshift_subnet_ipv6_prefixes)) len_intra_subnets = max(length(var.intra_subnets), length(var.intra_subnet_ipv6_prefixes)) len_outpost_subnets = max(length(var.outpost_subnets), length(var.outpost_subnet_ipv6_prefixes)) + len_firewall_subnets = max(length(var.firewall_subnets), length(var.firewall_subnet_ipv6_prefixes)) max_subnet_length = max( local.len_private_subnets, @@ -13,8 +14,18 @@ locals { local.len_elasticache_subnets, local.len_database_subnets, local.len_redshift_subnets, + local.len_firewall_subnets, ) + // TODO - comment what this line does + firewall_sync_states = try(module.firewall[0].status[0].sync_states, {}) + firewall_vpce = { + for state in local.firewall_sync_states: state.availability_zone => { + cidr_block = one([ for subnet in aws_subnet.firewall : subnet.cidr_block if subnet.id == state.attachment[0].subnet_id ]) + endpoint_id = state.attachment[0].endpoint_id + } + } + # Use `local.vpc_id` to give a hint to Terraform that subnets should be deleted before secondary CIDR blocks can be free! vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this[0].id, "") @@ -153,7 +164,7 @@ resource "aws_route_table_association" "public" { } resource "aws_route" "public_internet_gateway" { - count = local.create_public_subnets && var.create_igw ? local.num_public_route_tables : 0 + count = local.create_public_subnets && var.create_igw && !(var.enable_network_firewall && local.len_firewall_subnets > 0) ? local.num_public_route_tables : 0 route_table_id = aws_route_table.public[count.index].id destination_cidr_block = "0.0.0.0/0" @@ -164,6 +175,32 @@ resource "aws_route" "public_internet_gateway" { } } +resource "aws_route_table_association" "public_internet_gateway" { + count = local.create_vpc && var.create_igw && var.enable_network_firewall && local.len_firewall_subnets > 0 ? 1 : 0 + + gateway_id = aws_internet_gateway.this[0].id + route_table_id = aws_route_table.internet_gateway[0].id +} + +resource "aws_route_table_association" "firewall" { + count = local.create_vpc && local.len_firewall_subnets > 0 ? local.len_firewall_subnets : 0 + + subnet_id = element(aws_subnet.firewall.*.id, count.index) + route_table_id = aws_route_table.firewall[0].id +} + +resource "aws_route" "public_firewall" { + count = local.create_vpc && var.enable_network_firewall ? local.len_public_subnets : 0 + + route_table_id = element(aws_route_table.public.*.id, count.index) + destination_cidr_block = "0.0.0.0/0" + vpc_endpoint_id = local.firewall_vpce[aws_subnet.public[count.index].availability_zone].endpoint_id + + timeouts { + create = "5m" + } +} + resource "aws_route" "public_internet_gateway_ipv6" { count = local.create_public_subnets && var.create_igw && var.enable_ipv6 ? local.num_public_route_tables : 0 @@ -223,6 +260,145 @@ resource "aws_network_acl_rule" "public_outbound" { ipv6_cidr_block = lookup(var.public_outbound_acl_rules[count.index], "ipv6_cidr_block", null) } +################################################################################ +# Firewall Subnets +################################################################################ + +locals { + create_firewall_subnets = local.create_vpc && local.len_firewall_subnets > 0 +} + +resource "aws_subnet" "firewall" { + count = local.create_firewall_subnets ? local.len_firewall_subnets : 0 + + vpc_id = local.vpc_id + cidr_block = var.firewall_subnets[count.index] + availability_zone = length(regexall("^[a-z]{2}-", element(var.azs, count.index))) > 0 ? element(var.azs, count.index) : null + availability_zone_id = length(regexall("^[a-z]{2}-", element(var.azs, count.index))) == 0 ? element(var.azs, count.index) : null + assign_ipv6_address_on_creation = var.enable_ipv6 && var.firewall_subnet_ipv6_native ? true : var.firewall_subnet_assign_ipv6_address_on_creation + + ipv6_cidr_block = var.enable_ipv6 && length(var.firewall_subnet_ipv6_prefixes) > 0 ? cidrsubnet(aws_vpc.this[0].ipv6_cidr_block, 8, var.firewall_subnet_ipv6_prefixes[count.index]) : null + + tags = merge( + { + "Name" = format( + "%s-${var.firewall_subnet_suffix}-%s", + var.name, + element(var.azs, count.index), + ) + }, + var.tags, + var.firewall_subnet_tags, + ) +} + + +resource "aws_route_table" "firewall" { + count = local.create_vpc && var.create_firewall_subnet_route_table && local.len_firewall_subnets > 0 ? 1 : 0 + + vpc_id = local.vpc_id + + tags = merge( + { + "Name" = "${var.name}-${var.firewall_subnet_suffix}" + }, + var.tags, + var.firewall_route_table_tags, + ) +} + +resource "aws_route" "firewall_internet_gateway" { + count = local.create_vpc && var.create_igw && local.len_firewall_subnets > 0 ? 1 : 0 + + route_table_id = aws_route_table.firewall[count.index].id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.this[0].id + + timeouts { + create = "5m" + } +} + +resource "aws_route_table" "internet_gateway" { + count = local.create_vpc && var.enable_network_firewall && local.len_firewall_subnets > 0 ? 1 : 0 + vpc_id = local.vpc_id + + tags = merge( + { + "Name" = format("%s-internet-gateway-${var.firewall_subnet_suffix}", var.name) + }, + var.tags, + var.public_route_table_tags, + ) +} + +resource "aws_route" "internet_gateway_firewall" { + count = local.create_vpc && var.enable_network_firewall && local.len_firewall_subnets > 0 ? local.len_public_subnets : 0 + + route_table_id = aws_route_table.internet_gateway[0].id + destination_cidr_block = aws_subnet.public[count.index].cidr_block + + + vpc_endpoint_id = local.firewall_vpce[aws_subnet.public[count.index].availability_zone].endpoint_id // TODO testing + #vpc_endpoint_id = element(local.firewall_endpoint_ids_ordered_by_azs, count.index) +} + +################################################################################ +# Firewall Network ACLs +################################################################################ + +locals { + create_firewall_network_acl = local.create_firewall_subnets && var.firewall_dedicated_network_acl +} + +resource "aws_network_acl" "firewall" { + count = local.create_firewall_network_acl ? 1 : 0 + + vpc_id = local.vpc_id + subnet_ids = aws_subnet.firewall[*].id + + tags = merge( + { "Name" = "${var.name}-${var.firewall_subnet_suffix}" }, + var.tags, + var.firewall_acl_tags, + ) +} + +resource "aws_network_acl_rule" "firewall_inbound" { + count = local.create_firewall_network_acl ? length(var.firewall_inbound_acl_rules) : 0 + + network_acl_id = aws_network_acl.firewall[0].id + + egress = false + rule_number = var.firewall_inbound_acl_rules[count.index]["rule_number"] + rule_action = var.firewall_inbound_acl_rules[count.index]["rule_action"] + from_port = lookup(var.firewall_inbound_acl_rules[count.index], "from_port", null) + to_port = lookup(var.firewall_inbound_acl_rules[count.index], "to_port", null) + icmp_code = lookup(var.firewall_inbound_acl_rules[count.index], "icmp_code", null) + icmp_type = lookup(var.firewall_inbound_acl_rules[count.index], "icmp_type", null) + protocol = var.firewall_inbound_acl_rules[count.index]["protocol"] + cidr_block = lookup(var.firewall_inbound_acl_rules[count.index], "cidr_block", null) + ipv6_cidr_block = lookup(var.firewall_inbound_acl_rules[count.index], "ipv6_cidr_block", null) +} + +resource "aws_network_acl_rule" "firewall_outbound" { + count = local.create_firewall_network_acl ? length(var.firewall_outbound_acl_rules) : 0 + + network_acl_id = aws_network_acl.firewall[0].id + + egress = true + rule_number = var.firewall_outbound_acl_rules[count.index]["rule_number"] + rule_action = var.firewall_outbound_acl_rules[count.index]["rule_action"] + from_port = lookup(var.firewall_outbound_acl_rules[count.index], "from_port", null) + to_port = lookup(var.firewall_outbound_acl_rules[count.index], "to_port", null) + icmp_code = lookup(var.firewall_outbound_acl_rules[count.index], "icmp_code", null) + icmp_type = lookup(var.firewall_outbound_acl_rules[count.index], "icmp_type", null) + protocol = var.firewall_outbound_acl_rules[count.index]["protocol"] + cidr_block = lookup(var.firewall_outbound_acl_rules[count.index], "cidr_block", null) + ipv6_cidr_block = lookup(var.firewall_outbound_acl_rules[count.index], "ipv6_cidr_block", null) +} + + ################################################################################ # Private Subnets ################################################################################ diff --git a/network-firewall.tf b/network-firewall.tf new file mode 100644 index 000000000..9c577f4cf --- /dev/null +++ b/network-firewall.tf @@ -0,0 +1,144 @@ +locals { + #aws_managed_rules_prefix_arn = "arn:aws:network-firewall:${data.aws_region.current.name}:aws-managed:stateful-rulegroup" + aws_managed_rules_prefix_arn = "arn:aws:network-firewall:us-east-2:aws-managed:stateful-rulegroup" // TODO - review this region + + // TODO - Review these rules + firewall_managed_rules = distinct(concat([ + "AbusedLegitMalwareDomainsStrictOrder", + "BotNetCommandAndControlDomainsStrictOrder", + "AbusedLegitBotNetCommandAndControlDomainsStrictOrder", + "MalwareDomainsStrictOrder", + "ThreatSignaturesIOCStrictOrder", + "ThreatSignaturesPhishingStrictOrder", + "ThreatSignaturesBotnetWebStrictOrder", + "ThreatSignaturesEmergingEventsStrictOrder", + "ThreatSignaturesDoSStrictOrder", + "ThreatSignaturesMalwareWebStrictOrder", + "ThreatSignaturesExploitsStrictOrder", + "ThreatSignaturesWebAttacksStrictOrder", + "ThreatSignaturesScannersStrictOrder", + "ThreatSignaturesBotnetStrictOrder", + "ThreatSignaturesMalwareStrictOrder", + "ThreatSignaturesMalwareCoinminingStrictOrder", + "ThreatSignaturesFUPStrictOrder", + "ThreatSignaturesSuspectStrictOrder", + "ThreatSignaturesBotnetWindowsStrictOrder", + ], var.firewall_managed_rules)) + + name = "${var.name}-network-firewall" +} + +module "firewall" { + source = "terraform-aws-modules/network-firewall/aws" + + count = var.create_network_firewall ? 1 : 0 + + # Firewall + name = local.name + description = var.description + + # Only for example + delete_protection = var.delete_protection + firewall_policy_change_protection = var.firewall_policy_change_protection + subnet_change_protection = var.subnet_change_protection + + vpc_id = aws_vpc.this[0].id + subnet_mapping = { for subnet_id in aws_subnet.firewall.*.id : + "subnet-${subnet_id}" => { + subnet_id = subnet_id + ip_address_type = "IPV4" + } + } + + # Logging configuration + create_logging_configuration = true + logging_configuration_destination_config = [ + { + log_destination = { + logGroup = module.logs_alerts[0].cloudwatch_log_group_name + } + log_destination_type = "CloudWatchLogs" + log_type = "ALERT" + }, + { + log_destination = { + logGroup = module.logs_flow[0].cloudwatch_log_group_name + } + log_destination_type = "CloudWatchLogs" + log_type = "FLOW" + }, + ] + + encryption_configuration = { + key_id = module.kms[0].key_arn + type = "CUSTOMER_KMS" + } + + # Policy + policy_name = local.name + policy_description = "Default network firewall policy for ${local.name}" + + # policy_stateful_rule_group_reference = {} + policy_stateful_rule_group_reference = { + for i, rule_group in local.firewall_managed_rules : rule_group => { + resource_arn = "${local.aws_managed_rules_prefix_arn}/${rule_group}", + priority = i + 1, + } + } + + policy_stateful_engine_options = { + rule_order = "STRICT_ORDER" + } + policy_stateless_default_actions = ["aws:forward_to_sfe"] + policy_stateless_fragment_default_actions = ["aws:forward_to_sfe"] + + tags = var.tags // TODO - review these tags + + depends_on = [module.kms] +} + +module "logs_alerts" { + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" + + count = var.create_network_firewall ? 1 : 0 + + name = "${local.name}-alerts" + tenant = var.tenant + region = var.region + environment = var.environment + + retention_in_days = var.logs_retention_in_days + kms_key_arn = var.logs_kms_key_arn + create_datadog_subscription_filter = true +} + +// TODO review if this module is really necessary +module "logs_flow" { + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" + + count = var.create_network_firewall ? 1 : 0 + + name = "${local.name}-flow" // TODO - review this name + tenant = var.tenant + region = var.region + environment = var.environment + + retention_in_days = var.logs_retention_in_days + kms_key_arn = var.logs_kms_key_arn + create_datadog_subscription_filter = false +} + +module "kms" { + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + + count = var.create_network_firewall ? 1 : 0 + + description = "KMS key used for ${var.name} AWS Network Firewall" + name = var.name // TODO - review this name + region = var.region + environment = var.environment + namespace = var.namespace + tenant = var.tenant + tags = var.tags +} + diff --git a/outputs.tf b/outputs.tf index c2367e210..7d640c945 100644 --- a/outputs.tf +++ b/outputs.tf @@ -2,6 +2,7 @@ locals { redshift_route_table_ids = aws_route_table.redshift[*].id public_route_table_ids = aws_route_table.public[*].id private_route_table_ids = aws_route_table.private[*].id + firewall_route_table_ids = aws_route_table.firewall[*].id } ################################################################################ @@ -500,6 +501,55 @@ output "intra_network_acl_arn" { value = try(aws_network_acl.intra[0].arn, null) } +################################################################################ +# Firewall Subnets +################################################################################ + +output "firewall_subnet_objects" { + description = "A list of all firewall subnets, containing the full objects." + value = aws_subnet.firewall +} + +output "firewall_subnets" { + description = "List of IDs of firewall subnets" + value = aws_subnet.firewall[*].id +} + +output "firewall_subnet_arns" { + description = "List of ARNs of firewall subnets" + value = aws_subnet.firewall[*].arn +} + +output "firewall_subnets_cidr_blocks" { + description = "List of cidr_blocks of firewall subnets" + value = compact(aws_subnet.firewall[*].cidr_block) +} + +output "firewall_subnets_ipv6_cidr_blocks" { + description = "List of IPv6 cidr_blocks of firewall subnets in an IPv6 enabled VPC" + value = compact(aws_subnet.firewall[*].ipv6_cidr_block) +} + +output "firewall_route_table_ids" { + description = "List of IDs of firewall route tables" + value = local.firewall_route_table_ids +} + +output "firewall_route_table_association_ids" { + description = "List of IDs of the firewall route table association" + value = aws_route_table_association.firewall[*].id +} + +output "firewall_network_acl_id" { + description = "ID of the firewall network ACL" + value = try(aws_network_acl.firewall[0].id, null) +} + +output "firewall_network_acl_arn" { + description = "ARN of the firewall network ACL" + value = try(aws_network_acl.firewall[0].arn, null) +} + ################################################################################ # NAT Gateway ################################################################################ @@ -649,6 +699,15 @@ output "vpc_flow_log_deliver_cross_account_role" { value = try(aws_flow_log.this[0].deliver_cross_account_role, null) } +################################################################################ +# Firewall +################################################################################ + +output "firewall_status" { + description = "Nested list of information about the current status of the firewall" + value = try(module.firewall[0].status, {}) +} + ################################################################################ # Static values (arguments) ################################################################################ diff --git a/variables.tf b/variables.tf index 095cc8bdf..31070d5bd 100644 --- a/variables.tf +++ b/variables.tf @@ -1166,6 +1166,284 @@ variable "outpost_acl_tags" { default = {} } + + + + + + + + + + + +################################################################################ +# Firewall +################################################################################ + +variable "create_firewall_subnet_route_table" { + description = "Whether route table for firewall should be created" + type = bool + default = true +} + +variable "create_network_firewall" { + description = "Whether network firewall should be created" + type = bool + default = false +} + +variable "enable_network_firewall" { + description = "Whether network firewall should be enabled" + type = bool + default = false +} + +variable "firewall_policy_arn" { + description = "The network firewall policy arn to associate with the network firewall. Needed if you are setting enable_firewall to true" + type = string + default = null +} + +variable "enable_firewall_logs" { + description = "Whether or not to enable Network Firewall Logs" + type = bool + default = false +} + +variable "firewall_managed_rules" { + description = "List of firewall managed rules" + type = list(string) + default = [] +} + + +variable "firewall_log_cloudwatch_log_group_name_prefix" { + description = "Specifies the name prefix of Network Firewall Log Group for Network Firewall logs." + type = string + default = "/aws/network-firewall-log/" +} + +variable "firewall_log_cloudwatch_log_group_retention_in_days" { + description = "Specifies the number of days you want to retain log events in the specified log group for Network Firewall logs." + type = number + default = 120 +} + +variable "firewall_log_cloudwatch_log_group_kms_key_id" { + description = "The ARN of the KMS Key to use when encrypting log data for Network Firewall logs." + type = string + default = null +} + +variable "firewall_log_types" { + description = "The Types of Network Firewall Logs to send" + type = list(string) + default = ["FLOW", "ALERT"] +} + +variable "region" { + description = "Main region used to deploy the resources. May differ for multi-region databases" + type = string + default = "us-east-2" +} + +variable "environment" { + description = "Environment used to deploy the resources, also used in the naming convention" + type = string +} + +variable "namespace" { + description = "The namespace used in the naming convention" + type = string + default = "clutch" +} + +variable "tenant" { + description = "The tenant used in the naming convention" + type = string + default = "app" +} + +variable "description" { + description = "Description of the network firewall." + type = string + default = null +} + +variable "delete_protection" { + description = "A boolean flag indicating whether it is possible to delete the firewall. Defaults to `true`" + type = bool + default = true +} + +variable "subnet_change_protection" { + description = "A boolean flag indicating whether it is possible to change the associated subnet(s). Defaults to `true`" + type = bool + default = true +} + +variable "firewall_policy_change_protection" { + description = "A boolean flag indicating whether it is possible to change the associated firewall policy. Defaults to `false`" + type = bool + default = true +} + +variable "logs_retention_in_days" { + type = string + description = "Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653." +} + +variable "logs_kms_key_arn" { + description = "The Amazon Resource Name (ARN) of the key used for encrypting the log group" + type = string +} + +resource "random_id" "suffix_name" { + byte_length = 1 +} + + + + +################################################################################ +# Firewall Subnet +################################################################################ + +variable "firewall_subnets" { + description = "A list of firewall subnets inside the VPC" + type = list(string) + default = [] +} + +variable "firewall_subnet_assign_ipv6_address_on_creation" { + description = "Specify true to indicate that network interfaces created in the specified subnet should be assigned an IPv6 address. Default is `false`" + type = bool + default = false +} + +variable "firewall_subnet_enable_dns64" { + description = "Indicates whether DNS queries made to the Amazon-provided DNS Resolver in this subnet should return synthetic IPv6 addresses for IPv4-only destinations. Default: `true`" + type = bool + default = true +} + +variable "firewall_subnet_enable_resource_name_dns_aaaa_record_on_launch" { + description = "Indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records. Default: `true`" + type = bool + default = true +} + +variable "firewall_subnet_enable_resource_name_dns_a_record_on_launch" { + description = "Indicates whether to respond to DNS queries for instance hostnames with DNS A records. Default: `false`" + type = bool + default = false +} + +variable "firewall_subnet_ipv6_prefixes" { + description = "Assigns IPv6 firewall subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" + type = list(string) + default = [] +} + +variable "firewall_subnet_ipv6_native" { + description = "Indicates whether to create an IPv6-only subnet. Default: `false`" + type = bool + default = false +} + +variable "firewall_subnet_private_dns_hostname_type_on_launch" { + description = "The type of hostnames to assign to instances in the subnet at launch. For IPv6-only subnets, an instance DNS name must be based on the instance ID. For dual-stack and IPv4-only subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. Valid values: `ip-name`, `resource-name`" + type = string + default = null +} + +variable "firewall_subnet_names" { + description = "Explicit values to use in the Name tag on firewall subnets. If empty, Name tags are generated" + type = list(string) + default = [] +} + +variable "firewall_subnet_suffix" { + description = "Suffix to append to firewall subnets name" + type = string + default = "public" +} + +variable "firewall_subnet_tags" { + description = "Additional tags for the firewall subnets" + type = map(string) + default = {} +} + +variable "firewall_subnet_tags_per_az" { + description = "Additional tags for the firewall subnets where the primary key is the AZ" + type = map(map(string)) + default = {} +} + +variable "firewall_route_table_tags" { + description = "Additional tags for the firewall route tables" + type = map(string) + default = {} +} + +################################################################################ +# Firewall Network ACLs +################################################################################ + +variable "firewall_dedicated_network_acl" { + description = "Whether to use dedicated network ACL (not default) and custom rules for firewall subnets" + type = bool + default = false +} + +variable "firewall_inbound_acl_rules" { + description = "Firewall subnets inbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "firewall_outbound_acl_rules" { + description = "Firewall subnets outbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "firewall_acl_tags" { + description = "Additional tags for the firewall subnets network ACL" + type = map(string) + default = {} +} + + + + + + + + + + + ################################################################################ # Internet Gateway ################################################################################ From 5b43213ceaed48a51037d41230a0f5fe0ab8e03b Mon Sep 17 00:00:00 2001 From: roger-amorim-dv Date: Tue, 28 Jan 2025 18:57:25 -0300 Subject: [PATCH 2/5] feat: add network firewall example --- examples/network-firewall/main.tf | 88 +++++++++++++++++++ examples/network-firewall/outputs.tf | 41 +++++++++ examples/network-firewall/variables.tf | 0 examples/network-firewall/versions.tf | 14 ++++ network-firewall.tf | 74 +++++++--------- outputs.tf | 5 ++ variables.tf | 112 ++++--------------------- 7 files changed, 192 insertions(+), 142 deletions(-) create mode 100644 examples/network-firewall/main.tf create mode 100644 examples/network-firewall/outputs.tf create mode 100644 examples/network-firewall/variables.tf create mode 100644 examples/network-firewall/versions.tf diff --git a/examples/network-firewall/main.tf b/examples/network-firewall/main.tf new file mode 100644 index 000000000..35f92e9b2 --- /dev/null +++ b/examples/network-firewall/main.tf @@ -0,0 +1,88 @@ +provider "aws" { + region = local.region +} + +locals { + region = "us-east-2" + name = "nf-example-${random_pet.this.id}" + environment = "test" +} + +resource "random_pet" "this" { + length = 2 + separator = "-" +} + +################################################################################ +# KMS Module +################################################################################ + +module "kms" { + #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + + name = local.name + environment = "test" + description = "KMS key used to test the ${local.name} AWS Network Firewall" + allow_usage_in_network_log_groups = true +} + +################################################################################ +# VPC Module +################################################################################ + +module "vpc" { + source = "../../" + + environment = "test" + name = "nf-example" + + ######### VPC ########## + cidr = "10.0.0.0/16" + azs = ["${local.region}a", "${local.region}b", "${local.region}c"] + + ######### Subnets ########## + private_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"] + public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"] + firewall_subnets = ["10.0.3.0/28", "10.0.3.16/28", "10.0.3.32/28"] + + create_multiple_public_route_tables = true + + ######### NAT Gateway ########## + enable_nat_gateway = true + one_nat_gateway_per_az = true + + ########## Firewall ########## + create_network_firewall = true + enable_network_firewall = true + + ######### Firewall Logs ########## + firewall_logs_retention_in_days = 14 + firewall_logs_kms_key_arn = module.kms.key_arn + + ######### Firewall Rules and Filter ########## + firewall_log_types = ["FLOW", "ALERT"] + firewall_managed_rules = [ + "AbusedLegitMalwareDomainsStrictOrder", + "BotNetCommandAndControlDomainsStrictOrder", + "AbusedLegitBotNetCommandAndControlDomainsStrictOrder", + "MalwareDomainsStrictOrder", + "ThreatSignaturesIOCStrictOrder", + "ThreatSignaturesPhishingStrictOrder", + "ThreatSignaturesBotnetWebStrictOrder", + "ThreatSignaturesEmergingEventsStrictOrder", + "ThreatSignaturesDoSStrictOrder", + "ThreatSignaturesMalwareWebStrictOrder", + "ThreatSignaturesExploitsStrictOrder", + "ThreatSignaturesWebAttacksStrictOrder", + "ThreatSignaturesScannersStrictOrder", + "ThreatSignaturesBotnetStrictOrder", + "ThreatSignaturesMalwareStrictOrder", + "ThreatSignaturesMalwareCoinminingStrictOrder", + "ThreatSignaturesFUPStrictOrder", + "ThreatSignaturesSuspectStrictOrder", + "ThreatSignaturesBotnetWindowsStrictOrder", + ] + + depends_on = [module.kms] +} diff --git a/examples/network-firewall/outputs.tf b/examples/network-firewall/outputs.tf new file mode 100644 index 000000000..ed4dfb298 --- /dev/null +++ b/examples/network-firewall/outputs.tf @@ -0,0 +1,41 @@ +################################################################################ +# VPC +################################################################################ + +output "vpc_id" { + description = "The ID of the VPC" + value = module.vpc.vpc_id +} + +################################################################################ +# Subnets +################################################################################ + +output "private_subnets" { + description = "List of IDs of private subnets" + value = module.vpc.private_subnets +} + +output "public_subnets" { + description = "List of IDs of public subnets" + value = module.vpc.public_subnets +} + +output "firewall_subnets" { + description = "List of IDs of firewall subnets" + value = module.vpc.firewall_subnets +} + +################################################################################ +# NAT Gateway +################################################################################ + +output "nat_public_ips" { + description = "List of public Elastic IPs created for AWS NAT Gateway" + value = module.vpc.nat_public_ips +} + +output "network_firewall_arn" { + description = "ARN of the Network Firewall" + value = module.vpc.network_firewall_arn +} diff --git a/examples/network-firewall/variables.tf b/examples/network-firewall/variables.tf new file mode 100644 index 000000000..e69de29bb diff --git a/examples/network-firewall/versions.tf b/examples/network-firewall/versions.tf new file mode 100644 index 000000000..c20408bf6 --- /dev/null +++ b/examples/network-firewall/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.46" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" + } + } +} diff --git a/network-firewall.tf b/network-firewall.tf index 9c577f4cf..f32060102 100644 --- a/network-firewall.tf +++ b/network-firewall.tf @@ -1,46 +1,24 @@ locals { - #aws_managed_rules_prefix_arn = "arn:aws:network-firewall:${data.aws_region.current.name}:aws-managed:stateful-rulegroup" - aws_managed_rules_prefix_arn = "arn:aws:network-firewall:us-east-2:aws-managed:stateful-rulegroup" // TODO - review this region - - // TODO - Review these rules - firewall_managed_rules = distinct(concat([ - "AbusedLegitMalwareDomainsStrictOrder", - "BotNetCommandAndControlDomainsStrictOrder", - "AbusedLegitBotNetCommandAndControlDomainsStrictOrder", - "MalwareDomainsStrictOrder", - "ThreatSignaturesIOCStrictOrder", - "ThreatSignaturesPhishingStrictOrder", - "ThreatSignaturesBotnetWebStrictOrder", - "ThreatSignaturesEmergingEventsStrictOrder", - "ThreatSignaturesDoSStrictOrder", - "ThreatSignaturesMalwareWebStrictOrder", - "ThreatSignaturesExploitsStrictOrder", - "ThreatSignaturesWebAttacksStrictOrder", - "ThreatSignaturesScannersStrictOrder", - "ThreatSignaturesBotnetStrictOrder", - "ThreatSignaturesMalwareStrictOrder", - "ThreatSignaturesMalwareCoinminingStrictOrder", - "ThreatSignaturesFUPStrictOrder", - "ThreatSignaturesSuspectStrictOrder", - "ThreatSignaturesBotnetWindowsStrictOrder", - ], var.firewall_managed_rules)) - - name = "${var.name}-network-firewall" + aws_managed_rules_prefix_arn = "arn:aws:network-firewall:${var.region}:aws-managed:stateful-rulegroup" + firewall_managed_rules = distinct(var.firewall_managed_rules) + name = "${var.name}-network-firewall" } module "firewall" { - source = "terraform-aws-modules/network-firewall/aws" + source = "terraform-aws-modules/network-firewall/aws" + version = "~> 1.0" count = var.create_network_firewall ? 1 : 0 - # Firewall + name = local.name - description = var.description + description = var.firewall_description + - # Only for example - delete_protection = var.delete_protection + delete_protection = var.firewall_delete_protection firewall_policy_change_protection = var.firewall_policy_change_protection - subnet_change_protection = var.subnet_change_protection + subnet_change_protection = var.firewall_subnet_change_protection + vpc_id = aws_vpc.this[0].id subnet_mapping = { for subnet_id in aws_subnet.firewall.*.id : @@ -50,8 +28,8 @@ module "firewall" { } } - # Logging configuration - create_logging_configuration = true + ### Logging configuration ### + create_logging_configuration = false logging_configuration_destination_config = [ { log_destination = { @@ -74,11 +52,10 @@ module "firewall" { type = "CUSTOMER_KMS" } - # Policy + ### Policy ### policy_name = local.name policy_description = "Default network firewall policy for ${local.name}" - # policy_stateful_rule_group_reference = {} policy_stateful_rule_group_reference = { for i, rule_group in local.firewall_managed_rules : rule_group => { resource_arn = "${local.aws_managed_rules_prefix_arn}/${rule_group}", @@ -94,7 +71,7 @@ module "firewall" { tags = var.tags // TODO - review these tags - depends_on = [module.kms] + depends_on = [module.kms, module.logs_alerts, module.logs_flow] } module "logs_alerts" { @@ -102,34 +79,38 @@ module "logs_alerts" { count = var.create_network_firewall ? 1 : 0 - name = "${local.name}-alerts" + name = "nf-network-log-alerts" tenant = var.tenant region = var.region environment = var.environment - retention_in_days = var.logs_retention_in_days - kms_key_arn = var.logs_kms_key_arn + retention_in_days = var.firewall_logs_retention_in_days + kms_key_arn = module.kms[0].key_arn create_datadog_subscription_filter = true + + depends_on = [module.kms] } -// TODO review if this module is really necessary module "logs_flow" { source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" count = var.create_network_firewall ? 1 : 0 - name = "${local.name}-flow" // TODO - review this name + name = "nf-network-log-flow" tenant = var.tenant region = var.region environment = var.environment - retention_in_days = var.logs_retention_in_days - kms_key_arn = var.logs_kms_key_arn + retention_in_days = var.firewall_logs_retention_in_days + kms_key_arn = module.kms[0].key_arn create_datadog_subscription_filter = false + + depends_on = [module.kms] } module "kms" { - source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" count = var.create_network_firewall ? 1 : 0 @@ -140,5 +121,6 @@ module "kms" { namespace = var.namespace tenant = var.tenant tags = var.tags + #allow_usage_in_network_log_groups = true } diff --git a/outputs.tf b/outputs.tf index 7d640c945..c5759124d 100644 --- a/outputs.tf +++ b/outputs.tf @@ -708,6 +708,11 @@ output "firewall_status" { value = try(module.firewall[0].status, {}) } +output "network_firewall_arn" { + description = "ARN of the Network Firewall" + value = try(module.firewall[0].arn, {}) +} + ################################################################################ # Static values (arguments) ################################################################################ diff --git a/variables.tf b/variables.tf index 31070d5bd..5f819b9b7 100644 --- a/variables.tf +++ b/variables.tf @@ -1166,17 +1166,6 @@ variable "outpost_acl_tags" { default = {} } - - - - - - - - - - - ################################################################################ # Firewall ################################################################################ @@ -1199,24 +1188,17 @@ variable "enable_network_firewall" { default = false } -variable "firewall_policy_arn" { - description = "The network firewall policy arn to associate with the network firewall. Needed if you are setting enable_firewall to true" - type = string - default = null -} - -variable "enable_firewall_logs" { - description = "Whether or not to enable Network Firewall Logs" - type = bool - default = false -} - variable "firewall_managed_rules" { description = "List of firewall managed rules" type = list(string) default = [] } +variable "firewall_log_types" { + description = "The Types of Network Firewall Logs to send" + type = list(string) + default = ["FLOW", "ALERT"] +} variable "firewall_log_cloudwatch_log_group_name_prefix" { description = "Specifies the name prefix of Network Firewall Log Group for Network Firewall logs." @@ -1224,24 +1206,6 @@ variable "firewall_log_cloudwatch_log_group_name_prefix" { default = "/aws/network-firewall-log/" } -variable "firewall_log_cloudwatch_log_group_retention_in_days" { - description = "Specifies the number of days you want to retain log events in the specified log group for Network Firewall logs." - type = number - default = 120 -} - -variable "firewall_log_cloudwatch_log_group_kms_key_id" { - description = "The ARN of the KMS Key to use when encrypting log data for Network Firewall logs." - type = string - default = null -} - -variable "firewall_log_types" { - description = "The Types of Network Firewall Logs to send" - type = list(string) - default = ["FLOW", "ALERT"] -} - variable "region" { description = "Main region used to deploy the resources. May differ for multi-region databases" type = string @@ -1265,19 +1229,19 @@ variable "tenant" { default = "app" } -variable "description" { +variable "firewall_description" { description = "Description of the network firewall." type = string default = null } -variable "delete_protection" { +variable "firewall_delete_protection" { description = "A boolean flag indicating whether it is possible to delete the firewall. Defaults to `true`" type = bool default = true } -variable "subnet_change_protection" { +variable "firewall_subnet_change_protection" { description = "A boolean flag indicating whether it is possible to change the associated subnet(s). Defaults to `true`" type = bool default = true @@ -1289,12 +1253,12 @@ variable "firewall_policy_change_protection" { default = true } -variable "logs_retention_in_days" { +variable "firewall_logs_retention_in_days" { type = string description = "Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653." } -variable "logs_kms_key_arn" { +variable "firewall_logs_kms_key_arn" { description = "The Amazon Resource Name (ARN) of the key used for encrypting the log group" type = string } @@ -1303,9 +1267,6 @@ resource "random_id" "suffix_name" { byte_length = 1 } - - - ################################################################################ # Firewall Subnet ################################################################################ @@ -1314,6 +1275,11 @@ variable "firewall_subnets" { description = "A list of firewall subnets inside the VPC" type = list(string) default = [] + + validation { + condition = var.create_network_firewall == false || length(var.firewall_subnets) > 0 + error_message = "The 'firewall_subnets' variable must be set when 'create_network_firewall' is true." + } } variable "firewall_subnet_assign_ipv6_address_on_creation" { @@ -1322,24 +1288,6 @@ variable "firewall_subnet_assign_ipv6_address_on_creation" { default = false } -variable "firewall_subnet_enable_dns64" { - description = "Indicates whether DNS queries made to the Amazon-provided DNS Resolver in this subnet should return synthetic IPv6 addresses for IPv4-only destinations. Default: `true`" - type = bool - default = true -} - -variable "firewall_subnet_enable_resource_name_dns_aaaa_record_on_launch" { - description = "Indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records. Default: `true`" - type = bool - default = true -} - -variable "firewall_subnet_enable_resource_name_dns_a_record_on_launch" { - description = "Indicates whether to respond to DNS queries for instance hostnames with DNS A records. Default: `false`" - type = bool - default = false -} - variable "firewall_subnet_ipv6_prefixes" { description = "Assigns IPv6 firewall subnet id based on the Amazon provided /56 prefix base 10 integer (0-256). Must be of equal length to the corresponding IPv4 subnet list" type = list(string) @@ -1352,22 +1300,10 @@ variable "firewall_subnet_ipv6_native" { default = false } -variable "firewall_subnet_private_dns_hostname_type_on_launch" { - description = "The type of hostnames to assign to instances in the subnet at launch. For IPv6-only subnets, an instance DNS name must be based on the instance ID. For dual-stack and IPv4-only subnets, you can specify whether DNS names use the instance IPv4 address or the instance ID. Valid values: `ip-name`, `resource-name`" - type = string - default = null -} - -variable "firewall_subnet_names" { - description = "Explicit values to use in the Name tag on firewall subnets. If empty, Name tags are generated" - type = list(string) - default = [] -} - variable "firewall_subnet_suffix" { description = "Suffix to append to firewall subnets name" type = string - default = "public" + default = "firewall" } variable "firewall_subnet_tags" { @@ -1376,12 +1312,6 @@ variable "firewall_subnet_tags" { default = {} } -variable "firewall_subnet_tags_per_az" { - description = "Additional tags for the firewall subnets where the primary key is the AZ" - type = map(map(string)) - default = {} -} - variable "firewall_route_table_tags" { description = "Additional tags for the firewall route tables" type = map(string) @@ -1434,16 +1364,6 @@ variable "firewall_acl_tags" { default = {} } - - - - - - - - - - ################################################################################ # Internet Gateway ################################################################################ From 59d736a0d164570f1201c8b5d987a17c549cf4ec Mon Sep 17 00:00:00 2001 From: roger-amorim-dv Date: Tue, 28 Jan 2025 20:13:16 -0300 Subject: [PATCH 3/5] feat: adjust example and minor fixes --- examples/network-firewall/README.md | 41 +++++++++++++++++++++++++++++ examples/network-firewall/main.tf | 17 ++++++------ main.tf | 10 +++---- network-firewall.tf | 29 ++++++++++---------- variables.tf | 14 +++++++--- 5 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 examples/network-firewall/README.md diff --git a/examples/network-firewall/README.md b/examples/network-firewall/README.md new file mode 100644 index 000000000..204913ec6 --- /dev/null +++ b/examples/network-firewall/README.md @@ -0,0 +1,41 @@ +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | >= 5.46 | +| [random](#requirement\_random) | >= 3.0 | + +## Providers + +| Name | Version | +|------|---------| +| [random](#provider\_random) | 3.6.3 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [kms](#module\_kms) | git::https://github.com/withclutch/terraform-modules-registry | aws-kms_v1.194 | +| [vpc](#module\_vpc) | ../../ | n/a | + +## Resources + +| Name | Type | +|------|------| +| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [firewall\_subnets](#output\_firewall\_subnets) | List of IDs of firewall subnets | +| [nat\_public\_ips](#output\_nat\_public\_ips) | List of public Elastic IPs created for AWS NAT Gateway | +| [network\_firewall\_arn](#output\_network\_firewall\_arn) | ARN of the Network Firewall | +| [private\_subnets](#output\_private\_subnets) | List of IDs of private subnets | +| [public\_subnets](#output\_public\_subnets) | List of IDs of public subnets | +| [vpc\_id](#output\_vpc\_id) | The ID of the VPC | diff --git a/examples/network-firewall/main.tf b/examples/network-firewall/main.tf index 35f92e9b2..79cd93567 100644 --- a/examples/network-firewall/main.tf +++ b/examples/network-firewall/main.tf @@ -3,7 +3,7 @@ provider "aws" { } locals { - region = "us-east-2" + region = "us-east-1" name = "nf-example-${random_pet.this.id}" environment = "test" } @@ -18,13 +18,11 @@ resource "random_pet" "this" { ################################################################################ module "kms" { - #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - name = local.name - environment = "test" - description = "KMS key used to test the ${local.name} AWS Network Firewall" - allow_usage_in_network_log_groups = true + name = local.name + environment = "test" + description = "KMS key used to test the ${local.name} AWS Network Firewall" } ################################################################################ @@ -59,10 +57,11 @@ module "vpc" { ######### Firewall Logs ########## firewall_logs_retention_in_days = 14 firewall_logs_kms_key_arn = module.kms.key_arn + create_logging_configuration = true ######### Firewall Rules and Filter ########## - firewall_log_types = ["FLOW", "ALERT"] - firewall_managed_rules = [ + firewall_log_types = ["FLOW", "ALERT"] + firewall_managed_rules = [ "AbusedLegitMalwareDomainsStrictOrder", "BotNetCommandAndControlDomainsStrictOrder", "AbusedLegitBotNetCommandAndControlDomainsStrictOrder", diff --git a/main.tf b/main.tf index 34c74e6a1..2bf350b6f 100644 --- a/main.tf +++ b/main.tf @@ -20,11 +20,11 @@ locals { // TODO - comment what this line does firewall_sync_states = try(module.firewall[0].status[0].sync_states, {}) firewall_vpce = { - for state in local.firewall_sync_states: state.availability_zone => { - cidr_block = one([ for subnet in aws_subnet.firewall : subnet.cidr_block if subnet.id == state.attachment[0].subnet_id ]) - endpoint_id = state.attachment[0].endpoint_id - } + for state in local.firewall_sync_states : state.availability_zone => { + cidr_block = one([for subnet in aws_subnet.firewall : subnet.cidr_block if subnet.id == state.attachment[0].subnet_id]) + endpoint_id = state.attachment[0].endpoint_id } + } # Use `local.vpc_id` to give a hint to Terraform that subnets should be deleted before secondary CIDR blocks can be free! vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this[0].id, "") @@ -325,7 +325,7 @@ resource "aws_route_table" "internet_gateway" { tags = merge( { - "Name" = format("%s-internet-gateway-${var.firewall_subnet_suffix}", var.name) + "Name" = format("%s-internet-gateway-${var.public_subnet_suffix}", var.name) }, var.tags, var.public_route_table_tags, diff --git a/network-firewall.tf b/network-firewall.tf index f32060102..386771ea1 100644 --- a/network-firewall.tf +++ b/network-firewall.tf @@ -4,17 +4,16 @@ locals { name = "${var.name}-network-firewall" } +### TODO - AWS Network Firewall Managed and Custom Rules will be reviewed/implemented in next release - ### module "firewall" { source = "terraform-aws-modules/network-firewall/aws" version = "~> 1.0" count = var.create_network_firewall ? 1 : 0 - name = local.name description = var.firewall_description - delete_protection = var.firewall_delete_protection firewall_policy_change_protection = var.firewall_policy_change_protection subnet_change_protection = var.firewall_subnet_change_protection @@ -29,7 +28,7 @@ module "firewall" { } ### Logging configuration ### - create_logging_configuration = false + create_logging_configuration = var.create_logging_configuration logging_configuration_destination_config = [ { log_destination = { @@ -69,17 +68,17 @@ module "firewall" { policy_stateless_default_actions = ["aws:forward_to_sfe"] policy_stateless_fragment_default_actions = ["aws:forward_to_sfe"] - tags = var.tags // TODO - review these tags + tags = var.tags depends_on = [module.kms, module.logs_alerts, module.logs_flow] } module "logs_alerts" { - source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" count = var.create_network_firewall ? 1 : 0 - name = "nf-network-log-alerts" + name = "${local.name}-alerts" tenant = var.tenant region = var.region environment = var.environment @@ -88,15 +87,17 @@ module "logs_alerts" { kms_key_arn = module.kms[0].key_arn create_datadog_subscription_filter = true + tags = merge(var.tags, var.firewall_log_tags) + depends_on = [module.kms] } module "logs_flow" { - source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-log-group_v1.194" - count = var.create_network_firewall ? 1 : 0 + count = var.create_network_firewall ? 1 : 0 - name = "nf-network-log-flow" + name = "${local.name}-flow" tenant = var.tenant region = var.region environment = var.environment @@ -105,22 +106,22 @@ module "logs_flow" { kms_key_arn = module.kms[0].key_arn create_datadog_subscription_filter = false + tags = merge(var.tags, var.firewall_log_tags) + depends_on = [module.kms] } module "kms" { - #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" count = var.create_network_firewall ? 1 : 0 - description = "KMS key used for ${var.name} AWS Network Firewall" - name = var.name // TODO - review this name + description = "KMS key used for ${local.name} AWS Network Firewall" + name = "${local.name}-kms" region = var.region environment = var.environment namespace = var.namespace tenant = var.tenant tags = var.tags - #allow_usage_in_network_log_groups = true } diff --git a/variables.tf b/variables.tf index 5f819b9b7..33e90dce4 100644 --- a/variables.tf +++ b/variables.tf @@ -1200,10 +1200,16 @@ variable "firewall_log_types" { default = ["FLOW", "ALERT"] } -variable "firewall_log_cloudwatch_log_group_name_prefix" { - description = "Specifies the name prefix of Network Firewall Log Group for Network Firewall logs." - type = string - default = "/aws/network-firewall-log/" +variable "firewall_log_tags" { + description = "Additional tags for the Firewall Logs" + type = map(string) + default = {} +} + +variable "create_logging_configuration" { + description = "Controls if a Logging Configuration should be created" + type = bool + default = false } variable "region" { From 34799c7168f862c8802ebfa9d8fe52d7159f633c Mon Sep 17 00:00:00 2001 From: roger-amorim-dv Date: Tue, 28 Jan 2025 21:30:37 -0300 Subject: [PATCH 4/5] feat: small adjustments --- examples/network-firewall/README.md | 2 +- examples/network-firewall/main.tf | 14 ++++++++------ network-firewall.tf | 23 ++++++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/examples/network-firewall/README.md b/examples/network-firewall/README.md index 204913ec6..4eefc9856 100644 --- a/examples/network-firewall/README.md +++ b/examples/network-firewall/README.md @@ -16,7 +16,7 @@ | Name | Source | Version | |------|--------|---------| -| [kms](#module\_kms) | git::https://github.com/withclutch/terraform-modules-registry | aws-kms_v1.194 | +| [kms](#module\_kms) | /Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms | n/a | | [vpc](#module\_vpc) | ../../ | n/a | ## Resources diff --git a/examples/network-firewall/main.tf b/examples/network-firewall/main.tf index 79cd93567..49d86f4b4 100644 --- a/examples/network-firewall/main.tf +++ b/examples/network-firewall/main.tf @@ -3,8 +3,8 @@ provider "aws" { } locals { - region = "us-east-1" - name = "nf-example-${random_pet.this.id}" + region = "us-east-2" + name_prefix = random_pet.this.id environment = "test" } @@ -18,11 +18,13 @@ resource "random_pet" "this" { ################################################################################ module "kms" { - source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" - name = local.name - environment = "test" - description = "KMS key used to test the ${local.name} AWS Network Firewall" + name = "${local.name_prefix}-kms" + environment = "test" + description = "KMS key used to test the ${local.name_prefix} AWS Network Firewall" + allow_usage_in_network_log_groups = true } ################################################################################ diff --git a/network-firewall.tf b/network-firewall.tf index 386771ea1..bb948ccd4 100644 --- a/network-firewall.tf +++ b/network-firewall.tf @@ -112,16 +112,17 @@ module "logs_flow" { } module "kms" { - source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - - count = var.create_network_firewall ? 1 : 0 - - description = "KMS key used for ${local.name} AWS Network Firewall" - name = "${local.name}-kms" - region = var.region - environment = var.environment - namespace = var.namespace - tenant = var.tenant - tags = var.tags + #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" + source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + count = var.create_network_firewall ? 1 : 0 + + name = "${local.name}-kms" + description = "KMS key used for ${local.name} AWS Network Firewall" + region = var.region + environment = var.environment + namespace = var.namespace + tenant = var.tenant + tags = var.tags + allow_usage_in_network_log_groups = true } From 989089f6861726bd98ca1acecd781211b44c6677 Mon Sep 17 00:00:00 2001 From: roger-amorim-dv Date: Wed, 29 Jan 2025 14:51:01 -0300 Subject: [PATCH 5/5] feat: update KMS module and also update docs --- examples/network-firewall/README.md | 27 +++++++++++++++++++++++++-- examples/network-firewall/main.tf | 3 +-- network-firewall.tf | 3 +-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/examples/network-firewall/README.md b/examples/network-firewall/README.md index 4eefc9856..38d856916 100644 --- a/examples/network-firewall/README.md +++ b/examples/network-firewall/README.md @@ -1,3 +1,26 @@ +VPC with Network Firewall + +This configuration creates a VPC with the following resources across multiple AZs + +- Internet gateway +- NAT gateway per AZ +- public, private and firewall subnets +- AWS network firewall + +The routing tables for such a deployment model follows the [AWS blog suggestion](https://aws.amazon.com/blogs/networking-and-content-delivery/deployment-models-for-aws-network-firewall/), particularly "2) AWS Network Firewall is deployed to protect traffic between an AWS service in a public subnet and IGW" + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which can cost money (AWS Elastic IP, for example). Run `terraform destroy` when you don't need these resources. + ## Requirements | Name | Version | @@ -10,13 +33,13 @@ | Name | Version | |------|---------| -| [random](#provider\_random) | 3.6.3 | +| [random](#provider\_random) | >= 3.0 | ## Modules | Name | Source | Version | |------|--------|---------| -| [kms](#module\_kms) | /Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms | n/a | +| [kms](#module\_kms) | git::https://github.com/withclutch/terraform-modules-registry | aws-kms_v1.204 | | [vpc](#module\_vpc) | ../../ | n/a | ## Resources diff --git a/examples/network-firewall/main.tf b/examples/network-firewall/main.tf index 49d86f4b4..236ab822a 100644 --- a/examples/network-firewall/main.tf +++ b/examples/network-firewall/main.tf @@ -18,8 +18,7 @@ resource "random_pet" "this" { ################################################################################ module "kms" { - #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.204" name = "${local.name_prefix}-kms" environment = "test" diff --git a/network-firewall.tf b/network-firewall.tf index bb948ccd4..2ffeade4e 100644 --- a/network-firewall.tf +++ b/network-firewall.tf @@ -112,8 +112,7 @@ module "logs_flow" { } module "kms" { - #source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.194" - source = "/Users/roger.amorim/Clutch/projects/infrastructure/terraform-modules/modules/aws-kms" + source = "git::https://github.com/withclutch/terraform-modules-registry?ref=aws-kms_v1.204" count = var.create_network_firewall ? 1 : 0 name = "${local.name}-kms"