Skip to content

Network Firewall policies should have default stateless action set to drop or forward for full packets

With aws:pass as the default stateless action, any packet that doesn't match an explicit stateless rule flows through the firewall without being blocked or inspected. That's the opposite of what you deployed a network firewall for: traffic that skips stateless matching gets a free pass unless something else in the stack catches it.

aws:drop blocks unmatched traffic outright. aws:forward_to_sfe sends it to the stateful engine for deeper inspection. Both are acceptable. The goal is that unknown traffic doesn't slide through by default.

Retrofit consideration

Changing the default from pass to drop on an existing firewall policy may immediately block legitimate traffic that previously relied on the permissive default. Audit stateless rule coverage before switching.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "network_firewall" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/network-firewall/aws//modules/policy"
  version = ">=1.0.0"

  name = "abc123-policy"
}

module "network_firewall" {
  source  = "nistcsf.compliance.tf/terraform-aws-modules/network-firewall/aws//modules/policy"
  version = ">=1.0.0"

  name = "abc123-policy"
}

module "network_firewall" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/network-firewall/aws//modules/policy"
  version = ">=1.0.0"

  name = "abc123-policy"
}

If you use terraform-aws-modules/network-firewall/aws//modules/policy, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "network_firewall" {
  source  = "terraform-aws-modules/network-firewall/aws//modules/policy"
  version = ">=1.0.0"

  name = "abc123-policy"
}

Use AWS provider resources directly. See docs for the resources involved: aws_networkfirewall_firewall_policy.

resource "aws_networkfirewall_firewall_policy" "this" {
  firewall_policy {
    stateless_default_actions          = ["aws:drop"]
    stateless_fragment_default_actions = ["aws:drop"]
  }
  name = "pofix-abc123"
}

What this control checks

stateless_default_actions lives in the firewall_policy block of the aws_networkfirewall_firewall_policy resource. It takes a list of action strings applied to full packets when no stateless rule matches. The control passes when the list includes "aws:drop" or "aws:forward_to_sfe" and fails when it is set to ["aws:pass"]. A typical passing configuration is stateless_default_actions = ["aws:forward_to_sfe"] to hand unmatched packets to the stateful engine, or stateless_default_actions = ["aws:drop"] to silently discard them.

Common pitfalls

  • Confusing full packet and fragment default actions

    There are two distinct default action arguments: stateless_default_actions for full packets, and stateless_fragment_default_actions for fragmented packets. This control only checks the first. You can set stateless_fragment_default_actions to drop and still fail here if stateless_default_actions is aws:pass. A separate check covers fragments.

  • Custom action names masking a pass

    Defining a stateless_custom_action for metrics publishing is common, and including that custom action name in stateless_default_actions is fine. The problem is when that list also contains aws:pass. A custom action alongside aws:pass doesn't neutralize the pass. The standard action in the list must be aws:drop or aws:forward_to_sfe.

  • Terraform import of existing policies

    Get this wrong on an import and you won't know until you run a plan against corrected config. terraform import on an existing firewall policy reflects whatever default action is already live. If the policy was created with aws:pass, that ends up in state and Terraform won't flag it until your configuration explicitly sets something different. Always inspect stateless_default_actions in imported state before treating the resource as compliant.

Audit evidence

Config rule networkfirewall-policy-default-action-full-packets should return COMPLIANT for each in-scope firewall policy. A screenshot of the Stateless default actions section on the firewall policy detail page confirms the full packet default is Drop or Forward to stateful rule groups. CloudTrail UpdateFirewallPolicy and CreateFirewallPolicy events show no policy was created or modified with a pass default during the audit period.

Framework-specific interpretation

PCI DSS v4.0: Requirement 1 covers network security controls, and PCI DSS v4.0 is explicit about default-deny intent for unauthorized traffic. A stateless default of aws:pass can conflict with that intent unless compensating rules enforce effective deny-by-default behavior elsewhere in the policy.

NIST Cybersecurity Framework v2.0: PR.PS under the Protect function calls for implemented, managed protections for platforms and infrastructure. Restricting the default stateless action to drop or forward is the kind of explicit network traffic control that satisfies that expectation.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: networkfirewall_firewall_policy_default_stateless_action_check_full_packets

  • AWS Config Managed Rule: NETFW_POLICY_DEFAULT_ACTION_FULL_PACKETS

  • Powerpipe Control: aws_compliance.control.networkfirewall_firewall_policy_default_stateless_action_check_full_packets

  • Prowler Check: networkfirewall_policy_default_action_full_packets

  • AWS Security Hub Control: NetworkFirewall.4

Last reviewed: 2026-03-09