diff --git a/apps-devstg/base-network/locals.tf b/apps-devstg/base-network/locals.tf index 2c49468fa..aacd92f29 100644 --- a/apps-devstg/base-network/locals.tf +++ b/apps-devstg/base-network/locals.tf @@ -60,6 +60,14 @@ locals { # Allow / Deny VPC private subnets inbound default traffic # default_inbound = [ + { + rule_number = 800 # own private subnet cidr + rule_action = "allow" + from_port = 0 + to_port = 65535 + protocol = "all" + cidr_block = local.private_subnets_cidr[0] + }, { rule_number = 900 # NTP traffic rule_action = "allow" diff --git a/apps-prd/base-network/locals.tf b/apps-prd/base-network/locals.tf index 0fbb0890f..02af24627 100644 --- a/apps-prd/base-network/locals.tf +++ b/apps-prd/base-network/locals.tf @@ -74,6 +74,14 @@ locals { # Allow / Deny VPC private subnets inbound default traffic # default_inbound = [ + { + rule_number = 800 # own private subnet cidr + rule_action = "allow" + from_port = 0 + to_port = 65535 + protocol = "all" + cidr_block = local.private_subnets_cidr[0] + }, { rule_number = 900 # shared pritunl vpn server rule_action = "allow" @@ -135,6 +143,12 @@ locals { bucket = "${var.project}-network-terraform-backend" key = "network/network/terraform.tfstate" } + network-firewall = { + region = var.region + profile = "${var.project}-network-devops" + bucket = "${var.project}-network-terraform-backend" + key = "network/network-firewall/terraform.tfstate" + } } datasources-vpcs = merge( diff --git a/apps-prd/base-network/network_vpc_peering_requester_apps_prd_to_shared.tf b/apps-prd/base-network/network_vpc_peering_requester_apps_prd_to_shared.tf index 8aba12139..a209fc45c 100644 --- a/apps-prd/base-network/network_vpc_peering_requester_apps_prd_to_shared.tf +++ b/apps-prd/base-network/network_vpc_peering_requester_apps_prd_to_shared.tf @@ -9,7 +9,7 @@ # VPC Apps Prd w/ Shared # resource "aws_vpc_peering_connection" "apps_prd_vpc_with_shared_vpc" { - count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_tgw ? 1 : 0 + count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_vpc_attach["apps-prd"] ? 1 : 0 peer_owner_id = var.shared_account_id peer_vpc_id = data.terraform_remote_state.shared-vpcs["shared-base"].outputs.vpc_id @@ -28,7 +28,7 @@ resource "aws_vpc_peering_connection" "apps_prd_vpc_with_shared_vpc" { # read more: https://github.com/binbashar/le-tf-infra-aws/issues/49 # resource "aws_route" "priv_route_table_1_apps_prd_vpc_to_shared_vpc" { - count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_tgw ? 1 : 0 + count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_vpc_attach["apps-prd"] ? 1 : 0 route_table_id = element(module.vpc.private_route_table_ids, 0) destination_cidr_block = data.terraform_remote_state.shared-vpcs["shared-base"].outputs.vpc_cidr_block @@ -36,7 +36,7 @@ resource "aws_route" "priv_route_table_1_apps_prd_vpc_to_shared_vpc" { } resource "aws_route" "pub_route_table_1_apps_prd_vpc_to_shared_vpc" { - count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_tgw ? 1 : 0 + count = var.vpc_shared_created && !data.terraform_remote_state.network-vpcs["network-base"].outputs.enable_vpc_attach["apps-prd"] ? 1 : 0 route_table_id = element(module.vpc.public_route_table_ids, 0) destination_cidr_block = data.terraform_remote_state.shared-vpcs["shared-base"].outputs.vpc_cidr_block diff --git a/apps-prd/k8s-eks/network/locals.tf b/apps-prd/k8s-eks/network/locals.tf index df43f6a45..6b007b080 100644 --- a/apps-prd/k8s-eks/network/locals.tf +++ b/apps-prd/k8s-eks/network/locals.tf @@ -68,6 +68,14 @@ locals { # Allow / Deny VPC private subnets inbound default traffic # default_inbound = [ + { + rule_number = 800 # own private subnet cidr + rule_action = "allow" + from_port = 0 + to_port = 65535 + protocol = "all" + cidr_block = local.private_subnets_cidr[0] + }, { rule_number = 900 # shared pritunl vpn server rule_action = "allow" @@ -137,6 +145,12 @@ locals { bucket = "${var.project}-network-terraform-backend" key = "network/network/terraform.tfstate" } + network-firewall = { + region = var.region + profile = "${var.project}-network-devops" + bucket = "${var.project}-network-terraform-backend" + key = "network/network-firewall/terraform.tfstate" + } } datasources-vpcs = merge( diff --git a/network/base-identities/policies.tf b/network/base-identities/policies.tf index bc08f1ef8..385d6c38b 100644 --- a/network/base-identities/policies.tf +++ b/network/base-identities/policies.tf @@ -45,12 +45,14 @@ resource "aws_iam_policy" "devops_access" { "elasticloadbalancing:*", "es:*", "events:*", + "fms:*", "guardduty:*", "health:*", "iam:*", "kms:*", "lambda:*", "logs:*", + "network-firewall:*", "ram:*", "rds:*", "redshift:*", diff --git a/network/base-network/config.tf b/network/base-network/config.tf index 276bbf7bd..4a71cf5f2 100644 --- a/network/base-network/config.tf +++ b/network/base-network/config.tf @@ -68,9 +68,22 @@ data "terraform_remote_state" "tools-vpn-server" { } } +data "terraform_remote_state" "network-firewall" { + + backend = "s3" + + config = { + region = var.region + profile = "${var.project}-network-devops" + bucket = "${var.project}-network-terraform-backend" + key = "network/network-firewall/terraform.tfstate" + + } +} + # VPC remote states for network data "terraform_remote_state" "network-vpcs" { - for_each = local.network-vpcs + for_each = var.enable_network_firewall ? local.network-vpcs : {} backend = "s3" diff --git a/network/base-network/locals.tf b/network/base-network/locals.tf index ca4a7319d..1ae73fc6f 100644 --- a/network/base-network/locals.tf +++ b/network/base-network/locals.tf @@ -113,11 +113,11 @@ locals { # network network-vpcs = { - network-base = { + network-firewall = { region = var.region profile = "${var.project}-network-devops" bucket = "${var.project}-network-terraform-backend" - key = "network/network/terraform.tfstate" + key = "network/network-firewall/terraform.tfstate" } } @@ -160,9 +160,10 @@ locals { } datasources-vpcs = merge( - data.terraform_remote_state.network-vpcs, # network - data.terraform_remote_state.shared-vpcs, # shared - data.terraform_remote_state.apps-devstg-vpcs, # apps-devstg-vpcs - data.terraform_remote_state.apps-prd-vpcs, # apps-prd-vpcs + data.terraform_remote_state.network-vpcs, # network + #data.terraform_remote_state.shared-vpcs, # shared + #data.terraform_remote_state.apps-devstg-vpcs, # apps-devstg-vpcs + data.terraform_remote_state.apps-prd-vpcs, # apps-prd-vpcs ) } + diff --git a/network/base-network/network.auto.tfvars b/network/base-network/network.auto.tfvars index 4dc17d460..7a2adbe2e 100644 --- a/network/base-network/network.auto.tfvars +++ b/network/base-network/network.auto.tfvars @@ -11,3 +11,6 @@ enable_vpc_attach = { apps-devstg = false apps-prd = false } + +# Network Firewall +enable_network_firewall = false diff --git a/network/base-network/outputs.tf b/network/base-network/outputs.tf index bb58a88a4..6f9d7d4b8 100644 --- a/network/base-network/outputs.tf +++ b/network/base-network/outputs.tf @@ -59,3 +59,23 @@ output "enable_tgw" { description = "This is set to `true` if the Transit Gateway is enabled" value = var.enable_tgw } + +output "enable_vpc_attach" { + description = "VPC attachments per account" + value = var.enable_vpc_attach +} + +output "enable_network_firewall" { + description = "This is set to `true` if the AWS Network Firewall is enabled" + value = var.enable_network_firewall +} + +output "tgw_route_tabe_id" { + description = "TGW default route table id" + value = var.enable_tgw ? module.tgw[0].transit_gateway_route_table_id : null +} + +output "tgw_inspection_route_tabe_id" { + description = "TGW inspection route table id" + value = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_route_table_id : null +} diff --git a/network/base-network/transit_gateway.tf b/network/base-network/transit_gateway.tf index 5cb92fba9..8dc2fe54c 100644 --- a/network/base-network/transit_gateway.tf +++ b/network/base-network/transit_gateway.tf @@ -1,33 +1,34 @@ +# AWS Transit Gateway module "tgw" { source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" count = var.enable_tgw ? 1 : 0 - name = "${var.project}-tgw" + name = "${var.project}-${var.environment}-tgw" ram_resource_share_enabled = true create_transit_gateway = true create_transit_gateway_route_table = true create_transit_gateway_vpc_attachment = false - create_transit_gateway_route_table_association_and_propagation = true + create_transit_gateway_route_table_association_and_propagation = var.enable_network_firewall ? false : true config = merge( # network private lookup(var.enable_vpc_attach, "network", false) ? { - for k, v in data.terraform_remote_state.network-vpcs : v.outputs.vpc_id => { + (module.vpc.vpc_id) = { vpc_id = null vpc_cidr = null subnet_ids = null subnet_route_table_ids = null route_to = null route_to_cidr_blocks = [] - transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network[0].transit_gateway_vpc_attachment_ids[k] + transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network["network-base"].transit_gateway_vpc_attachment_ids["network-base"] static_routes = [ { blackhole = false destination_cidr_block = "0.0.0.0/0" - }, + } ] } } : {}, @@ -40,7 +41,7 @@ module "tgw" { subnet_route_table_ids = null route_to = null route_to_cidr_blocks = null - transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-devstg[0].transit_gateway_vpc_attachment_ids[k] + transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-devstg[k].transit_gateway_vpc_attachment_ids[k] static_routes = null } } : {}, @@ -53,7 +54,7 @@ module "tgw" { subnet_route_table_ids = null route_to = null route_to_cidr_blocks = null - transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-prd[0].transit_gateway_vpc_attachment_ids[k] + transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-prd[k].transit_gateway_vpc_attachment_ids[k] static_routes = null } } : {}, @@ -66,24 +67,175 @@ module "tgw" { subnet_route_table_ids = null route_to = null route_to_cidr_blocks = null - transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_shared[0].transit_gateway_vpc_attachment_ids[k] + transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_shared[k].transit_gateway_vpc_attachment_ids[k] static_routes = null } } : {}, ) + tags = { + Name = "${var.project}-${var.environment}-tgw" + } + providers = { aws = aws.network } } +# +# Route Table defitions +# +module "tgw_inspection_route_table" { + + source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" + + count = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? 1 : 0 + + name = "${var.project}-${var.environment}-inspection" + + existing_transit_gateway_id = module.tgw[0].transit_gateway_id + create_transit_gateway = false + create_transit_gateway_route_table = true + create_transit_gateway_vpc_attachment = false + create_transit_gateway_route_table_association_and_propagation = false + + config = { + inspection = { + vpc_id = null + vpc_cidr = null + subnet_ids = null + subnet_route_table_ids = null + route_to = null + route_to_cidr_blocks = null + transit_gateway_vpc_attachment_id = null + #transit_gateway_vpc_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_vpc_attachment_ids["network-firewall"] + static_routes = [ + { + blackhole = false + destination_cidr_block = "0.0.0.0/0" + } + ] + } + } + + tags = local.tags + + providers = { + aws = aws.network + } +} + +# +# Network Firewall +# +resource "aws_ec2_transit_gateway_route" "inspection_default" { + count = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? 1 : 0 + + destination_cidr_block = "0.0.0.0/0" + transit_gateway_route_table_id = module.tgw_inspection_route_table[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_vpc_attachment_ids["network-firewall"] +} + +resource "aws_ec2_transit_gateway_route" "network_firewall_default" { + count = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? 1 : 0 + + destination_cidr_block = "0.0.0.0/0" + transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network["network-base"].transit_gateway_vpc_attachment_ids["network-base"] +} + +resource "aws_ec2_transit_gateway_route_table_association" "network-inspection-association" { + count = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? 1 : 0 + + transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_vpc_attachment_ids["network-firewall"] +} + +resource "aws_ec2_transit_gateway_route_table_association" "network-base-association" { + count = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? 1 : 0 + + transit_gateway_route_table_id = module.tgw_inspection_route_table[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_network["network-base"].transit_gateway_vpc_attachment_ids["network-base"] +} + +# shared +resource "aws_ec2_transit_gateway_route_table_association" "shared-rt-associations" { + + for_each = { + for k, v in data.terraform_remote_state.shared-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "shared", false) + } + + transit_gateway_route_table_id = module.tgw_inspection_route_table[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_shared[each.key].transit_gateway_vpc_attachment_ids[each.key] +} + +resource "aws_ec2_transit_gateway_route_table_propagation" "shared-rt-propagations" { + for_each = { + for k, v in data.terraform_remote_state.shared-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "shared", false) + } + + transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_shared[each.key].transit_gateway_vpc_attachment_ids[each.key] + +} + +# apps-devstg +resource "aws_ec2_transit_gateway_route_table_association" "apps-devstg-rt-associations" { + + for_each = { + for k, v in data.terraform_remote_state.apps-devstg-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "apps-devstg", false) + } + + transit_gateway_route_table_id = module.tgw_inspection_route_table[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-devstg[each.key].transit_gateway_vpc_attachment_ids[each.key] +} + +resource "aws_ec2_transit_gateway_route_table_propagation" "apps-devstg-rt-propagations" { + for_each = { + for k, v in data.terraform_remote_state.apps-devstg-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "apps-devstg", false) + } + + transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-devstg[each.key].transit_gateway_vpc_attachment_ids[each.key] + +} + +# apps-prd +resource "aws_ec2_transit_gateway_route_table_association" "apps-prd-rt-associations" { + + for_each = { + for k, v in data.terraform_remote_state.apps-prd-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "apps-prd", false) + } + + transit_gateway_route_table_id = module.tgw_inspection_route_table[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-prd[each.key].transit_gateway_vpc_attachment_ids[each.key] +} + +resource "aws_ec2_transit_gateway_route_table_propagation" "apps-prd-rt-propagations" { + for_each = { + for k, v in data.terraform_remote_state.apps-prd-vpcs : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "apps-prd", false) + } + + transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + transit_gateway_attachment_id = module.tgw_vpc_attachments_and_subnet_routes_apps-prd[each.key].transit_gateway_vpc_attachment_ids[each.key] + +} + +# # Update network public RT +# resource "aws_route" "apps_devstg_public_route_to_tgw" { # For each vpc... for_each = { for k, v in data.terraform_remote_state.apps-devstg-vpcs : - k => v if var.enable_tgw + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-devstg", false) } # ...add a route into the network public RT @@ -100,7 +252,7 @@ resource "aws_route" "apps_prd_public_route_to_tgw" { # For each vpc... for_each = { for k, v in data.terraform_remote_state.apps-prd-vpcs : - k => v if var.enable_tgw + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-prd", false) } # ...add a route into the network public RT @@ -118,7 +270,7 @@ resource "aws_route" "shared_public_apps_devstg_route_to_tgw" { # For each vpc... for_each = { for k, v in data.terraform_remote_state.apps-devstg-vpcs : - k => v if var.enable_tgw + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-devstg", false) } # ...add a route into the network public RT @@ -137,7 +289,7 @@ resource "aws_route" "shared_public_apps_prd_route_to_tgw" { # For each vpc... for_each = { for k, v in data.terraform_remote_state.apps-prd-vpcs : - k => v if var.enable_tgw + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-prd", false) } # ...add a route into the network public RT @@ -150,3 +302,44 @@ resource "aws_route" "shared_public_apps_prd_route_to_tgw" { provider = aws.shared } + +# Update Inspection & AWS Network Firewall route tables +data "aws_route_table" "inspection_route_table" { + for_each = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? { + for k, v in data.terraform_remote_state.network-firewall.outputs["inspection_subnets"] : + k => v + } : {} + + subnet_id = each.value +} + +resource "aws_route" "inspection_to_endpoint" { + for_each = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? { + for s in data.terraform_remote_state.network-firewall.outputs["sync_states"][0] : + s["availability_zone"] => s["attachment"] + } : {} + + + route_table_id = data.aws_route_table.inspection_route_table[each.key].id + vpc_endpoint_id = each.value[0]["endpoint_id"] + destination_cidr_block = "0.0.0.0/0" +} + +data "aws_route_table" "network_firewall_route_table" { + for_each = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? { + for k, v in data.terraform_remote_state.network-firewall.outputs["network_firewall_subnets"] : + k => v } : {} + + subnet_id = each.value +} + +resource "aws_route" "network_firewall_tgw" { + for_each = var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) ? { + for s in data.terraform_remote_state.network-firewall.outputs["sync_states"][0] : + s["availability_zone"] => s["attachment"] + } : {} + + route_table_id = data.aws_route_table.network_firewall_route_table[each.key].id + transit_gateway_id = module.tgw[0].transit_gateway_id + destination_cidr_block = "0.0.0.0/0" +} diff --git a/network/base-network/variables.tf b/network/base-network/variables.tf index e4efe89e8..9427b2cb8 100644 --- a/network/base-network/variables.tf +++ b/network/base-network/variables.tf @@ -226,3 +226,9 @@ variable "enable_vpc_attach" { apps-prd = false } } + +variable "enable_network_firewall" { + description = "Enable AWS Network Firewall support" + type = bool + default = false +} diff --git a/network/base-network/vpc_attachments.tf b/network/base-network/vpc_attachments.tf index 54215e0bc..7da446788 100644 --- a/network/base-network/vpc_attachments.tf +++ b/network/base-network/vpc_attachments.tf @@ -1,9 +1,60 @@ +# Network Firewall VPC attachment - Inspection subnets (private) +module "tgw_vpc_attachments_and_subnet_routes_network_firewall" { + + source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" + + for_each = { + for k, v in { + "network-firewall" = data.terraform_remote_state.network-firewall + } : + k => v if var.enable_tgw && var.enable_network_firewall && lookup(var.enable_vpc_attach, "network", false) + } + + # network account can access the Transit Gateway in the network: account since we shared the Transit Gateway with the Organization using Resource Access Manager + existing_transit_gateway_id = module.tgw[0].transit_gateway_id + create_transit_gateway = false + create_transit_gateway_route_table = false + create_transit_gateway_vpc_attachment = true + create_transit_gateway_route_table_association_and_propagation = false + + config = { + (each.key) = { + vpc_id = each.value.outputs.vpc_id + vpc_cidr = each.value.outputs.vpc_cidr_block + subnet_ids = values(each.value.outputs.inspection_subnets) + subnet_route_table_ids = values(each.value.outputs.inspection_route_table_ids) + route_to = null + route_to_cidr_blocks = null + static_routes = null + transit_gateway_vpc_attachment_id = null + } + } + + tags = { + Name = "${var.project}-${each.key}-vpc" + } + + providers = { + aws = aws.network + } +} + # network VPC attachments (private) module "tgw_vpc_attachments_and_subnet_routes_network" { source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" - count = var.enable_tgw && var.enable_vpc_attach["network"] ? 1 : 0 + for_each = { + for k, v in { + network-base = { + vpc_id = module.vpc.vpc_id + vpc_cidr_block = local.vpc_cidr_block + private_subnets = module.vpc.private_subnets + private_route_table_ids = module.vpc.private_route_table_ids + } + } : + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "network", false) + } # network account can access the Transit Gateway in the network: account since we shared the Transit Gateway with the Organization using Resource Access Manager existing_transit_gateway_id = module.tgw[0].transit_gateway_id @@ -14,11 +65,11 @@ module "tgw_vpc_attachments_and_subnet_routes_network" { create_transit_gateway_route_table_association_and_propagation = false config = { - for k, v in data.terraform_remote_state.network-vpcs : k => { - vpc_id = v.outputs.vpc_id - vpc_cidr = v.outputs.vpc_cidr_block - subnet_ids = v.outputs.private_subnets - subnet_route_table_ids = v.outputs.private_route_table_ids + (each.key) = { + vpc_id = each.value.vpc_id + vpc_cidr = each.value.vpc_cidr_block + subnet_ids = each.value.private_subnets + subnet_route_table_ids = each.value.private_route_table_ids route_to = null route_to_cidr_blocks = null static_routes = null @@ -27,7 +78,7 @@ module "tgw_vpc_attachments_and_subnet_routes_network" { } tags = { - Name = "${var.project}-network-vpc-attach" + Name = "${var.project}-${each.key}-vpc" } providers = { @@ -40,36 +91,38 @@ module "tgw_vpc_attachments_and_subnet_routes_apps-devstg" { source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" - count = var.enable_tgw && var.enable_vpc_attach["apps-devstg"] ? 1 : 0 + for_each = { + for k, v in data.terraform_remote_state.apps-devstg-vpcs : + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-devstg", false) + } # apps-devstg account can access the Transit Gateway in the network account since we shared the Transit Gateway with the Organization using Resource Access Manager existing_transit_gateway_id = module.tgw[0].transit_gateway_id - existing_transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + existing_transit_gateway_route_table_id = var.enable_tgw && var.enable_network_firewall ? module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_route_table_id : module.tgw[0].transit_gateway_route_table_id create_transit_gateway = false create_transit_gateway_route_table = false create_transit_gateway_vpc_attachment = true create_transit_gateway_route_table_association_and_propagation = false config = { - for k, v in data.terraform_remote_state.apps-devstg-vpcs : k => { - vpc_id = v.outputs.vpc_id - vpc_cidr = v.outputs.vpc_cidr_block - subnet_ids = v.outputs.private_subnets - subnet_route_table_ids = v.outputs.private_route_table_ids + (each.key) = { + vpc_id = each.value.outputs.vpc_id + vpc_cidr = each.value.outputs.vpc_cidr_block + subnet_ids = each.value.outputs.private_subnets + subnet_route_table_ids = each.value.outputs.private_route_table_ids route_to = null route_to_cidr_blocks = concat( ["0.0.0.0/0"], #tgw #[for v in values(data.terraform_remote_state.shared-vpcs) : v.outputs.vpc_cidr_block], # shared #[for v in values(data.terraform_remote_state.network-vpcs) : v.outputs.vpc_cidr_block], # network ) - static_routes = null transit_gateway_vpc_attachment_id = null } } tags = { - Name = "${var.project}-apps-devstg-vpc-attach" + Name = "${var.project}-apps-devstg-vpc" } providers = { @@ -82,28 +135,31 @@ module "tgw_vpc_attachments_and_subnet_routes_apps-prd" { source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" - count = var.enable_tgw && var.enable_vpc_attach["apps-prd"] ? 1 : 0 + for_each = { + for k, v in data.terraform_remote_state.apps-prd-vpcs : + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "apps-prd", false) + } - name = "${var.project}-apps-prd-vpc-attach" + name = "${var.project}-apps-prd-vpc" # apps-prd account can access the Transit Gateway in the network account since we shared the Transit Gateway with the Organization using Resource Access Manager existing_transit_gateway_id = module.tgw[0].transit_gateway_id - existing_transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + existing_transit_gateway_route_table_id = var.enable_tgw && var.enable_network_firewall ? module.tgw_inspection_route_table[0].transit_gateway_route_table_id : module.tgw[0].transit_gateway_route_table_id create_transit_gateway = false create_transit_gateway_route_table = false create_transit_gateway_vpc_attachment = true create_transit_gateway_route_table_association_and_propagation = false config = { - for k, v in data.terraform_remote_state.apps-prd-vpcs : k => { - vpc_id = v.outputs.vpc_id - vpc_cidr = v.outputs.vpc_cidr_block - subnet_ids = v.outputs.private_subnets - subnet_route_table_ids = v.outputs.private_route_table_ids + (each.key) = { + vpc_id = each.value.outputs.vpc_id + vpc_cidr = each.value.outputs.vpc_cidr_block + subnet_ids = each.value.outputs.private_subnets + subnet_route_table_ids = each.value.outputs.private_route_table_ids route_to = null route_to_cidr_blocks = concat( - ["0.0.0.0/0"], #tgw - [for v in values(data.terraform_remote_state.shared-vpcs) : v.outputs.vpc_cidr_block], # shared + ["0.0.0.0/0"], #tgw + #[for v in values(data.terraform_remote_state.shared-vpcs) : v.outputs.vpc_cidr_block], # shared #[for v in values(data.terraform_remote_state.network-vpcs) : v.outputs.vpc_cidr_block], # network ) static_routes = null @@ -111,9 +167,7 @@ module "tgw_vpc_attachments_and_subnet_routes_apps-prd" { } } - tags = { - Name = "${var.project}-apps-prd-vpc-attach" - } + tags = local.tags providers = { aws = aws.apps-prd @@ -125,37 +179,38 @@ module "tgw_vpc_attachments_and_subnet_routes_shared" { source = "github.com/binbashar/terraform-aws-transit-gateway?ref=0.4.0" - count = var.enable_tgw && var.enable_vpc_attach["shared"] ? 1 : 0 + for_each = { + for k, v in data.terraform_remote_state.shared-vpcs : + k => v if var.enable_tgw && lookup(var.enable_vpc_attach, "shared", false) + } # apps-devstg account can access the Transit Gateway in the network account since we shared the Transit Gateway with the Organization using Resource Access Manager existing_transit_gateway_id = module.tgw[0].transit_gateway_id - existing_transit_gateway_route_table_id = module.tgw[0].transit_gateway_route_table_id + existing_transit_gateway_route_table_id = var.enable_tgw && lookup(var.enable_vpc_attach, "shared", false) ? try(module.tgw_vpc_attachments_and_subnet_routes_network_firewall["network-firewall"].transit_gateway_route_table_id, null) : module.tgw[0].transit_gateway_route_table_id create_transit_gateway = false create_transit_gateway_route_table = false create_transit_gateway_vpc_attachment = true create_transit_gateway_route_table_association_and_propagation = false config = { - for k, v in data.terraform_remote_state.shared-vpcs : k => { - vpc_id = v.outputs.vpc_id - vpc_cidr = v.outputs.vpc_cidr_block - subnet_ids = v.outputs.private_subnets - subnet_route_table_ids = v.outputs.private_route_table_ids + (each.key) = { + vpc_id = each.value.outputs.vpc_id + vpc_cidr = each.value.outputs.vpc_cidr_block + subnet_ids = each.value.outputs.private_subnets + subnet_route_table_ids = each.value.outputs.private_route_table_ids route_to = null route_to_cidr_blocks = concat( - #["0.0.0.0/0"], #tgw + ["0.0.0.0/0"], #tgw #[for v in values(data.terraform_remote_state.shared-vpcs) : v.outputs.vpc_cidr_block], # shared #[for v in values(data.terraform_remote_state.network-vpcs) : v.outputs.vpc_cidr_block], # network - ["172.19.32.0/20"], # apps-prd/k8s-eks ) - static_routes = null transit_gateway_vpc_attachment_id = null } } tags = { - Name = "${var.project}-shared-vpc-attach" + Name = "${var.project}-shared-vpc" } providers = { diff --git a/network/network-firewall/account.tf b/network/network-firewall/account.tf new file mode 100644 index 000000000..8fc4b38cc --- /dev/null +++ b/network/network-firewall/account.tf @@ -0,0 +1 @@ +data "aws_caller_identity" "current" {} diff --git a/network/network-firewall/config.tf b/network/network-firewall/config.tf new file mode 100644 index 000000000..e85d78775 --- /dev/null +++ b/network/network-firewall/config.tf @@ -0,0 +1,41 @@ +#=============================# +# AWS Provider Settings # +#=============================# +provider "aws" { + region = var.region + profile = var.profile + shared_credentials_file = "~/.aws/${var.project}/config" +} + +#=============================# +# Backend Config (partial) # +#=============================# +terraform { + required_version = ">= 0.14.11" + + required_providers { + aws = "~> 3.0" + } + + backend "s3" { + key = "network/network-firewall/terraform.tfstate" + } +} + +#=============================# +# Data sources # +#=============================# + +# +# Inspection Network +# +data "terraform_remote_state" "inspection_vpc" { + backend = "s3" + + config = { + region = var.region + profile = "${var.project}-network-devops" + bucket = "${var.project}-network-terraform-backend" + key = "network/inspection-network/terraform.tfstate" + } +} diff --git a/network/network-firewall/firewall.tf b/network/network-firewall/firewall.tf new file mode 100644 index 000000000..c2d63bd7a --- /dev/null +++ b/network/network-firewall/firewall.tf @@ -0,0 +1,117 @@ +# Firewall +resource "aws_networkfirewall_firewall" "firewall" { + + count = var.enable_network_firewall ? 1 : 0 + + name = "${var.project}-${var.environment}-firewall" + firewall_policy_arn = aws_networkfirewall_firewall_policy.policy[0].arn + vpc_id = module.vpc.vpc_id + + # subnet_mapping + dynamic "subnet_mapping" { + for_each = values(module.network_firewall_private_subnets.az_subnet_ids) + + content { + subnet_id = subnet_mapping.value + } + } + + tags = local.tags +} + +# Policy +resource "aws_networkfirewall_firewall_policy" "policy" { + + count = var.enable_network_firewall ? 1 : 0 + + name = "${var.project}-${var.environment}-firewall-policy" + + firewall_policy { + stateless_default_actions = ["aws:pass"] + stateless_fragment_default_actions = ["aws:drop"] + + stateless_rule_group_reference { + priority = 10 + resource_arn = aws_networkfirewall_rule_group.staless_rule_group[0].arn + } + + stateful_rule_group_reference { + resource_arn = aws_networkfirewall_rule_group.staleful_rule_group[0].arn + } + } + + tags = local.tags +} + +# Stateless rule groups +resource "aws_networkfirewall_rule_group" "staless_rule_group" { + + count = var.enable_network_firewall ? 1 : 0 + + name = "${var.project}-${var.environment}-default-forward" + + description = "Stateless Rule" + capacity = 100 + type = "STATELESS" + rule_group { + rules_source { + stateless_rules_and_custom_actions { + stateless_rule { + priority = 10 + rule_definition { + actions = ["aws:forward_to_sfe"] + match_attributes { + source { + address_definition = "0.0.0.0/0" + } + #source_port { + # from_port = 0 + # to_port = 0 + #} + destination { + address_definition = "0.0.0.0/0" + } + #destination_port { + # from_port = 0 + # to_port = 0 + #} + } + } + } + } + } + } + + tags = local.tags +} + +# Stateful rule groups +resource "aws_networkfirewall_rule_group" "staleful_rule_group" { + + count = var.enable_network_firewall ? 1 : 0 + + name = "${var.project}-${var.environment}-deny-wikipedia" + capacity = 50 + description = "Deny Wikipedia access" + type = "STATEFUL" + rule_group { + rule_variables { + ip_sets { + key = "HOME_NET" + ip_set { + definition = ["0.0.0.0/0"] + } + + } + } + rules_source { + rules_source_list { + generated_rules_type = "DENYLIST" + target_types = ["TLS_SNI", "HTTP_HOST"] + targets = [".wikipedia.org"] + } + } + } + + tags = local.tags +} diff --git a/network/network-firewall/locals.tf b/network/network-firewall/locals.tf new file mode 100644 index 000000000..5f6b322fb --- /dev/null +++ b/network/network-firewall/locals.tf @@ -0,0 +1,35 @@ +# Inspection VPC +locals { + + tags = { + Terraform = "true" + Environment = var.environment + } + + # Network Local Vars + # https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html + vpc_name = "${var.project}-${var.environment}-firewall-vpc" + vpc_cidr_block = "172.20.16.0/20" + azs = [ + "${var.region}a", + #"${var.region}b", + #"${var.region}c" + ] + + # This includes the inspection and te firewall subnets + private_subnets_cidr = ["172.20.16.0/20"] + + inspection_subnets_cidr = ["172.20.16.0/21"] + inspection_subnets = [ + "172.20.16.0/23", + #"172.20.18.0/23", + #"172.20.20.0/23", + ] + + network_firewall_subnets_cidr = ["172.20.24.0/21"] + network_firewall_subnets = [ + "172.20.24.0/23", + #"172.20.26.0/23", + #"172.20.28.0/23", + ] +} diff --git a/network/network-firewall/network.auto.tfvars b/network/network-firewall/network.auto.tfvars new file mode 100644 index 000000000..ebfd5ff13 --- /dev/null +++ b/network/network-firewall/network.auto.tfvars @@ -0,0 +1,2 @@ +# Network Firewall +enable_network_firewall = false diff --git a/network/network-firewall/network.tf b/network/network-firewall/network.tf new file mode 100644 index 000000000..f6c879c0b --- /dev/null +++ b/network/network-firewall/network.tf @@ -0,0 +1,34 @@ +## Inspection VPC +module "vpc" { + source = "github.com/binbashar/terraform-aws-vpc-base?ref=0.26.1" + + assign_generated_ipv6_cidr_block = false + name = local.vpc_name + cidr_block = local.vpc_cidr_block + tags = local.tags +} + +module "inspection_private_subnets" { + source = "cloudposse/multi-az-subnets/aws" + + name = "${var.project}-${var.environment}-inspection" + vpc_id = module.vpc.vpc_id + availability_zones = local.azs + cidr_block = local.inspection_subnets_cidr[0] + type = "private" + max_subnets = 4 + tags = local.tags + +} + +module "network_firewall_private_subnets" { + source = "github.com/binbashar/terraform-aws-multi-az-subnets?ref=0.14.0" + + name = "${var.project}-${var.environment}-firewall" + vpc_id = module.vpc.vpc_id + availability_zones = local.azs + cidr_block = local.network_firewall_subnets_cidr[0] + type = "private" + max_subnets = 4 + tags = local.tags +} diff --git a/network/network-firewall/outputs.tf b/network/network-firewall/outputs.tf new file mode 100644 index 000000000..924712dc6 --- /dev/null +++ b/network/network-firewall/outputs.tf @@ -0,0 +1,66 @@ +# VPC ID +output "vpc_id" { + description = "VPC ID" + value = module.vpc.vpc_id +} + +output "vpc_name" { + description = "VPC Name" + value = local.vpc_name +} + +output "vpc_cidr_block" { + description = "VPC CIDR Block" + value = local.vpc_cidr_block +} + +# Subnets +output "inspection_subnets" { + description = "Map of AZ names to subnet IDs of inspection subnets" + value = module.inspection_private_subnets.az_subnet_ids +} + +output "network_firewall_subnets" { + description = "Map of AZ names to subnet IDs of network firewall subnets" + value = module.network_firewall_private_subnets.az_subnet_ids +} + +output "private_subnets_cidr" { + description = "CIDRS of private subnets" + value = local.private_subnets_cidr +} +output "inspection_subnets_cidr" { + description = "CIDRS of inspection subnets" + value = local.inspection_subnets_cidr +} + +output "network_firewall_subnets_cidr" { + description = "CIDR of network firewall subnets" + value = local.network_firewall_subnets_cidr +} + +output "network_firewall_route_table_ids" { + description = "Map of AZ names to Route Table IDs of network_firewall route tables" + value = module.network_firewall_private_subnets.az_route_table_ids +} + +output "inspection_route_table_ids" { + description = "Map of AZ names to Route Table IDs of inspection route tables" + value = module.inspection_private_subnets.az_route_table_ids +} + +# Network Firewall +output "network_firewall_status" { + description = "Nested list of information about the current status of the firewall." + value = var.enable_network_firewall ? aws_networkfirewall_firewall.firewall[0].firewall_status : [] +} + +output "sync_states" { + description = "Set of subnets configured for use by the firewall." + value = var.enable_network_firewall ? aws_networkfirewall_firewall.firewall[0].firewall_status.*.sync_states : [] +} + +output "network_firewall_subnet_id_endpoint_id" { + description = "Map of endpoint_id per subnet_id" + value = var.enable_network_firewall ? { for v in aws_networkfirewall_firewall.firewall[0].firewall_status[0]["sync_states"].*.attachment : v[0]["subnet_id"] => v[0]["endpoint_id"] } : {} +} diff --git a/network/network-firewall/variables.tf b/network/network-firewall/variables.tf new file mode 100644 index 000000000..100516e76 --- /dev/null +++ b/network/network-firewall/variables.tf @@ -0,0 +1,202 @@ +# +# config/backend.config +# +#================================# +# Terraform AWS Backend Settings # +#================================# +variable "region" { + type = string + description = "AWS Region" +} + +variable "profile" { + type = string + description = "AWS Profile (required by the backend but also used for other resources)" +} + +variable "bucket" { + type = string + description = "AWS S3 TF State Backend Bucket" +} + +variable "dynamodb_table" { + type = string + description = "AWS DynamoDB TF Lock state table name" +} + +variable "encrypt" { + type = bool + description = "Enable AWS DynamoDB with server side encryption" +} + +# +# config/base.config +# +#=============================# +# Project Variables # +#=============================# +variable "project" { + type = string + description = "Project Name" +} + +variable "project_long" { + type = string + description = "Project Long Name" +} + +variable "environment" { + type = string + description = "Environment Name" +} + +# +# config/extra.config +# +#=============================# +# Accounts & Extra Vars # +#=============================# +variable "region_secondary" { + type = string + description = "AWS Scondary Region for HA" +} + +variable "root_account_id" { + type = string + description = "Account: Root" +} + +variable "security_account_id" { + type = string + description = "Account: Security & Users Management" +} + +variable "shared_account_id" { + type = string + description = "Account: Shared Resources" +} + +variable "appsdevstg_account_id" { + type = string + description = "Account: Dev Modules & Libs" +} + +variable "appsprd_account_id" { + type = string + description = "Account: Prod Modules & Libs" +} + +variable "vault_address" { + type = string + description = "Vault Address" +} + +variable "vault_token" { + type = string + description = "Vault Token" +} + +#===========================================# +# Networking # +#===========================================# +variable "vpc_apps_devstg_created" { + description = "true if Apps Dev account VPC is created for Peering purposes" + type = bool + default = true +} + +variable "vpc_apps_devstg_eks_created" { + description = "true if Apps Dev account EKS VPC is created for Peering purposes" + type = bool + default = true +} + +variable "vpc_apps_prd_created" { + description = "true if Apps Prd account VPC is created for Peering purposes" + type = bool + default = true +} + +variable "vpc_vault_hvn_created" { + description = "true if the Hahicorp Vault Cloud HVN account VPC is created for Peering purposes" + type = bool + default = true +} + +variable "vpc_vault_hvn_peering_connection_id" { + description = "Hahicorp Vault Cloud HVN VPC peering ID" + type = string + default = "pcx-0109e4ef7e784ee06" +} + +variable "vpc_vault_hvn_cird" { + description = "Hahicorp Vault Cloud HVN VPC CIDR segment" + type = string + default = "172.25.16.0/20" +} + +variable "vpc_enable_nat_gateway" { + description = "Enable NAT Gatewway" + type = bool + default = false +} + +variable "vpc_single_nat_gateway" { + description = "Single NAT Gatewway" + type = bool + default = true +} + +variable "vpc_enable_dns_hostnames" { + description = "Enable DNS HOSTNAME" + type = bool + default = true +} + +variable "vpc_enable_vpn_gateway" { + description = "Enable VPN Gateway" + type = bool + default = false +} + +variable "vpc_enable_s3_endpoint" { + description = "Enable S3 endpoint" + type = bool + default = true +} + +variable "vpc_enable_dynamodb_endpoint" { + description = "Enable DynamoDB endpoint" + type = bool + default = true +} + +variable "enable_kms_endpoint" { + description = "Enable KMS endpoint" + type = bool + default = false +} + +variable "manage_default_network_acl" { + description = "Manage default Network ACL" + type = bool + default = false +} + +variable "public_dedicated_network_acl" { + description = "Manage default Network ACL" + type = bool + default = true +} + +variable "private_dedicated_network_acl" { + description = "Manage default Network ACL" + type = bool + default = true +} + +variable "enable_network_firewall" { + description = "Enable AWS Network Firewall support" + type = bool + default = false +} diff --git a/shared/base-network/config.tf b/shared/base-network/config.tf index 2784a6279..8ff71ca66 100644 --- a/shared/base-network/config.tf +++ b/shared/base-network/config.tf @@ -40,10 +40,27 @@ data "terraform_remote_state" "tools-vpn-server" { } } +# VPC remote states for network +data "terraform_remote_state" "network-vpcs" { + for_each = local.network-vpcs + + backend = "s3" + + config = { + region = lookup(each.value, "region") + profile = lookup(each.value, "profile") + bucket = lookup(each.value, "bucket") + key = lookup(each.value, "key") + } +} + # VPC remote states for apps-devstg data "terraform_remote_state" "apps-devstg-vpcs" { - for_each = local.apps-devstg-vpcs + for_each = { + for k, v in local.apps-devstg-vpcs : + k => v if !v["tgw"] + } backend = "s3" @@ -58,7 +75,10 @@ data "terraform_remote_state" "apps-devstg-vpcs" { # VPC remote states for apps-prd data "terraform_remote_state" "apps-prd-vpcs" { - for_each = local.apps-prd-vpcs + for_each = { + for k, v in local.apps-prd-vpcs : + k => v if !v["tgw"] + } backend = "s3" diff --git a/shared/base-network/locals.tf b/shared/base-network/locals.tf index 54b6aacfb..13df6393e 100644 --- a/shared/base-network/locals.tf +++ b/shared/base-network/locals.tf @@ -51,6 +51,14 @@ locals { # Allow / Deny VPC private subnets inbound default traffic # default_inbound = [ + { + rule_number = 800 # own private subnet cidr + rule_action = "allow" + from_port = 0 + to_port = 65535 + protocol = "all" + cidr_block = local.private_subnets_cidr[0] + }, { rule_number = 900 # shared pritunl vpn server rule_action = "allow" @@ -102,6 +110,16 @@ locals { # Data source definitions # + # network + network-vpcs = { + network-base = { + region = var.region + profile = "${var.project}-network-devops" + bucket = "${var.project}-network-terraform-backend" + key = "network/network/terraform.tfstate" + } + } + # apps-devstg apps-devstg-vpcs = { apps-devstg-base = { @@ -109,18 +127,21 @@ locals { profile = "${var.project}-apps-devstg-devops" bucket = "${var.project}-apps-devstg-terraform-backend" key = "apps-devstg/network/terraform.tfstate" + tgw = false } apps-devstg-k8s-eks = { region = var.region profile = "${var.project}-apps-devstg-devops" bucket = "${var.project}-apps-devstg-terraform-backend" key = "apps-devstg/k8s-eks/network/terraform.tfstate" + tgw = false } apps-devstg-eks-demoapps = { region = var.region profile = "${var.project}-apps-devstg-devops" bucket = "${var.project}-apps-devstg-terraform-backend" key = "apps-devstg/k8s-eks-demoapps/network/terraform.tfstate" + tgw = false } } @@ -131,12 +152,14 @@ locals { profile = "${var.project}-apps-prd-devops" bucket = "${var.project}-apps-prd-terraform-backend" key = "apps-prd/network/terraform.tfstate" + tgw = false } apps-prd-k8s-eks = { region = var.region profile = "${var.project}-apps-prd-devops" bucket = "${var.project}-apps-prd-terraform-backend" key = "apps-prd/k8s-eks/network/terraform.tfstate" + tgw = false } }