Skip to content

Coalfire-CF/terraform-aws-vpc-nfw

Repository files navigation

Coalfire

AWS VPC NFW Terraform Module

Terraform module which creates VPC and/or NFW resources on AWS.

These types of resources are supported:

Submodule

Network Firewall

Assumptions

  • Networking resources, including VPCs, Transit Gateways and Network Firewalls, are designed to be deployed under a single state.
  • Outputs of this module can be referenced via terraform state in the following manner:
    • module.mgmt_vpc.private_subnets["mvp-mgmt-compute-us-gov-west-1a"]
    • data.terraform_remote_state.network.outputs.public_subnets["mvp-mgmt-dmz-us-gov-west-1a"]
  • This is designed to automatically reference the firewall subnets when opted to be created.
  • Automatically adds AWS region to the subnet name upon creation
  • The private route table IDs includes the rtb IDs from database subnets as well

Usage

If networks are being created with the goal of peering, it is best practice to build and deploy those resources within the same Terraform state. This allows for efficient referencing of peer subnets and CIDRs to facilitate a proper routing architecture.

module "mgmt_vpc" {
  source = "github.com/Coalfire-CF/terraform-aws-vpc-nfw"
  providers = {
    aws = aws.mgmt
  }

  name = "${var.resource_prefix}-mgmt"

  delete_protection = var.delete_protection

  cidr = var.mgmt_vpc_cidr

  azs = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]]

  private_subnets = local.private_subnets # Map of Name -> CIDR

  public_subnets       = local.public_subnets # Map of Name -> CIDR
  public_subnet_suffix = "public"

  single_nat_gateway     = false
  enable_nat_gateway     = true
  one_nat_gateway_per_az = true
  enable_vpn_gateway     = false
  enable_dns_hostnames   = true

  flow_log_destination_type              = "cloud-watch-logs"
  cloudwatch_log_group_retention_in_days = 30
  cloudwatch_log_group_kms_key_id        = data.terraform_remote_state.day0.outputs.cloudwatch_kms_key_arn

  ### Network Firewall ###
  deploy_aws_nfw                        = var.deploy_aws_nfw
  aws_nfw_prefix                        = var.resource_prefix
  aws_nfw_name                          = "pak-nfw"
  aws_nfw_stateless_rule_group          = local.stateless_rule_group_shrd_svcs
  aws_nfw_fivetuple_stateful_rule_group = local.fivetuple_rule_group_shrd_svcs
  aws_nfw_domain_stateful_rule_group    = local.domain_stateful_rule_group_shrd_svcs
  aws_nfw_suricata_stateful_rule_group  = local.suricata_rule_group_shrd_svcs # Requires creation of local file with fw rules
  nfw_kms_key_id                        = module.nfw_kms_key.kms_key_arn

  #When deploying NFW, firewall_subnets must be specified
  firewall_subnets       = local.firewall_subnets
  firewall_subnet_suffix = "firewall"

  # TLS Outbound Inspection
  enable_tls_inspection = var.enable_tls_inspection # deploy_aws_nfw must be set to true to enable this
  tls_cert_arn          = var.tls_cert_arn
  tls_destination_cidrs = var.tls_destination_cidrs # Set these to the NAT gateways to filter outbound traffic without affecting the hosted VPN

  /* Add Additional tags here */
  tags = {
    Owner       = var.resource_prefix
    Environment = "mgmt"
    createdBy   = "terraform"
  }
}

AWS Networking deployment without AWS Network Firewall

module "mgmt_vpc" {
  source = "github.com/Coalfire-CF/terraform-aws-vpc-nfw"
  providers = {
    aws = aws.mgmt
  }

  name = "${var.resource_prefix}-mgmt"

  delete_protection = var.delete_protection

  cidr = var.mgmt_vpc_cidr

  azs = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]]

  private_subnets = local.private_subnets # Map of Name -> CIDR

  public_subnets       = local.public_subnets # Map of Name -> CIDR
  public_subnet_suffix = "public"

  single_nat_gateway     = false
  enable_nat_gateway     = true
  one_nat_gateway_per_az = true
  enable_vpn_gateway     = false
  enable_dns_hostnames   = true

  flow_log_destination_type              = "cloud-watch-logs"
  cloudwatch_log_group_retention_in_days = 30
  cloudwatch_log_group_kms_key_id        = data.terraform_remote_state.day0.outputs.cloudwatch_kms_key_arn

  /* Add Additional tags here */
  tags = {
    Owner       = var.resource_prefix
    Environment = "mgmt"
    createdBy   = "terraform"
  }
}

