# Firewall rules explicitly allow only necessary CDE traffic

- **Pattern:** `ab-001187` (`ecommerce-pci.network-security.firewall-rules`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001187
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001187)

## Why it matters

PCI-DSS 4.0 Req 1.2.1 requires that inbound and outbound traffic is restricted to that which is necessary; Req 1.4 prohibits direct public access to any CDE component. A security group with `0.0.0.0/0` on port 22 (SSH) or 5432 (PostgreSQL) means your database is reachable from the entire internet — any brute-force or credential-stuffing attack against it requires only a public IP. CWE-183 (Permissive List of Allowed Inputs) and NIST SC-7 both require deny-by-default firewall posture. A single overly permissive rule can invalidate an otherwise well-segmented network architecture.

## Severity rationale

High because one allow-all or `0.0.0.0/0` rule on a sensitive port (SSH, database) exposes the CDE directly to internet-sourced attacks, negating any network segmentation investment.

## Remediation

Replace every allow-all ingress rule with explicit source security group references or narrowly scoped CIDR blocks. SSH access must be limited to a bastion host security group — never `0.0.0.0/0`. Database ports must accept traffic only from the application tier security group.

```hcl
# Restrict SSH to bastion only
ingress {
  from_port       = 22
  to_port         = 22
  protocol        = "tcp"
  security_groups = [aws_security_group.bastion.id]
}

# Database accessible from app tier only
ingress {
  from_port       = 5432
  to_port         = 5432
  protocol        = "tcp"
  security_groups = [aws_security_group.app.id]
}
```

Set a deny-all default egress on CDE security groups and add specific outbound rules only for required destinations (e.g., port 443 to payment processor IPs). Audit `terraform plan` output for any `cidr_blocks = ["0.0.0.0/0"]` on ports below 1024.

## Detection

- **ID:** `firewall-rules`
- **Severity:** `high`
- **What to look for:** Enumerate all firewall and security group rules in infrastructure code. For each rule, classify it as restrictive (specific port + specific source) or permissive (all ports, or `0.0.0.0/0` on sensitive ports like 22, 3306, 5432). Count the total number of ingress rules and the number that are overly permissive. Check for deny-by-default principle (no rule = deny).
- **Pass criteria:** At least 1 security group or firewall configuration exists with explicit rules. No more than 0 rules allow `0.0.0.0/0` on sensitive ports (22, 3306, 5432, 27017). No more than 0 rules allow all ports (from_port: 0, to_port: 65535). All CDE-bound traffic is restricted to specific source security groups or CIDR ranges. Report: "X total ingress rules, Y restrictive, Z permissive."
- **Fail criteria:** At least 1 overly permissive rule exists (allow-all ports from any source, or `0.0.0.0/0` on database/SSH ports), or no firewall rules documented at all.
- **Skip (N/A) when:** All payment processing delegated to third-party (no CDE infrastructure, no security groups in project).
- **Detail on fail:** Identify overly permissive rules. Example: `"Security group cde-sg allows 0.0.0.0/0 on port 22 (SSH). 2 of 5 ingress rules are overly permissive."` or `"Security group has from_port: 0, to_port: 65535 from 0.0.0.0/0. All ports open to internet."`
- **Remediation:** Define restrictive firewall rules. Replace allow-all with explicit rules:

  ```hcl
  # Before: Overly permissive
  resource "aws_security_group" "bad" {
    ingress {
      from_port   = 0
      to_port     = 65535
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }

  # After: Explicit rules
  resource "aws_security_group" "cde" {
    # SSH only from bastion
    ingress {
      from_port       = 22
      to_port         = 22
      protocol        = "tcp"
      security_groups = [aws_security_group.bastion.id]
    }

    # Database from app tier only
    ingress {
      from_port       = 5432
      to_port         = 5432
      protocol        = "tcp"
      security_groups = [aws_security_group.app.id]
    }

    # Monitoring from monitoring tools
    ingress {
      from_port       = 9090
      to_port         = 9090
      protocol        = "tcp"
      security_groups = [aws_security_group.monitoring.id]
    }

    # Explicit deny-all for unlisted
    egress {
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = []
    }

    # Allow specific outbound
    egress {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"] # to internet for updates
    }
  }
  ```

## External references

- pci-dss Req 1.2
- pci-dss Req 1.4
- cwe CWE-183
- owasp A05
- nist SC-7

Taxons: operational-readiness, regulatory-conformance

HTML version: https://auditbuffet.com/patterns/ab-001187
