The Network Firewall filters perimeter traffic at the VPC.
In current VPC module implementation, traffic to the internet in the public subnet is sent to the NFW endpoint instead of directly to the Internet Gateway.
Module call (variables as part of the call to the parent VPC module):
### Network Firewall ###
deploy_aws_nfw = true
aws_nfw_prefix = var.resource_prefix
aws_nfw_name = "mvp-test-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
nfw_kms_key_id = aws_kms_key.nfw_key.arn
# When deploying NFW, firewall_subnets must be specified
firewall_subnets = local.firewall_subnets
firewall_subnet_suffix = "firewall"
NFW Policies (in root module):
locals {
rdp_remote_access_policy_shrd_svcs = flatten([
for k, subnet in local.public_subnets : [
for index, cidr in var.cidrs_for_remote_access : {
description = "All Ingress RDP traffic"
protocol = "TCP"
source_ipaddress = cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = subnet
destination_port = 3389
sid = k + index + 1
actions = {
type = "pass"
}
}
]
])
ssh_remote_access_policy_shrd_svcs = flatten([
for k, subnet in local.public_subnets : [
for index, cidr in var.cidrs_for_remote_access : {
description = "All Ingress SSH traffic"
protocol = "SSH"
source_ipaddress = cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = subnet
destination_port = 22
sid = k + index + 1
actions = {
type = "pass"
}
}
]
])
domain_stateful_rule_group_shrd_svcs = [
{
capacity = 1000
name = "GoogleBlock"
description = "Stateful rule blocking google.com"
domain_list = [".cnn.com", ".google.com"]
actions = "DENYLIST"
protocols = ["HTTP_HOST", "TLS_SNI"]
rule_variables = {
ip_sets = [
{
key = "HOME_NET"
ip_set = [var.mgmt_vpc_cidr]
},
{
key = "EXTERNAL_HOST"
ip_set = ["0.0.0.0/0"]
}
]
port_sets = [
{
key = "HTTP_PORTS"
port_sets = ["443", "80"]
}
]
}
},
]
fivetuple_rule_group_shrd_svcs = [
{
name = "EGRESSWEB"
capacity = 1000
description = "Stateful rule to internet from VPCs"
rule_config = [
{
description = "All WEB Internet traffic"
protocol = "TCP"
source_ipaddress = var.mgmt_vpc_cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = "ANY"
destination_port = "ANY"
sid = 1
actions = {
type = "pass"
}
},
{
description = "All HTTP Internet traffic"
protocol = "TCP"
source_ipaddress = var.mgmt_vpc_cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = "ANY"
destination_port = "ANY"
sid = 2
actions = {
type = "pass"
}
}
]
},
{
name = "EGRESSSSHRDP"
capacity = 1000
description = "Stateful rule to RDP/SSH to VPCs"
rule_config = [
{
description = "All RDP traffic"
protocol = "TCP"
source_ipaddress = var.mgmt_vpc_cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = "ANY"
destination_port = 3389
sid = 1
actions = {
type = "pass"
}
},
{
description = "All SSH traffic"
protocol = "TCP"
source_ipaddress = var.mgmt_vpc_cidr
source_port = "ANY"
direction = "FORWARD"
destination_ipaddress = "ANY"
destination_port = 22
sid = 2
actions = {
type = "pass"
}
}
]
},
{
name = "INGRESSRDP"
capacity = 1000
description = "Stateful rule to RDP to WINBastions"
rule_config = local.rdp_remote_access_policy_shrd_svcs
},
{
name = "INGRESSSSH"
capacity = 1000
description = "Stateful rule to SSH to LINBastions"
rule_config = local.ssh_remote_access_policy_shrd_svcs
}
]
stateless_rule_group_shrd_svcs = [
{
name = "STATELESSEGRESSWEB"
capacity = 1000
description = "Stateless rule to internet from VPCs"
rule_config = [
{
protocols_number = [6]
source_ipaddress = var.mgmt_vpc_cidr
source_to_port = "ANY"
destination_to_port = "ANY"
destination_ipaddress = "0.0.0.0/0"
tcp_flag = {
flags = ["SYN"]
masks = ["SYN", "ACK"]
}
actions = {
type = "pass"
}
}
]
},
{
name = "STATELESSRDPBASTION"
capacity = 1000
description = "Stateless rule to allow RDP to Windows Bastion"
rule_config = [
for index, cidr in var.cidrs_for_remote_access : {
protocols_number = [6]
source_ipaddress = cidr
source_to_port = 3389
destination_to_port = 3389
destination_ipaddress = var.mgmt_vpc_cidr
tcp_flag = {
flags = ["SYN"]
masks = ["SYN", "ACK"]
}
actions = {
type = "pass"
}
}
]
},
{
name = "STATELESSSSHBASTION"
capacity = 1000
description = "Stateless rule to allow SSH to Linux Bastion"
rule_config = [
for index, cidr in var.cidrs_for_remote_access : {
protocols_number = [6]
source_ipaddress = cidr
source_to_port = 22
destination_to_port = 22
destination_ipaddress = var.mgmt_vpc_cidr
tcp_flag = {
flags = ["SYN"]
masks = ["SYN", "ACK"]
}
actions = {
type = "pass"
}
}
]
}
]
suricata_rule_group_shrd_svcs = [
{
capacity = 1000
name = "SURICATARULES"
description = "Stateful rules with suricta type"
rules_file = "./test.rules.json"
}
]
}
test.rules.json file (in calling root module):
drop tls any any -> $EXTERNAL_NET any (tls.sni; content: ".cnn.com"; startswith; nocase; endswith; msg: "matching TLS denylisted FQDNs"; priority: 1; flow:to_server, established; sid: 1; rev:1;)
drop http any any -> $EXTERNAL_NET any (http.host; content: ".google.com"; startswith; endswith; msg: "matching HTTP denylisted FQDNs"; priority: 1; flow: to_server, established; sid: 3; rev: 1;)
Rule group variables are lists of objects. The variables can be further inspected to determine what parameters and types are expected. Stateless rule groups are dynamically given a priority from the top-down (start at 0 at the top, then increment by 1).
Name | Version |
---|---|
terraform | ~>1.0 |
aws | ~> 5.0 |
Name | Version |
---|---|
aws | ~> 5.0 |
No modules.
Name | Type |
---|---|
aws_cloudwatch_log_group.nfw | resource |
aws_networkfirewall_firewall.this | resource |
aws_networkfirewall_firewall_policy.this | resource |
aws_networkfirewall_logging_configuration.this | resource |
aws_networkfirewall_rule_group.domain_stateful_group | resource |
aws_networkfirewall_rule_group.fivetuple_stateful_group | resource |
aws_networkfirewall_rule_group.stateless_group | resource |
aws_networkfirewall_rule_group.suricata_stateful_group | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
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 |
delete_protection | Whether or not to enable deletion protection of NFW | bool |
true |
no |
description | Description for the resources | string |
"" |
no |
domain_stateful_rule_group | Config for domain type stateful rule group | list(object({ |
[] |
no |
firewall_name | firewall name | string |
"example" |
no |
firewall_policy_change_protection | (Option) A boolean flag indicating whether it is possible to change the associated firewall policy | string |
false |
no |
fivetuple_stateful_rule_group | Config for 5-tuple type stateful rule group | list(object({ |
[] |
no |
nfw_kms_key_id | NFW KMS Key Id for encryption | string |
n/a | yes |
prefix | The description for each environment, ie: bin-dev | string |
n/a | yes |
stateful_managed_rule_groups_arns | https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_firewall_policy#action | list(string) |
[] |
no |
stateless_default_actions | Default stateless Action | string |
"forward_to_sfe" |
no |
stateless_fragment_default_actions | Default Stateless action for fragmented packets | string |
"forward_to_sfe" |
no |
stateless_rule_group | Config for stateless rule group | list(object({ |
[] |
no |
subnet_change_protection | (Optional) A boolean flag indicating whether it is possible to change the associated subnet(s) | string |
false |
no |
subnet_mapping | Subnet ids mapping to have individual firewall endpoint | list(string) |
n/a | yes |
suricata_stateful_rule_group | Config for Suricata type stateful rule group | list(object({ |
[] |
no |
tags | The tags for the resources | map(any) |
{} |
no |
vpc_id | VPC ID | string |
n/a | yes |
Name | Description |
---|---|
arn | Created Network Firewall ARN from network_firewall module |
endpoint_id | Created Network Firewall endpoint id |
id | Created Network Firewall ID from network_firewall module |