Custom Routes

There are variables provided for each subnet type:

  • database_custom_routes
  • elasticache_custom_routes
  • firewall_custom_routes
  • intra_custom_routes
  • private_custom_routes
  • public_custom_routes
  • redshift_custom_routes

These variables are lists of objects.

Example of custom public routes:

public_custom_routes = [
    {
      destination_cidr_block = "8.8.8.8/32"
      internet_route              = true
    },
    {
      destination_cidr_block = "4.4.4.4/32"
      internet_route              = true
    }
  ]

An "internet_route" boolean sets a default to send traffic to the created IGW as a target (required), or to the NFW endpoint if created.

Some variables expose different expected values based on sensible assumptions. For example, a public custom route would not expose NAT gateway as a target, and likewise private subnets will not allow Internet Gateway to be a target.

The variables can be further inspected to see what parameters and types are expected.

Requirements

Name Version
terraform ~>1.5
aws >= 5.15.0, < 6.0

Providers

Name Version
aws 5.64.0

Modules

Name Source Version
aws_network_firewall ./modules/aws-network-firewall n/a

Resources

Name Type
aws_cloudwatch_log_group.this resource
aws_db_subnet_group.database resource
aws_default_security_group.default resource
aws_default_vpc.this resource
aws_eip.nat resource
aws_elasticache_subnet_group.elasticache resource
aws_flow_log.this resource
aws_iam_policy.flowlogs_policy resource
aws_iam_role.flowlogs_role resource
aws_iam_role_policy_attachment.flowlogs_policy resource
aws_internet_gateway.this resource
aws_nat_gateway.this resource
aws_redshift_subnet_group.redshift resource
aws_route.aws_nfw_igw_rt resource
aws_route.aws_nfw_public_internet resource
aws_route.database_custom resource
aws_route.elasticache_custom resource
aws_route.firewall_custom resource
aws_route.intra_custom resource
aws_route.nfw_public_custom resource
aws_route.nfw_public_internet_gateway resource
aws_route.private_custom resource
aws_route.private_nat_gateway resource
aws_route.public_custom resource
aws_route.public_internet_gateway resource
aws_route.redshift_custom resource
aws_route.tgw_custom resource
aws_route_table.aws_nfw_igw_rtb resource
aws_route_table.database resource
aws_route_table.elasticache resource
aws_route_table.firewall resource
aws_route_table.intra resource
aws_route_table.private resource
aws_route_table.public resource
aws_route_table.redshift resource
aws_route_table.tgw resource
aws_route_table_association.database resource
aws_route_table_association.elasticache resource
aws_route_table_association.firewall resource
aws_route_table_association.intra resource
aws_route_table_association.nfw_igw resource
aws_route_table_association.nfw_public resource
aws_route_table_association.private resource
aws_route_table_association.public resource
aws_route_table_association.redshift resource
aws_route_table_association.tgw resource
aws_subnet.database resource
aws_subnet.elasticache resource
aws_subnet.firewall resource
aws_subnet.intra resource
aws_subnet.private resource
aws_subnet.public resource
aws_subnet.redshift resource
aws_subnet.tgw resource
aws_vpc.this resource
aws_vpc_dhcp_options.this resource
aws_vpc_dhcp_options_association.this resource
aws_vpc_endpoint.dynamodb resource
aws_vpc_endpoint.s3 resource
aws_vpc_endpoint_route_table_association.intra_dynamodb resource
aws_vpc_endpoint_route_table_association.intra_s3 resource
aws_vpc_endpoint_route_table_association.private_dynamodb resource
aws_vpc_endpoint_route_table_association.private_s3 resource
aws_vpc_endpoint_route_table_association.public_dynamodb resource
aws_vpc_endpoint_route_table_association.public_s3 resource
aws_vpc_ipv4_cidr_block_association.this resource
aws_vpn_gateway.this resource
aws_vpn_gateway_attachment.this resource
aws_vpn_gateway_route_propagation.private resource
aws_vpn_gateway_route_propagation.public resource
aws_iam_policy_document.flow_log_cloudwatch_assume_role data source
aws_iam_policy_document.vpc_flow_log_cloudwatch data source
aws_vpc_endpoint_service.dynamodb data source
aws_vpc_endpoint_service.s3 data source

Inputs

