Chapter 4.1 - Firewall Architecture, Segmentation & Zero Trust
Module 4: Defense Engineering & Hardening This module shifts perspective entirely - from attacker to defender. Every technique in Module 3 has a structural countermeasure. This chapter covers the foundational controls.
Table of Contents
- Firewall Generations & Processing Models
- Stateful Inspection - Connection Tracking & State Tables
- Next-Generation Firewalls - Application Awareness & Deep Inspection
- iptables & nftables - Linux Packet Filtering in Depth
- Network Segmentation - Zones, DMZ Design & VLANs
- Micro-Segmentation & East-West Traffic Control
- Zero Trust Architecture - Principles, Components & Implementation
- Firewall Rule Auditing & Misconfiguration Detection
- Defensive Metrics & Validation
- MITRE ATT&CK Mapping & Control Coverage
1. Firewall Generations & Processing Models
Firewalls evolved from simple packet filters to application-aware inspection engines. Understanding what each generation can and cannot enforce is essential for designing layered defenses - no single generation handles all threat classes.
Evolution of Firewall Technology
| Generation | Core Mechanism | Visibility | Blind Spots |
|---|---|---|---|
| Packet filter (L3/L4) | ACL on IP/port/protocol | Header fields only | All payload; stateless = ACK scan bypass |
| Stateful inspection | Connection state tracking | TCP session lifecycle | Application-layer content; encrypted payloads |
| Application-layer gateway (proxy) | Full protocol proxy | Application commands (FTP, DNS) | Non-proxied protocols; TLS without inspection |
| NGFW | DPI + App-ID + User-ID + IPS | Application, user, content | Encrypted C2 without TLS inspection; zero-days |
| Cloud-native / SASE | Identity + context + cloud delivery | User, device, app, behavior | Depends on agent deployment; blind on unmanaged devices |
Packet Processing Pipeline
Understanding the order in which rules are evaluated prevents logical misconfigurations - a rule that can never be reached because a broader rule precedes it is a common audit finding:
Ingress interface
│
▼
[Ingress ACL] ← Pre-routing filter (can block before routing decision)
│
▼
[Routing decision] ← Determines egress interface
│
▼
[Stateful tracking] ← Is this an established/related connection?
│
├── Established → fast path (skip deep inspection)
│
└── New → policy lookup
│
▼
[Policy match] ← First matching rule wins (most firewalls)
│
▼
[Action: allow/deny/inspect/log]
│
▼
[Egress ACL]
│
▼
Egress interface
First-match vs best-match: Most firewalls (iptables, Palo Alto, Cisco ASA) use first-match - rules are evaluated top-to-bottom and the first match terminates evaluation. A broad ALLOW rule above a specific DENY rule makes the DENY unreachable. This is the source of the vast majority of firewall misconfigurations found in audits.
2. Stateful Inspection - Connection Tracking & State Tables
Stateful firewalls track TCP/UDP/ICMP sessions in a connection tracking table (conntrack). Each entry records the 5-tuple, state, timeout, and expected next transitions. This allows the firewall to:
- Permit return traffic for established outbound connections without explicit rules
- Detect out-of-state packets (TCP ACK with no corresponding SYN = potential scan)
- Enforce protocol behavior (FTP data channel, related ICMP errors)
Linux Connection Tracking
# View the connection tracking table
conntrack -L # List all tracked connections
conntrack -L --proto tcp # TCP only
conntrack -L --state ESTABLISHED # Only established sessions
# Real-time event monitoring (new connections, destroyed sessions)
conntrack -E # Event mode - watch in real time
conntrack -E -e NEW # Only new connection events
conntrack -E -e DESTROY # Only destroyed connections
# Example conntrack output:
# tcp 6 431999 ESTABLISHED src=10.0.1.5 dst=203.0.113.1 sport=54231 dport=443
# src=203.0.113.1 dst=10.0.1.5 sport=443 dport=54231
# [ASSURED] mark=0 use=1
# Fields: proto timeout state original_tuple reply_tuple flags
# Conntrack table statistics
conntrack -S # Per-CPU stats
# Watch for: insert_failed (table full), drop (hash collision)
# Set conntrack table size (for high-traffic environments)
sysctl net.netfilter.nf_conntrack_max # Current max
sysctl -w net.netfilter.nf_conntrack_max=1048576 # Set to 1M entries
echo "net.netfilter.nf_conntrack_max = 1048576" >> /etc/sysctl.conf
# Conntrack timeouts - reduce for DDoS/scan resilience
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=300 # 5 min (default: 5 days!)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10 # 10s SYN timeout
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=15 # TIME_WAIT
# Flush entire conntrack table (use with caution - drops all tracked sessions)
conntrack -F
TCP State Tracking and Bypass Techniques
# Stateful rule: only allow NEW and ESTABLISHED inbound, block invalid
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP # Drop invalid state
iptables -A INPUT -j DROP # Default deny
# Why INVALID matters:
# Packets with no corresponding conntrack entry and no SYN flag = INVALID
# This catches: ACK scans, out-of-window RSTs, fragmented packet attacks
# Without this rule, some port scanners bypass stateful inspection
# Detect conntrack table exhaustion attacks (SYN flood fills table)
watch -n 1 'conntrack -S | grep insert_failed'
# Rising insert_failed = table full = new connections dropped = effective DoS
3. Next-Generation Firewalls - Application Awareness & Deep Inspection
NGFWs operate at L7, identifying applications by content signatures rather than port numbers. This matters because attackers routinely run services on non-standard ports (SSH on 443, C2 over HTTP on 8080) or tunnel protocols inside allowed ones (DNS tunneling, HTTP tunneling over port 80).
Application Identification
NGFW App-ID engines work by:
- Protocol decoding - parse the application protocol to identify it definitively
- Pattern matching - match payload against application signatures
- Behavioral analysis - classify based on flow behavior (packet sizes, timing, direction ratios)
- Unknown application handling - classify by port if content is unrecognizable (risky fallback)
Palo Alto Networks - Policy Concepts
Palo Alto is the dominant enterprise NGFW. Its policy model organizes rules by Security Zone pairs rather than IP ranges alone:
# PAN-OS CLI - view security policy rules
show security policy-rule all
# Show application usage on a policy rule
show running security-policy
# Check application identification on live sessions
show session all filter application unknown # Sessions with unidentified app
show session all filter state active # All active sessions
show session id 12345 # Detail for specific session
# Application override - force classify traffic (use sparingly)
# Forces PAN to skip App-ID and classify by port only
# Useful for custom internal apps that App-ID can't identify
# Verify which applications are allowed through a rule
show security policy-rule "Allow-Internet" application
# Threat logs - blocked threats from IPS/AV
show log threat direction equal forward | match "critical\|high"
# Traffic logs with application detail
show log traffic application equal unknown start-time equal last-5-minutes
SSL/TLS Inspection Policy
# PAN-OS: verify SSL inspection is active
show running ssl-decrypt
# Key configuration points:
# - Forward Trust cert: corporate CA cert loaded on firewall, trusted by endpoints
# - Forward Untrust cert: different CA for sites with untrusted certs (users see warning)
# - Decryption profile: controls TLS version, cipher requirements, certificate validation
# - Exclusions: banking, healthcare, personal accounts (legal/privacy requirements)
# Check what's being excluded from decryption
show decryption exclude-cache
# Linux/open-source equivalent: Squid with ssl-bump
# Check which connections Squid is decrypting vs splicing:
tail -f /var/log/squid/access.log | grep "CONNECT\|TUNNEL"
# CONNECT = Squid intercepted and decrypted
# TUNNEL = Squid passed through without inspection (excluded)
4. iptables & nftables - Linux Packet Filtering in Depth
iptables - Tables, Chains & Rules
iptables organizes rules into tables (filter, nat, mangle, raw) and chains (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING). For firewall purposes, the filter table is primary.
# View all rules with line numbers and packet/byte counters
iptables -L -n -v --line-numbers # filter table (default)
iptables -t nat -L -n -v --line-numbers # NAT table
iptables -t mangle -L -n -v # Mangle table
# Save and restore rules (persistent across reboots)
iptables-save > /etc/iptables/rules.v4 # Save current rules
iptables-restore < /etc/iptables/rules.v4 # Restore saved rules
# Production server hardening ruleset
# ============================================
# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F
# Default policies - deny everything, allow nothing
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT # Allow outbound (adjust per policy)
# Allow loopback (required for local services)
iptables -A INPUT -i lo -j ACCEPT
# Allow established/related return traffic
iptables -A INPUT -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
# Drop invalid state packets (ACK scans, out-of-state)
iptables -A INPUT -m conntrack \
--ctstate INVALID -j DROP
# Rate-limit new SSH connections (brute-force protection)
iptables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW \
-m recent --set --name SSH_BRUTE # Track new SSH connection sources
iptables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW \
-m recent --update --name SSH_BRUTE \
--seconds 60 \ # Within 60 seconds
--hitcount 4 \ # More than 4 attempts
-j DROP # Drop the connection
iptables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW -j ACCEPT # Allow SSH if under threshold
# Allow HTTP/HTTPS for web server
iptables -A INPUT -p tcp \
--dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp \
--dport 443 -m conntrack --ctstate NEW -j ACCEPT
# Allow ICMP ping (controlled - rate limited)
iptables -A INPUT -p icmp --icmp-type echo-request \
-m limit --limit 5/second \ # Max 5 pings/second
-j ACCEPT
# Log and drop everything else
iptables -A INPUT -m limit \
--limit 10/minute \ # Don't flood syslog
-j LOG --log-prefix "IPT_DROP: " --log-level 4
iptables -A INPUT -j DROP
nftables - Modern Replacement
nftables is the Linux kernel's successor to iptables, offering better performance, atomic rule updates, and a cleaner syntax. Most distributions now ship nftables by default:
# View current ruleset
nft list ruleset
# nftables equivalent of the iptables ruleset above:
cat > /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
# Connection tracking sets for rate limiting
set ssh_brute {
type ipv4_addr
flags dynamic, timeout
timeout 60s
}
chain input {
type filter hook input priority 0
policy drop # Default deny
iif lo accept # Allow loopback
ct state established,related accept # Allow return traffic
ct state invalid drop # Drop invalid state
# SSH rate limiting using nftables sets
tcp dport 22 ct state new \
add @ssh_brute { ip saddr limit rate over 4/minute } \
drop # Drop if > 4 new SSH/min from same IP
tcp dport 22 ct state new accept # Allow SSH under threshold
# Web traffic
tcp dport { 80, 443 } ct state new accept
# ICMP rate limit
ip protocol icmp icmp type echo-request \
limit rate 5/second accept
# Logging
limit rate 10/minute log prefix "NFT_DROP: " level warn
}
chain forward {
type filter hook forward priority 0
policy drop # Default deny forwarding
}
chain output {
type filter hook output priority 0
policy accept # Allow all outbound
}
}
EOF
# Apply ruleset
nft -f /etc/nftables.conf
# Atomic rule update (add rule without disrupting existing connections)
nft add rule inet filter input \
tcp dport 8080 ct state new accept
# List rules with handles (needed for deletion)
nft list chain inet filter input -a
# Delete a specific rule by handle
nft delete rule inet filter input handle 15
# Enable nftables service (persists across reboots)
systemctl enable nftables
systemctl start nftables
5. Network Segmentation - Zones, DMZ Design & VLANs
Security Zone Architecture
The core principle of segmentation: a compromised host in one zone must not automatically have access to hosts in another zone. Every lateral movement technique from Chapter 3.3 relies on flat network access - segmentation defeats it structurally.
Standard zone model:
| Zone | Hosts | Trust Level | Firewall Policy |
|---|---|---|---|
| Internet | Everything external | Untrusted | Deny all inbound by default |
| DMZ | Web servers, mail, DNS, VPN | Semi-trusted | Allow specific inbound from Internet; restricted outbound |
| Internal | Workstations, printers | Medium trust | Allow outbound to Internet via proxy; no direct Internet inbound |
| Server | Internal apps, databases | High trust | Strict access from specific Internal subnets only |
| OT/ICS | Industrial control | Critical | Air-gap or near-air-gap; no Internet access |
| Management | Firewalls, switches, servers (OOB) | Highest | Accessible only from jump host; MFA required |
DMZ Design
# Example: three-interface firewall DMZ
# eth0 = Internet (untrusted)
# eth1 = DMZ (web servers: 192.168.10.0/24)
# eth2 = Internal LAN (10.0.0.0/24)
# Internet to DMZ: allow HTTP/HTTPS to web servers only
iptables -A FORWARD -i eth0 -o eth1 \
-p tcp --dport 443 \
-d 192.168.10.0/24 \
-m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 \
-p tcp --dport 80 \
-d 192.168.10.0/24 \
-m conntrack --ctstate NEW -j ACCEPT
# Internet to Internal: deny ALL (no exceptions)
iptables -A FORWARD -i eth0 -o eth2 -j DROP
# DMZ to Internal: deny ALL (compromise of web server does not equal access to LAN)
iptables -A FORWARD -i eth1 -o eth2 -j DROP
# DMZ to Internet: allow only specific outbound (patch updates, API calls)
iptables -A FORWARD -i eth1 -o eth0 \
-p tcp --dport 443 \
-s 192.168.10.0/24 \
-m conntrack --ctstate NEW -j ACCEPT
# Internal to DMZ: allow HTTP/HTTPS to web servers (internal access)
iptables -A FORWARD -i eth2 -o eth1 \
-p tcp -m multiport --dports 80,443 \
-m conntrack --ctstate NEW -j ACCEPT
# Internal to Internet: allow via proxy only (transparent proxy on port 3128)
# Force all outbound web traffic through Squid
iptables -t nat -A PREROUTING -i eth2 \
-p tcp --dport 80 \
-j REDIRECT --to-port 3128 # Redirect HTTP to Squid transparent proxy
# Allow established return traffic in all directions
iptables -A FORWARD -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
# Log inter-zone violations
iptables -A FORWARD -j LOG \
--log-prefix "FW_FORWARD_DENY: " --log-level 4
iptables -A FORWARD -j DROP
VLAN Configuration for Segmentation
# Linux: create VLAN sub-interfaces (802.1Q tagging)
# Requires: modprobe 8021q
modprobe 8021q
echo "8021q" >> /etc/modules
# Create VLAN interfaces
ip link add link eth0 name eth0.10 type vlan id 10 # VLAN 10 = DMZ
ip link add link eth0 name eth0.20 type vlan id 20 # VLAN 20 = Internal
ip link add link eth0 name eth0.30 type vlan id 30 # VLAN 30 = Server
# Assign IPs
ip addr add 192.168.10.1/24 dev eth0.10
ip addr add 10.0.20.1/24 dev eth0.20
ip addr add 10.0.30.1/24 dev eth0.30
# Bring up interfaces
ip link set eth0.10 up
ip link set eth0.20 up
ip link set eth0.30 up
# Cisco IOS switch - VLAN configuration (for context)
# vlan 10
# name DMZ
# vlan 20
# name Internal
# interface GigabitEthernet0/1
# switchport mode trunk
# switchport trunk allowed vlan 10,20,30
# interface GigabitEthernet0/2
# switchport mode access
# switchport access vlan 10
# Verify VLAN separation - traffic on VLAN 10 should not reach VLAN 20
# without traversing the firewall/router
ping -I eth0.10 10.0.20.5 # Should fail if properly segmented
6. Micro-Segmentation & East-West Traffic Control
Traditional segmentation controls north-south traffic (between zones). Micro-segmentation controls east-west traffic (between hosts within the same zone) - the attack path exploited by lateral movement.
The Lateral Movement Problem
In a flat network (no micro-segmentation), a compromised workstation on the Internal VLAN can reach every other workstation - enabling worm propagation, pass-the-hash, and SMB relay across the entire segment. Micro-segmentation limits the blast radius.
Host-Based Firewall Enforcement
# Windows: enforce Windows Firewall via GPO
# Computer Configuration -> Windows Settings -> Security Settings ->
# Windows Defender Firewall with Advanced Security
# Block inbound SMB between workstations:
# PowerShell: block SMB inbound from non-server subnets
New-NetFirewallRule \
-DisplayName "Block Lateral SMB" \
-Direction Inbound \
-Protocol TCP \
-LocalPort 445 \
-RemoteAddress "10.0.0.0/24" \ # Block from workstation subnet to workstation
-Action Block \
-Profile Domain
# Allow SMB only from IT management subnet
New-NetFirewallRule \
-DisplayName "Allow SMB from IT" \
-Direction Inbound \
-Protocol TCP \
-LocalPort 445 \
-RemoteAddress "10.0.100.0/24" \ # IT management subnet only
-Action Allow \
-Profile Domain
# Linux: restrict lateral access between servers
# Allow only specific source IPs to reach a service
nft add rule inet filter input \
ip saddr != 10.0.30.0/24 \ # Not from Server subnet
tcp dport 5432 drop # Block PostgreSQL from non-server hosts
Software-Defined Perimeter with eBPF/Cilium
For Kubernetes and cloud-native environments, Cilium uses eBPF to enforce network policy at the kernel level with zero performance impact:
# Cilium NetworkPolicy - allow only specific pods to reach the database
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: db-access-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: postgres # Policy applies to postgres pods
ingress:
- fromEndpoints:
- matchLabels:
app: api-server # Only api-server pods can connect
toPorts:
- ports:
- port: "5432"
protocol: TCP
egress:
- toFQDNs: # Allow DNS resolution only
- matchPattern: "*.internal"
# Apply policy
kubectl apply -f db-access-policy.yaml
# Verify policy is enforced
cilium policy get
cilium endpoint list # Show per-pod policy status
# Test policy enforcement
kubectl exec -it test-pod -- nc -zv postgres-svc 5432
# Should succeed from api-server pod, fail from all others
7. Zero Trust Architecture - Principles, Components & Implementation
Zero Trust Principles
Zero Trust rejects the perimeter security model ("trusted inside, untrusted outside") because:
- Lateral movement is trivial once perimeter is breached (demonstrated in Module 3)
- Remote work, cloud, and BYOD have dissolved the perimeter
- Insider threats bypass perimeter controls entirely
Core tenets (NIST SP 800-207):
- All resources are accessed over secure, authenticated channels - location (IP, VLAN, VPN-connected) is not an implicit trust signal
- Access is granted per-session and per-resource - no persistent broad access grants
- Access policy incorporates all available context - user identity, device health, location, time, request behavior
- The network is assumed hostile - east-west traffic is inspected, not trusted
Zero Trust Components
+--------------------------------------------------------------+
| Control Plane |
| +-------------------+ +------------------+ |
| | Policy Engine |<---| Identity Provider| (Okta, AAD) |
| | (Access Decision | | Device Trust | (Intune, MDM)|
| | Point) | | Threat Intel |(CrowdStrike) |
| +--------+----------+ +------------------+ |
| | Policy Decision |
+-----------+--------------------------------------------------+
|
+-----------v--------------------------------------------------+
| Data Plane |
| +------------------------------------------------------+ |
| | Policy Enforcement Point (PEP) | |
| | - Reverse proxy / API gateway | |
| | - Network access control | |
| | - Endpoint agent | |
| +------------------------------------------------------+ |
| ^ v |
| Subject Resource |
| (User + Device) (App / Data / Service) |
+--------------------------------------------------------------+
Implementing Zero Trust with nginx + mTLS
A practical starting point: replace implicit network trust with explicit mTLS authentication at the service layer:
# Generate CA and service certificates
# Step 1: Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 \
-key ca.key \
-out ca.crt \
-days 3650 \
-subj "/CN=ZeroTrust-Internal-CA"
# Step 2: Generate server certificate for the protected service
openssl genrsa -out server.key 2048
openssl req -new -key server.key \
-out server.csr \
-subj "/CN=api.internal.corp"
openssl x509 -req \
-in server.csr \
-CA ca.crt -CAkey ca.key \
-CAcreateserial \
-out server.crt -days 365
# Step 3: Generate client certificate for each authorized service
openssl genrsa -out client-api.key 2048
openssl req -new -key client-api.key \
-out client-api.csr \
-subj "/CN=frontend-service/O=api-access"
openssl x509 -req \
-in client-api.csr \
-CA ca.crt -CAkey ca.key \
-CAcreateserial \
-out client-api.crt -days 365
# nginx config - require client certificate for access
# /etc/nginx/sites-available/protected-api
server {
listen 443 ssl;
server_name api.internal.corp;
ssl_certificate /etc/ssl/server.crt;
ssl_certificate_key /etc/ssl/server.key;
ssl_client_certificate /etc/ssl/ca.crt; # CA that signed client certs
ssl_verify_client on; # REQUIRE client cert
ssl_verify_depth 2;
ssl_protocols TLSv1.3; # TLS 1.3 only
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
location / {
# Optionally: check specific CN or OU from client cert
if ($ssl_client_s_dn !~ "O=api-access") {
return 403; # Reject wrong certificate purpose
}
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Client-CN $ssl_client_s_dn_cn; # Pass identity downstream
}
}
Zero Trust with BeyondCorp / Google IAP Model
# Implement IAP-style access control with OAuth2 + device posture
# Using oauth2-proxy as the enforcement point:
docker run -d \
--name oauth2-proxy \
-p 4180:4180 \
quay.io/oauth2-proxy/oauth2-proxy:latest \
--provider=google \
--client-id=YOUR_OAUTH_CLIENT_ID \
--client-secret=YOUR_OAUTH_SECRET \
--cookie-secret=$(python3 -c 'import secrets; print(secrets.token_hex(16))') \
--email-domain=corp.com \ # Only allow @corp.com email addresses
--upstream=http://internal-app:8080 \
--redirect-url=https://app.corp.com/oauth2/callback \
--skip-provider-button=true # Auto-redirect to provider
# nginx: route all traffic through oauth2-proxy
location / {
auth_request /oauth2/auth; # Check authentication first
error_page 401 = /oauth2/sign_in; # Redirect to login if not authenticated
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-Forwarded-User $user;
proxy_set_header X-Forwarded-Email $email;
proxy_pass http://internal-app:8080;
}
location /oauth2/ {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header Host $host;
}
8. Firewall Rule Auditing & Misconfiguration Detection
Rule bloat is universal in long-lived firewalls - shadowed rules, overly permissive any/any rules, and stale rules for decommissioned systems accumulate over years.
# fwaudit - open-source firewall rule analysis
# Detects: shadowed rules, unreachable rules, any/any, missing logging
# Parse iptables rules and analyze
iptables-save > /tmp/current_rules.txt
fwaudit --iptables /tmp/current_rules.txt \
--report /tmp/audit_report.html
# Manual analysis: find any/any rules in iptables
iptables -L -n | grep -E "0\.0\.0\.0/0.*0\.0\.0\.0/0.*ACCEPT"
# Any rule accepting from anywhere to anywhere = immediate finding
# Find rules with no logging (accept rules without a matching log rule)
iptables -L -n -v | grep ACCEPT | \
awk '{print $8, $9, $10}' | sort -u # Show destinations of ACCEPT rules
# Find shadowed rules - a rule that can never be reached
# Example: ACCEPT any -> 10.0.0.0/8 (rule 3) is shadowed by ACCEPT any -> 0.0.0.0/0 (rule 1)
# Manual inspection required - iptables doesn't flag this automatically
# nmap-based rule validation - test from outside what should be blocked
# From the internet-facing interface, test that DMZ restrictions hold:
nmap -sS \
-p 22,3389,445,1433,3306 \ # High-risk ports that should be blocked
--open \
192.168.10.0/24 # DMZ subnet
# Any open results = firewall misconfiguration
# Test inter-zone controls from inside
# From Internal LAN, verify you cannot reach the database directly
nmap -sT -p 5432,3306,1433 \
10.0.30.0/24 \ # Server subnet
--source-ip 10.0.20.50 # From workstation IP
# Cisco ASA: check for any/any rules
show access-list | grep "permit ip any any"
show access-list | grep "permit tcp any any"
# Palo Alto: find overly permissive rules
show security policy-rule all | \
match "any.*any.*any.*allow"
9. Defensive Metrics & Validation
Measuring Segmentation Effectiveness
# Automated segmentation testing - Nmap sweep from each zone
# Should be run after any firewall rule change
# Create zone test script
cat > /usr/local/bin/segmentation_test.sh << 'EOF'
#!/bin/bash
# Run from each zone, redirect output to SIEM/log
ZONES=(
"10.0.20.0/24:Internal"
"192.168.10.0/24:DMZ"
"10.0.30.0/24:Server"
)
PROBE_PORTS="22,23,80,443,445,3389,1433,3306,5432"
for zone_entry in "${ZONES[@]}"; do
subnet=$(echo $zone_entry | cut -d: -f1)
name=$(echo $zone_entry | cut -d: -f2)
echo "=== Testing access TO $name ($subnet) ==="
nmap -sT -p $PROBE_PORTS --open $subnet \
-oG - 2>/dev/null | \
grep "open" | \
awk -v zone="$name" '{print zone, $2, $5}'
echo ""
done
EOF
chmod +x /usr/local/bin/segmentation_test.sh
# Key firewall metrics to track:
# - Connections per second (capacity planning)
# - Block rate (rising = scan/attack; falling = policy drift)
# - Top blocked source IPs (threat intel)
# - Rule hit counts (zero-hit rules = candidates for removal)
# - Connection table utilization (approaching max = DoS risk)
# iptables: show rule hit counts
iptables -L -n -v | awk '$1 > 0' # Show only rules with packet hits
# Reset counters after policy review
iptables -Z # Zero all packet/byte counters
# Export iptables metrics to Prometheus (node_exporter)
# node_exporter with --collector.iptables flag exposes rule hit counts
# Then visualize in Grafana
10. MITRE ATT&CK Mapping & Control Coverage
| ATT&CK Technique | ID | Firewall/Segmentation Control | Zero Trust Control |
|---|---|---|---|
| Lateral Movement: SMB | T1021.002 | Block 445 east-west via micro-seg | Device trust required per session |
| Lateral Movement: WMI | T1021.006 | Block 135/dynamic RPC between workstations | Endpoint agent verifies request |
| C2: Standard Application Layer | T1071 | NGFW App-ID blocks unknown apps | Egress proxy with TLS inspection |
| Exfiltration: Data Transfer | T1041 | Egress filtering + DLP | Per-session access tokens; data classification |
| Discovery: Network Scanning | T1046 | Log/alert on cross-zone port scans | Every access requires authenticated request |
| Valid Accounts: Domain | T1078 | Cannot block (valid credentials) | Behavioral anomaly + device posture check |
| DCSync / RPC | T1003.006 | Block MS-DRSR from non-DC IPs | Identity-aware PEP rejects non-DC |
| Exploit Public App | T1190 | WAF + NGFW IPS | SASE inspects all traffic regardless of source |
| Initial Access: Phishing | T1566 | Email gateway; no network block | MFA defeats credential phishing |
| Defense Evasion: Port Knocking | T1205 | Stateful inspection detects sequence | Mutual authentication (mTLS) makes knocking moot |
End of Chapter 4.1 - Firewall Architecture, Segmentation & Zero Trust
Next: Chapter 4.2 - SIEM, SOAR & Detection Engineering