Skip to content

Latest commit

 

History

History
330 lines (300 loc) · 15.7 KB

File metadata and controls

330 lines (300 loc) · 15.7 KB

aws-network-firewall

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.

Usage

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).

Requirements

Name Version
terraform ~>1.0
aws ~> 5.0

Providers

Name Version
aws ~> 5.0

Modules

No modules.

Resources

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

Inputs

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({
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
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({
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
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({
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
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({
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
tags The tags for the resources map(any) {} no
vpc_id VPC ID string n/a yes

Outputs

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