Name Description Type Default Required
assign_generated_ipv6_cidr_block Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block bool false no
aws_nfw_domain_stateful_rule_group Config for domain type stateful rule group
list(object({
name = string
description = string
capacity = number
domain_list = list(string)
actions = string
protocols = list(string)
rules_file = optional(string, "")
rule_variables = optional(object({
ip_sets = list(object({
key = string
ip_set = list(string)
}))
port_sets = list(object({
key = string
port_sets = list(string)
}))
}), {
ip_sets = []
port_sets = []
})
}))
[] no
aws_nfw_fivetuple_stateful_rule_group Config for 5-tuple type stateful rule group
list(object({
name = string
description = string
capacity = number
rule_config = list(object({
description = string
protocol = string
source_ipaddress = string
source_port = string
direction = string
destination_port = string
destination_ipaddress = string
sid = number
actions = map(string)
}))
}))
[] no
aws_nfw_name AWS NFW Name string "" no
aws_nfw_prefix AWS NFW Prefix string "" no
aws_nfw_stateless_rule_group AWS NFW sateless rule group
list(object({
name = string
description = string
capacity = number
rule_config = list(object({
protocols_number = list(number)
source_ipaddress = string
source_to_port = string
destination_to_port = string
destination_ipaddress = string
tcp_flag = object({
flags = list(string)
masks = list(string)
})
actions = map(string)
}))
}))
[] no
aws_nfw_suricata_stateful_rule_group Config for Suricata type stateful rule group
list(object({
name = string
description = string
capacity = number
rules_file = optional(string, "")
rule_variables = optional(object({
ip_sets = list(object({
key = string
ip_set = list(string)
}))
port_sets = list(object({
key = string
port_sets = list(string)
}))
}), {
ip_sets = []
port_sets = []
})
}))
[] no
azs A list of availability zones in the region list(string) [] no
cidr The CIDR block for the VPC. string n/a yes
cloudwatch_log_group_kms_key_id Customer KMS Key id for Cloudwatch Log encryption string n/a yes
cloudwatch_log_group_retention_in_days Number of days to retain Cloudwatch logs number 365 no
create_database_subnet_group Controls if database subnet group should be created bool true no
create_database_subnet_route_table Controls if separate route table for database should be created bool false no
create_elasticache_subnet_route_table Controls if separate route table for elasticache should be created bool false no
create_redshift_subnet_route_table Controls if separate route table for redshift should be created bool false no
database_custom_routes Custom routes for Database Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
database_route_table_tags Additional tags for the database route tables map(string) {} no
database_subnet_group_tags Additional tags for the database subnet group map(string) {} no
database_subnet_suffix Suffix to append to database subnets name string "db" no
database_subnet_tags Additional tags for the database subnets map(string) {} no
database_subnets A list of database subnets map {} no
default_vpc_enable_dns_hostnames Should be true to enable DNS hostnames in the Default VPC bool false no
default_vpc_enable_dns_support Should be true to enable DNS support in the Default VPC bool true no
default_vpc_name Name to be used on the Default VPC string "" no
default_vpc_tags Additional tags for the Default VPC map(string) {} no
delete_protection Whether or not to enable deletion protection of NFW bool true no
deploy_aws_nfw enable nfw true/false bool false no
dhcp_options_domain_name Specifies DNS name for DHCP options set string "" no
dhcp_options_domain_name_servers Specify a list of DNS server addresses for DHCP options set, default to AWS provided list(string)
[
"AmazonProvidedDNS"
]
no
dhcp_options_netbios_name_servers Specify a list of netbios servers for DHCP options set list(string) [] no
dhcp_options_netbios_node_type Specify netbios node_type for DHCP options set string "" no
dhcp_options_ntp_servers Specify a list of NTP servers for DHCP options set list(string) [] no
dhcp_options_tags Additional tags for the DHCP option set map(string) {} no
dynamodb_endpoint_type DynamoDB VPC endpoint type string "Gateway" no
elasticache_custom_routes Custom routes for Elasticache Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
elasticache_route_table_tags Additional tags for the elasticache route tables map(string) {} no
elasticache_subnet_suffix Suffix to append to elasticache subnets name string "elasticache" no
elasticache_subnet_tags Additional tags for the elasticache subnets map(string) {} no
elasticache_subnets A list of elasticache subnets map {} no
enable_dhcp_options Should be true if you want to specify a DHCP options set with a custom domain name, DNS servers, NTP servers, netbios servers, and/or netbios server type bool false no
enable_dns_hostnames Should be true to enable DNS hostnames in the VPC bool false no
enable_dns_support Should be true to enable DNS support in the VPC bool true no
enable_dynamodb_endpoint Should be true if you want to provision a DynamoDB endpoint to the VPC bool false no
enable_nat_gateway Should be true if you want to provision NAT Gateways for each of your private networks bool false no
enable_s3_endpoint Should be true if you want to provision an S3 endpoint to the VPC bool false no
enable_tls_inspection enable nfw tls inspection true/false. deploy_aws_nfw must be true to enable this bool false no
enable_vpn_gateway Should be true if you want to create a new VPN Gateway resource and attach it to the VPC bool false no
external_nat_ip_ids List of EIP IDs to be assigned to the NAT Gateways (used in combination with reuse_nat_ips) list(string) [] no
firewall_custom_routes Custom routes for Firewall Subnets list(map(string)) [] no
firewall_route_table_tags Additional tags for the firewall route tables map(string) {} no
firewall_subnet_name_tag Additional name tag for the firewall subnets map(string) {} no
firewall_subnet_suffix Suffix to append to firewall subnets name string "firewall" no
firewall_subnets A list of firewall subnets inside the VPC map {} no
flow_log_destination_arn The ARN of the Cloudwatch log destination for Flow Logs string null no
flow_log_destination_type Type of flow log destination. Can be s3 or cloud-watch-logs string n/a yes
igw_tags Additional tags for the internet gateway map(string) {} no
instance_tenancy A tenancy option for instances launched into the VPC string "default" no
intra_custom_routes Custom routes for Intra Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
intra_route_table_tags Additional tags for the intra route tables map(string) {} no
intra_subnet_tags Additional tags for the intra subnets map(string) {} no
intra_subnets A list of intra subnets map(string) {} no
manage_default_vpc Should be true to adopt and manage Default VPC bool false no
map_public_ip_on_launch Should be false if you do not want to auto-assign public IP on launch bool true no
name Name to be used on all the resources as identifier string "" no
nat_eip_tags Additional tags for the NAT EIP map(string) {} no
nat_gateway_tags Additional tags for the NAT gateways map(string) {} no
nfw_kms_key_id NFW KMS Key Id for encryption string null no
one_nat_gateway_per_az Should be true if you want only one NAT Gateway per availability zone. Requires var.azs to be set, and the number of public_subnets created to be greater than or equal to the number of availability zones specified in var.azs. bool false no
private_custom_routes Custom routes for Private Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
private_route_table_tags Additional tags for the private route tables map(string) {} no
private_subnet_suffix Suffix to append to private subnets name string "private" no
private_subnet_tags Additional tags for the private subnets map(string) {} no
private_subnets A list of private subnets inside the VPC map {} no
propagate_private_route_tables_vgw Should be true if you want route table propagation bool false no
propagate_public_route_tables_vgw Should be true if you want route table propagation bool false no
public_custom_routes Custom routes for Public Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
internet_route = optional(bool, null)
transit_gateway_id = optional(string, null)
}))
[] no
public_route_table_tags Additional tags for the public route tables map(string) {} no
public_subnet_suffix Suffix to append to public subnets name string "public" no
public_subnet_tags Additional tags for the public subnets map(string) {} no
public_subnets A list of public subnets inside the VPC map {} no
redshift_custom_routes Custom routes for Redshift Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
redshift_route_table_tags Additional tags for the redshift route tables map(string) {} no
redshift_subnet_group_tags Additional tags for the redshift subnet group map(string) {} no
redshift_subnet_suffix Suffix to append to redshift subnets name string "redshift" no
redshift_subnet_tags Additional tags for the redshift subnets map(string) {} no
redshift_subnets A list of redshift subnets map {} no
reuse_nat_ips Should be true if you don't want EIPs to be created for your NAT Gateways and will instead pass them in via the 'external_nat_ip_ids' variable bool false no
s3_endpoint_type S3 VPC endpoint type string "Gateway" no
secondary_cidr_blocks List of secondary CIDR blocks to associate with the VPC to extend the IP Address pool list(string) [] no
single_nat_gateway Should be true if you want to provision a single shared NAT Gateway across all of your private networks bool false no
tags A map of tags to add to all resources map(string) {} no
tgw_custom_routes Custom routes for TGW Subnets
list(object({
destination_cidr_block = optional(string, null)
destination_prefix_list_id = optional(string, null)
network_interface_id = optional(string, null)
transit_gateway_id = optional(string, null)
vpc_endpoint_id = optional(string, null)
}))
[] no
tgw_route_table_tags Additional tags for the tgw route tables map(string) {} no
tgw_subnet_suffix Suffix to append to tgw subnets name string "tgw" no
tgw_subnet_tags Additional tags for the tgw subnets map(string) {} no
tgw_subnets A list of tgw subnets inside the VPC map {} no
tls_cert_arn TLS Certificate ARN string "" no
tls_description Description for the TLS Inspection string "TLS Oubound Inspection" no
tls_destination_cidrs Destination CIDRs for TLS Inspection list(string)
[
"0.0.0.0/0"
]
no
tls_destination_from_port Destination Port for TLS Inspection number 443 no
tls_destination_to_port Destination Port for TLS Inspection number 443 no
tls_source_cidr Source CIDR for TLS Inspection string "0.0.0.0/0" no
tls_source_from_port Source Port for TLS Inspection number 0 no
tls_source_to_port Source Port for TLS Inspection number 65535 no
vpc_tags Additional tags for the VPC map(string) {} no
vpn_gateway_id ID of VPN Gateway to attach to the VPC string "" no
vpn_gateway_tags Additional tags for the VPN gateway map(string) {} no

Outputs

Name Description
aws_nfw_endpoint_ids List of IDs of AWS NFW endpoints
database_subnet_group ID of database subnet group
database_subnets List of IDs of database subnets
database_subnets_cidr_blocks List of cidr_blocks of database subnets
default_network_acl_id The ID of the default network ACL
default_route_table_id The ID of the default route table
default_security_group_id The ID of the security group created by default on VPC creation
default_vpc_cidr_block The CIDR block of the VPC
default_vpc_default_network_acl_id The ID of the default network ACL
default_vpc_default_route_table_id The ID of the default route table
default_vpc_default_security_group_id The ID of the security group created by default on VPC creation
default_vpc_enable_dns_hostnames Whether or not the VPC has DNS hostname support
default_vpc_enable_dns_support Whether or not the VPC has DNS support
default_vpc_id The ID of the VPC
default_vpc_instance_tenancy Tenancy of instances spin up within VPC
default_vpc_main_route_table_id The ID of the main route table associated with this VPC
elasticache_route_table_ids List of IDs of elasticache route tables
elasticache_subnet_group ID of elasticache subnet group
elasticache_subnet_group_name Name of elasticache subnet group
elasticache_subnets List of IDs of elasticache subnets
elasticache_subnets_cidr_blocks List of cidr_blocks of elasticache subnets
firewall_route_table_ids List of IDs of firewall route tables
firewall_subnets List of IDs of firewall subnets
firewall_subnets_cidr_blocks List of cidr_blocks of firewall subnets
igw_id The ID of the Internet Gateway
intra_route_table_ids List of IDs of intra route tables
intra_subnets List of IDs of intra subnets
intra_subnets_cidr_blocks List of cidr_blocks of intra subnets
nat_ids List of allocation ID of Elastic IPs created for AWS NAT Gateway
nat_public_ips List of public Elastic IPs created for AWS NAT Gateway
natgw_ids List of NAT Gateway IDs
private_route_table_ids List of IDs of private route tables - including database route table IDs, as the database uses the private route tables
private_subnets List of IDs of private subnets
private_subnets_cidr_blocks List of cidr_blocks of private subnets
public_route_table_ids List of IDs of public route tables
public_subnets List of IDs of public subnets
public_subnets_cidr_blocks List of cidr_blocks of public subnets
redshift_route_table_ids List of IDs of redshift route tables
redshift_subnet_group ID of redshift subnet group
redshift_subnets List of IDs of redshift subnets
redshift_subnets_cidr_blocks List of cidr_blocks of redshift subnets
tgw_route_table_ids List of IDs of tgw route tables
tgw_subnets List of IDs of tgw subnets
tgw_subnets_cidr_blocks List of cidr_blocks of tgw subnets
vgw_id The ID of the VPN Gateway
vpc_cidr_block The CIDR block of the VPC
vpc_enable_dns_hostnames Whether or not the VPC has DNS hostname support
vpc_enable_dns_support Whether or not the VPC has DNS support
vpc_endpoint_dynamodb_id The ID of VPC endpoint for DynamoDB
vpc_endpoint_dynamodb_pl_id The prefix list for the DynamoDB VPC endpoint.
vpc_endpoint_s3_id The ID of VPC endpoint for S3
vpc_endpoint_s3_pl_id The prefix list for the S3 VPC endpoint.
vpc_id The ID of the VPC
vpc_instance_tenancy Tenancy of instances spin up within VPC
vpc_main_route_table_id The ID of the main route table associated with this VPC
vpc_secondary_cidr_blocks List of secondary CIDR blocks of the VPC

Contributing

Relative or absolute link to contributing.md

License

License

Coalfire Pages

Absolute link to any relevant Coalfire Pages

Copyright

Copyright © 2024 Coalfire Systems Inc.