Network Security Fundamentals: Firewalls, VPNs, and Zero Trust
Key Takeaways
- •A firewall applies a policy to network traffic.
- •A VPN creates an encrypted tunnel between two endpoints.
- •Segmentation is the control that limits what an attacker who has already gotten past the perimeter can reach.
- •A firewall enforces policy — traffic that matches allow rules passes.
- •Individual security tools — firewall logs, Suricata alerts, VPN authentication logs, endpoint detection events — produce data in isolation.
The SolarWinds supply chain attack in December 2020 compromised 18,000 organizations, including the US Treasury, the Departments of Commerce, Homeland Security, State, and Defense. The attackers — later attributed to Russia's SVR intelligence service — had persistent access to these networks for nine months before detection. They had bypassed every perimeter firewall, every VPN, and every network security appliance those organizations had deployed.
They did not break through those defenses. They walked through the front door as trusted software. SolarWinds Orion, a network monitoring platform deployed inside enterprise networks with privileged access to everything it monitored, pushed a malicious update that was signed with a legitimate certificate and contained a dormant backdoor that activated two weeks after installation. Once inside, the attackers moved laterally through networks that trusted any traffic from the Orion server — because Orion was supposed to see everything.
The SolarWinds attack is not a lesson about any specific security control. It is a lesson about the architectural assumption that a defended perimeter creates a trusted interior — and why that assumption has been wrong for at least a decade. Networks are not "clean" inside. Attackers who get past the perimeter find a flat, high-trust environment that lets them move freely. The interior is where the damage happens.
This post covers the core network security primitives, what each actually does mechanically, where each fails, and how to assemble them into an architecture that can actually limit damage from an attacker who has already gotten in.
Firewalls: What the Enforcement Boundary Actually Does
A firewall applies a policy to network traffic. Traffic that matches an allow rule passes. Traffic that matches a deny rule is dropped. Traffic that matches nothing is handled by the default policy — which must always be deny-all.
The practical effectiveness of a firewall depends entirely on three things: what layer it can see, what policy is configured, and whether that policy is maintained. The most capable NGFW with a poorly maintained ruleset provides weaker protection than a correctly configured stateful firewall.
Packet-Filter Firewalls: Fast, Dumb, Limited
Packet-filter firewalls operate at Layer 3 and Layer 4. They inspect:
- Source IP address
- Destination IP address
- Protocol (TCP, UDP, ICMP)
- Source port
- Destination port
They make allow/deny decisions based on these fields alone, per-packet, with no memory of previous packets. Each packet is evaluated in isolation.
The fundamental limitation: they are stateless. A TCP RST packet arriving on port 49322 is indistinguishable from a legitimate response to an outbound connection and a port-scan probe response. Without connection tracking, the firewall cannot tell the difference. This makes them bypassable with:
- IP fragmentation (headers split across fragments)
- TCP flag manipulation (SYN-FIN, NULL, Xmas scans)
- IP spoofing (appears to come from a trusted source)
- High-numbered port exploitation (return traffic rules open large port ranges)
Classic iptables (pre-nftables) packet filter syntax:
# Allow inbound SSH from management subnet, drop everything else on port 22
# This is STATELESS — each packet evaluated independently
iptables -A INPUT -p tcp --dport 22 -s 10.10.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
# The problem with this approach:
# You also need rules for return traffic on high-numbered ports
# This is where mistakes proliferate
iptables -A INPUT -p tcp --sport 22 --dport 1024:65535 -j ACCEPT
# This allows inbound traffic from ANY source claiming to come from port 22
# An attacker can craft packets that bypass this with source port 22Pure packet filtering is appropriate only as a first stage in a layered firewall architecture, or for coarse IP-range blocking upstream. It should never be the only firewall control.
Stateful Firewalls: The Operational Baseline
Stateful firewalls track the state of every TCP, UDP, and ICMP connection through a connection state table. When an outbound TCP SYN leaves the network, the firewall creates a state entry:
src=192.168.1.100:49532 dst=203.0.113.10:443 proto=TCP state=SYN_SENT
When the SYN-ACK returns from 203.0.113.10:443, the firewall checks the state table, finds the matching entry, verifies the sequence numbers are consistent, and allows the packet through as ESTABLISHED. When a third party sends an unsolicited TCP packet to 192.168.1.100:49532, the firewall has no matching state entry and drops it — even if the packet's source and destination addresses look correct.
This eliminates the high-numbered port problem: return traffic is permitted based on connection state, not on port-range rules. You do not need to allow all TCP traffic above port 1024.
The nftables stateful configuration (modern Linux standard):
# /etc/nftables.conf — stateful firewall skeleton
# This is the correct baseline for any Linux server
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
# Allow established and related connections (stateful tracking)
# This handles return traffic for outbound connections automatically
ct state established,related accept
ct state invalid drop
# Allow loopback interface
iifname "lo" accept
# Allow ICMP for connectivity (rate-limited to prevent ICMP flood)
ip protocol icmp limit rate 10/second accept
ip6 nexthdr icmpv6 limit rate 10/second accept
# SSH from management subnet only — not from the internet
ip saddr 10.10.0.0/24 tcp dport 22 ct state new accept
# Web traffic — only what this server publishes
tcp dport { 80, 443 } ct state new accept
# Log and drop everything else
log prefix "DROPPED: " flags all counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
# If this is a firewall between segments, add forwarding rules here
# Default deny on forward prevents routing unknown traffic
}
chain output {
type filter hook output priority filter; policy accept;
# Consider restricting outbound — C2 beacons, data exfiltration
# need outbound connectivity
}
}Apply and enable:
nft -f /etc/nftables.conf
systemctl enable --now nftables
# Verify rules loaded correctly
nft list ruleset
# Monitor dropped packets in real time (from the log rule above)
journalctl -f -k | grep "DROPPED:"Next-Generation Firewalls: Application-Layer Visibility
NGFW adds Layer 7 inspection to the stateful baseline. The differentiating capabilities:
Application identification. An NGFW can identify the application generating traffic regardless of port. Slack using port 443 is identifiable as Slack, not just "HTTPS." A Tor bridge connection using port 443 is identifiable as Tor. A C2 beacon using port 443 with unusual certificate fingerprints can be flagged. This matters because port-based access control is trivially bypassed — anything can use port 80 or 443.
TLS decryption and inspection. The majority of internet traffic is encrypted. Without TLS inspection, an NGFW cannot see inside HTTPS connections. TLS inspection requires the firewall to act as a man-in-the-middle: it terminates the TLS session from the client, inspects the plaintext, and re-encrypts it to the server using its own certificate. The client's browser trusts this because the firewall's signing CA has been distributed to all endpoints via group policy.
Without TLS inspection:
Client → [TLS Session A] → NGFW (sees encrypted bytes) → [TLS Session A] → Server
With TLS inspection:
Client → [TLS Session A] → NGFW → [decrypts, inspects, re-encrypts] → [TLS Session B] → Server
Client's browser trusts TLS Session A because NGFW's CA is trusted
The operational risks of TLS inspection:
- Every inspected endpoint must trust the NGFW's CA — a large PKI management burden
- If the NGFW's private key is compromised, all historical inspected traffic is exposed to decryption
- Client certificate authentication breaks when the NGFW re-signs — some applications fail
- Privacy regulations in some jurisdictions restrict interception of encrypted traffic even on corporate networks
Egress filtering. Default-allow outbound is the most exploited gap in perimeter security. Malware, ransomware C2 beacons, data exfiltration — all require outbound connectivity. An egress policy that permits only specific destinations (business-critical SaaS, update servers, your DNS resolver) dramatically raises the cost of post-exploitation activities.
# Egress filtering policy concept (NGFW policy or iptables equivalent)
ALLOW:
TCP 443 to 1.1.1.1, 8.8.8.8 (DNS over HTTPS to known resolvers)
UDP 53 to 1.1.1.1, 8.8.8.8 (DNS to known resolvers)
TCP 443 to known corporate SaaS: *.salesforce.com, *.office365.com, *.slack.com
TCP 443, 80 to software update infrastructure
SMTP (25, 587) to designated mail relay only
DENY:
Everything else outbound
Implementing egress filtering requires a categorization of legitimate outbound destinations, which is operationally significant work. Start with alerting and logging before blocking — two weeks of traffic analysis reveals what legitimate outbound looks like before you start denying it.
Web Application Firewalls: The Last HTTP Defense Layer
WAFs inspect HTTP request and response content: URL paths, query parameters, cookie values, POST body contents, HTTP headers. They block patterns associated with web application attacks: SQL injection, XSS, path traversal, SSRF, command injection.
WAFs operate in two modes:
Negative security model (blocklist): Define what is bad; permit everything else. The OWASP ModSecurity Core Rule Set (CRS) is the standard implementation — thousands of rules covering known attack patterns.
Positive security model (allowlist): Define what is permitted; deny everything else. Stronger security posture but requires detailed knowledge of what legitimate traffic looks like. Appropriate for APIs with strict schemas.
ModSecurity in detection-only mode (before you start blocking):
# nginx with ModSecurity WAF
# Install: apt-get install nginx libnginx-mod-modsecurity
# Enable ModSecurity in detection mode first — monitor for two weeks before blocking
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
Include /usr/local/owasp-modsecurity-crs/crs-setup.conf
Include /usr/local/owasp-modsecurity-crs/rules/*.conf
# /etc/nginx/modsec/modsecurity.conf
SecRuleEngine DetectionOnly # Change to On when ready to block
# Log anomaly scores — tune your rules against these before enabling blocking
SecAuditLog /var/log/nginx/modsec_audit.log
SecAuditLogType Concurrent
SecAuditLogStorageDir /var/log/modsec_audit/A WAF is not a code fix. A skilled attacker given enough time finds WAF bypasses — especially against signature-based rules. Fix the underlying vulnerability. Run the WAF to catch opportunistic exploitation and buy time.
VPNs: Encrypted Tunnels and Their Limits
A VPN creates an encrypted tunnel between two endpoints. Everything transmitted through the tunnel is encrypted between those endpoints. That is the complete scope of what a VPN does. Understanding that scope prevents misuse.
What a VPN actually provides:
- Confidentiality: traffic is encrypted between the VPN client and VPN server
- Source IP substitution: the destination sees the VPN server's IP, not the client's
- Protection from local network observers: the ISP or coffee shop AP sees only encrypted data to the VPN endpoint
What a VPN does not provide:
- Protection from threats on the client endpoint
- Protection from the VPN server itself (the server decrypts everything)
- Anonymity from a determined adversary
- Security of the destination server
- Protection from malware that calls out through the VPN tunnel
Site-to-Site VPNs: Connecting Network Segments
Site-to-site VPNs permanently connect two network segments via an encrypted tunnel — typically a branch office to headquarters, or an on-premises data center to a cloud VPC.
IPsec in tunnel mode is the standard protocol. Two gateways establish the tunnel; traffic between the two networks transits it transparently:
Branch office (192.168.10.0/24) ←→ [IPsec tunnel] ←→ HQ (10.0.0.0/8)
AWS Site-to-Site VPN configuration example:
# Create a customer gateway (your on-premises VPN device)
aws ec2 create-customer-gateway \
--type ipsec.1 \
--public-ip YOUR-PUBLIC-IP \
--bgp-asn 65000
# Create a virtual private gateway and attach to VPC
aws ec2 create-vpn-gateway --type ipsec.1
aws ec2 attach-vpn-gateway --vpc-id vpc-12345678 --vpn-gateway-id vgw-abcdef
# Create the VPN connection
aws ec2 create-vpn-connection \
--type ipsec.1 \
--customer-gateway-id cgw-11111111 \
--vpn-gateway-id vgw-abcdef \
--options '{"StaticRoutesOnly": false}'
# Download configuration for your VPN device
aws ec2 describe-vpn-connections \
--query 'VpnConnections[0].CustomerGatewayConfiguration' \
--output textRemote Access VPNs: WireGuard in Practice
For individual remote access, WireGuard is the current best practice — minimal attack surface (~4,000 lines of code versus OpenVPN's ~100,000), built into the Linux kernel since 5.6, and significantly faster.
# /etc/wireguard/wg0.conf — Server configuration
[Interface]
# Server's private key (generate with: wg genkey)
PrivateKey = SERVER-PRIVATE-KEY-HERE
# VPN network — clients get IPs from this range
Address = 10.10.10.1/24
# Listen port — open this in your firewall
ListenPort = 51820
# Enable IP forwarding for VPN clients to reach the internet
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = sysctl -w net.ipv4.ip_forward=0
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Client peer definitions — one [Peer] block per client
[Peer]
# Client's public key (generate with: wg genkey | tee privkey | wg pubkey)
PublicKey = CLIENT-PUBLIC-KEY-HERE
# IP address assigned to this client
AllowedIPs = 10.10.10.2/32# /etc/wireguard/wg0.conf — Client configuration
[Interface]
PrivateKey = CLIENT-PRIVATE-KEY-HERE
Address = 10.10.10.2/32
# Use VPN server as DNS (prevents DNS leaks)
DNS = 10.10.10.1
[Peer]
PublicKey = SERVER-PUBLIC-KEY-HERE
Endpoint = SERVER-PUBLIC-IP:51820
# 0.0.0.0/0 routes ALL traffic through VPN (no split tunneling)
# Change to specific CIDRs if you only want corporate traffic tunneled
AllowedIPs = 0.0.0.0/0, ::/0
# Keep NAT mappings alive — needed behind most home routers
PersistentKeepalive = 25# Generate key pairs for a new client
wg genkey | tee /etc/wireguard/client-private.key | wg pubkey > /etc/wireguard/client-public.key
# Bring up the interface
wg-quick up wg0
# Or via systemd (persistent across reboots)
systemctl enable --now wg-quick@wg0
# Check current status and connected peers
wg show
# Shows: peers, their endpoints, last handshake, data transferred
# Verify traffic is flowing through VPN
curl -s https://ifconfig.me # Should return VPN server's IP, not your local IPThe Security Limitations of Traditional VPN
Traditional VPNs grant network access, not application access. A user who authenticates to a corporate VPN typically receives a virtual IP in the corporate range and can reach any resource on the internal network — the same access an attacker who steals that user's credentials gets.
This is the architectural flaw that drove the development of zero trust. The VPN's perimeter model assumes authenticated users should have broad network access. But:
- Credential theft is the most common initial access vector
- Remote workers' devices are frequently compromised
- Once authenticated, attackers have months to explore the network laterally
- The VPN's broad access is exactly what makes credential theft so valuable
For high-security corporate environments, disable split tunneling on remote access VPNs. Split tunneling means some traffic routes through the VPN and some routes directly to the internet from the client device. A compromised device with split tunneling enabled has a foot in both the corporate network and the public internet simultaneously — it is a pivot point. All traffic should route through the VPN, including internet access, so corporate web filtering and monitoring applies.
Zero Trust Architecture: Network Access Without Trust
Zero trust is not a product. It is an architectural approach to access control based on one principle: no user, device, or network location is trusted by default. Access to every resource must be explicitly authorized based on verified identity, device health, and context — regardless of whether the request originates from inside or outside the traditional perimeter.
The traditional perimeter model:
[Internet] → [Firewall] → [Trusted Internal Network]
↑
"Everything inside is trusted"
The zero trust model:
[Any location] → [Identity-Aware Proxy] → [Specific Application]
↑
Every request authenticated + authorized
Device health verified
Least-privilege access only
All access logged
Why SolarWinds Broke the Perimeter Model
The SolarWinds attackers did not need to break through any perimeter. The Orion software update, which contained the SUNBURST backdoor, was signed with a valid SolarWinds code signing certificate and distributed through SolarWinds' legitimate update infrastructure. Once installed, the backdoor operated from inside the network, using the Orion service's existing network access to reach its C2 infrastructure.
The organizations that detected the breach earliest — and limited the damage — were those running zero trust architectures where:
- Orion's network access was scoped to only what it needed (specific management protocols, specific subnets)
- All outbound connections from the Orion server required authentication through an identity-aware proxy
- Anomalous outbound traffic (Orion connecting to
avsvmcloud[.]com, the initial C2 domain) was detectable because all outbound was logged and baselined
Organizations running flat trusted networks did not detect the breach for months — in some cases, they were notified by external parties (Microsoft, FireEye) that they were compromised.
Zero Trust Core Principles in Practice
Verify explicitly. Authenticate and authorize every access request based on all available signals:
# Example: Cloudflare Access policy for an internal application
# Every request to internal-app.company.com must satisfy ALL conditions
access_policy:
name: "Internal Dashboard - Engineering"
include:
- email_domain: "company.com" # Must have company email
require:
- mfa: true # Must have completed MFA
- device_posture:
check_type: "WARP_CLIENT" # Must have WARP running (device agent)
os_version: ">= 14.0" # macOS 14+ only
disk_encryption: required # FileVault/BitLocker required
firewall: required # Local firewall must be on
- country: # Geographic restriction
not_in: ["CN", "RU", "KP", "IR"]
exclude: []Use least-privilege access. Grant access to specific applications, not network segments:
Traditional VPN: User authenticates → gets 10.0.0.0/8 access
Zero Trust: User authenticates → gets access to app1.internal.com only
Different policy for app2.internal.com
No lateral movement between apps
Assume breach. Design the network as if attackers are already inside. Segment everything. Monitor all traffic, including east-west (server to server). Have an incident response plan that does not assume the network is clean.
Practical Zero Trust Implementation
Zero trust implementation is a multi-year effort. The phases, in practical order:
Phase 1: Identity Foundation (Months 1-3)
Deploy an identity provider with MFA as the authoritative source of identity for all access:
# Example: Configure Okta as IdP with hardware MFA required
# All authentication goes through Okta — SSO for all applications
# Require hardware MFA (FIDO2/WebAuthn) for privileged users
# Require TOTP at minimum for all users
# Block access from unmanaged devices (enforce device management enrollment)Phase 2: Device Inventory and Health Assessment (Months 2-6)
You cannot enforce device health requirements if you do not know what devices exist and what state they are in:
# Windows: Verify managed device status via Intune
# Check device compliance from the Microsoft Endpoint Manager admin center
# Create compliance policies that require:
Get-IntuneManagedDevice | Select DeviceName, OS, ComplianceState, LastSyncDateTime
# Linux/macOS: osquery for device state
osquery> SELECT * FROM os_version;
osquery> SELECT * FROM disk_encryption;
osquery> SELECT * FROM firewall_rules WHERE chain='INPUT' AND policy='REJECT';Phase 3: Replace Broad VPN with Identity-Aware Proxies (Months 6-18)
This is the core architectural shift — replacing network-level access with application-level access:
# Tailscale: Zero trust VPN alternative for small-to-medium organizations
# Uses WireGuard under the hood, adds identity-aware access control
# Install on a server
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --auth-key YOUR-AUTH-KEY
# Install on client devices
# Users authenticate with their identity provider (Okta, Google Workspace)
# Access to specific Tailscale IP ranges requires matching ACL rules
# Tailscale ACL example (tailscale.com/admin/acls)
{
"acls": [
// Developers can reach app servers
{
"action": "accept",
"src": ["tag:developer"],
"dst": ["tag:app-server:80,443"]
},
// Only ops team can reach database servers
{
"action": "accept",
"src": ["tag:ops"],
"dst": ["tag:database:5432"]
},
// Deny everything else by default
{"action": "accept", "src": ["*"], "dst": ["*"]}
]
}For larger organizations, Cloudflare Access, Zscaler Private Access, or BeyondCorp Enterprise provide enterprise-grade identity-aware proxy capabilities:
# Cloudflare Tunnel: Expose internal application without opening firewall ports
# The tunnel makes outbound HTTPS connection to Cloudflare
# No inbound firewall rules needed on the origin server at all
# Install cloudflared on the origin server
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
cloudflared tunnel create my-tunnel
# Create tunnel configuration
cat > ~/.cloudflared/config.yml << EOF
tunnel: YOUR-TUNNEL-ID
credentials-file: /root/.cloudflared/YOUR-TUNNEL-ID.json
ingress:
- hostname: internal-app.company.com
service: http://localhost:3000
- hostname: database-ui.company.com
service: http://localhost:5432
- service: http_status:404 # Catch-all for unmatched hostnames
EOF
# Run the tunnel (make it a systemd service)
cloudflared tunnel run my-tunnelZero trust does not mean "buy a zero trust product." Most vendors label any product with an identity check as "zero trust." Evaluate products by asking: does it grant access to a specific application or to a network segment? Does it verify device health, or just user identity? Does it continuously monitor session behavior, or just check at login? Real zero trust grants per-application access with ongoing verification — not a network credential that lasts 8 hours.
Network Segmentation: Limiting Blast Radius
Segmentation is the control that limits what an attacker who has already gotten past the perimeter can reach. It directly addresses the "assume breach" principle. If an attacker compromises one segment, they should not be able to freely pivot to others.
The Flat Network Problem
A flat network — one where all devices can communicate freely on a shared Layer 2 domain — is the worst-case segmentation failure. Compromise any device, reach every other device. This is unfortunately the default state of many SMB networks and a significant number of enterprise segments that grew organically.
In a flat network:
- An attacker who compromises a printer (common — printers run embedded Linux with unpatched firmware) can scan and attack every workstation and server directly
- A compromised marketing laptop can directly query the SQL database server on port 3306
- Ransomware that gains access to one device can spread laterally to all reachable devices simultaneously
Practical Segmentation Architecture
A practical segmentation model for a mid-size organization:
Internet
↓
[Perimeter Firewall/NGFW]
↓
DMZ (172.16.0.0/24)
├── Web servers (nginx/Apache)
├── Load balancers
├── Mail gateway
└── [No direct access to internal segments]
↓ (explicit policy through internal firewall)
Application Segment (10.0.10.0/24)
├── Application servers
├── API backends
└── [Can query database segment on port 5432 only]
↓
Database Segment (10.0.20.0/24)
├── PostgreSQL cluster
├── Redis cache
└── [No outbound internet access]
Corporate LAN (10.0.30.0/24)
├── Workstations
└── [Cannot directly reach database segment]
Management Segment (10.0.100.0/24) — Out of band
├── Bastion hosts / jump servers
├── Network device management interfaces
├── IPMI/iDRAC/iLO
└── [Accessible only from VPN or MFA-protected access]
IoT Segment (10.0.200.0/24)
├── Cameras, smart TVs, printers, badge readers
└── [Internet access only, no access to other segments]
Guest WiFi (10.0.250.0/24)
└── [Internet access only, completely isolated]
VLAN configuration on a managed switch (Cisco IOS syntax):
! Create VLANs
vlan 10
name DMZ
vlan 20
name Application
vlan 30
name Database
vlan 100
name Management
vlan 200
name IoT
vlan 250
name Guest
! Trunk port to firewall (carries all VLANs)
interface GigabitEthernet0/1
switchport mode trunk
switchport trunk allowed vlan 10,20,30,100,200,250
! Access port for a database server
interface GigabitEthernet0/24
switchport mode access
switchport access vlan 30
Firewall inter-segment rules (the policy that enforces segmentation):
# iptables rules enforcing the segmentation above
# Running on the internal firewall/router
# Allow Application → Database on PostgreSQL only
iptables -A FORWARD -s 10.0.10.0/24 -d 10.0.20.0/24 -p tcp --dport 5432 -j ACCEPT
iptables -A FORWARD -s 10.0.10.0/24 -d 10.0.20.0/24 -p tcp --dport 6379 -j ACCEPT # Redis
# Allow Management segment → everything (for administration)
iptables -A FORWARD -s 10.0.100.0/24 -d 10.0.0.0/8 -j ACCEPT
# Block Corporate LAN → Database directly
iptables -A FORWARD -s 10.0.30.0/24 -d 10.0.20.0/24 -j DROP
# Block IoT → everything except internet (handled by routing — IoT VLAN has no route to internal segments)
iptables -A FORWARD -s 10.0.200.0/24 -d 10.0.0.0/8 -j DROP
# Block Guest → internal networks completely
iptables -A FORWARD -s 10.0.250.0/24 -d 10.0.0.0/8 -j DROPMicro-Segmentation: Per-Workload Policy
Micro-segmentation applies firewall-equivalent policies at the individual workload level, enforced at the hypervisor or container runtime. East-west traffic between workloads in the same VLAN is controlled — not just north-south traffic at the perimeter.
In VMware environments, NSX-T provides micro-segmentation at the hypervisor level. In AWS, security groups applied to individual EC2 instances or ENIs achieve the same result. In Kubernetes, NetworkPolicy objects control pod-to-pod communication:
# Kubernetes NetworkPolicy: Only allow app pods to reach database pods
# All other ingress to database pods is denied
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-access-policy
namespace: production
spec:
podSelector:
matchLabels:
role: database # Applies to database pods
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
role: application # Only allow from application pods
ports:
- protocol: TCP
port: 5432 # PostgreSQL port only
egress: [] # No outbound from database pods — they receive queries onlyIDS/IPS: Detecting What Firewalls Miss
A firewall enforces policy — traffic that matches allow rules passes. It does not detect whether allowed traffic is malicious. An SQL injection payload in a POST body to port 443 from an authorized source IP will pass a firewall without inspection.
Intrusion Detection Systems (IDS) watch network traffic and alert on patterns matching known attack signatures or behavioral anomalies. Passive — they observe and report. They cannot block traffic.
Intrusion Prevention Systems (IPS) sit inline and can drop or reset traffic matching signatures. Active — they can stop an attack, but misconfigured rules block legitimate traffic.
Snort and Suricata are the dominant open-source options. Suricata is now preferred — it is multi-threaded, actively maintained, and the Emerging Threats ruleset is excellent.
# Install Suricata on Ubuntu
apt-get install -y suricata
# Download and update Emerging Threats rules
suricata-update
# Run Suricata in IDS mode (passive, monitoring only)
suricata -c /etc/suricata/suricata.yaml -i eth0
# Key configuration in /etc/suricata/suricata.yaml
vars:
address-groups:
HOME_NET: "[10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12]"
EXTERNAL_NET: "!$HOME_NET"
HTTP_SERVERS: "$HOME_NET"
SQL_SERVERS: "10.0.20.0/24" # Database segment only
# Enable specific rulesets
default-rule-path: /var/lib/suricata/rules/
rule-files:
- suricata.rules # All rules from suricata-update# Test Suricata is detecting malicious traffic
# This generates a test alert (the EICAR-like Suricata test rule)
curl http://testmynids.us/uid/index.html
# Check alerts in EVE JSON log
tail -f /var/log/suricata/eve.json | python3 -c "
import sys, json
for line in sys.stdin:
event = json.loads(line)
if event.get('event_type') == 'alert':
print(f\"{event['timestamp']} | {event['alert']['signature']} | {event['src_ip']} → {event['dest_ip']}\")
"Writing custom Snort/Suricata rules for your environment:
# Custom rule: Alert on SQL injection attempts against database servers
# sid must be unique — use 9000000+ for custom rules
alert http $EXTERNAL_NET any -> $SQL_SERVERS $HTTP_PORTS (
msg:"SQL Injection Attempt - UNION SELECT";
flow:to_server,established;
content:"UNION"; nocase;
content:"SELECT"; within:20; nocase;
classtype:web-application-attack;
sid:9000001;
rev:1;
)
# Alert on Mimikatz-related network signatures
alert tcp $HOME_NET any -> any any (
msg:"Mimikatz - LSASS Dump Detected";
content:"sekurlsa::logonpasswords"; nocase;
classtype:credential-theft;
sid:9000002;
rev:1;
)
# Alert on suspicious PowerShell download cradles
alert http $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (
msg:"PowerShell IEX Download Cradle";
content:"IEX"; content:"DownloadString"; within:100;
classtype:trojan-activity;
sid:9000003;
rev:1;
)Deployment considerations:
Start IPS in IDS mode (detection only). Run it for two to four weeks. Analyze alerts against a baseline of what legitimate traffic looks like. Only enable inline blocking after the false positive rate is acceptably low. Premature inline blocking on a busy network generates alerts from legitimate applications and erodes trust in the tool — the "alert fatigue" that causes real threats to be ignored.
Deploy Suricata at network chokepoints: upstream of the internal firewall (to see internet-bound attack traffic before it is blocked), between network segments (to see lateral movement), and on the management segment (to catch privileged attacks). A single Suricata instance monitoring a mirror/SPAN port of all inter-VLAN traffic gives you full visibility without impacting traffic flow.
SIEM: Making Sense of Security Events at Scale
Individual security tools — firewall logs, Suricata alerts, VPN authentication logs, endpoint detection events — produce data in isolation. A Security Information and Event Management (SIEM) platform ingests all of this, normalizes it, and correlates events across sources to identify attack patterns that no single tool would see.
A sophisticated attacker who compromises one endpoint and moves laterally uses techniques that individually look benign: valid credentials logging into systems, standard administrative tools, normal network protocols. The malicious pattern is in the correlation: the same account authenticating to an unusual system from an unusual workstation at 3 AM, followed by bulk file access, followed by an outbound connection to an unusual destination.
# Example Elastic SIEM detection rule
# Detects: successful VPN authentication → within 1 hour → access to database server
# This pattern is suspicious for credential reuse attack
rule:
name: "VPN Auth followed by Database Access from New IP"
type: eql # Event Query Language
query: |
sequence with maxspan=1h
[authentication where event.outcome == "success"
and network.application == "wireguard"
and not source.ip in ("10.10.0.0/24")] # Not from known management range
[network where destination.port == 5432 # PostgreSQL
and source.ip == sequence[0].source.ip] # Same IP
severity: high
risk_score: 75
tags: ["lateral-movement", "credential-reuse"]The Practical Defense Stack
No single control is sufficient. The architecture that actually limits damage:
| Layer | Control | What It Addresses | |---|---|---| | Perimeter | Stateful firewall, NGFW with egress filtering | Internet-facing attack surface | | Web | WAF (ModSecurity + OWASP CRS) | Web application attacks | | Remote access | WireGuard VPN or identity-aware proxy (Tailscale, Cloudflare Access) | Remote user access | | Zero trust | Per-application access control with device health verification | Credential theft and compromised devices | | Segmentation | VLANs, inter-VLAN firewall policy, Kubernetes NetworkPolicy | Lateral movement blast radius | | Detection | Suricata IDS at segment boundaries | Signature-based attack detection | | Logging | SIEM (Elastic/Splunk) aggregating all sources | Correlation and incident investigation | | Endpoint | EDR (CrowdStrike, SentinelOne) | Post-exploitation detection |
The goal at each layer is to make an attacker's task more expensive, not to make it impossible at one layer and trivial everywhere else. The SolarWinds attackers operated inside networks for nine months. The question is not whether attackers can get in — it is what they can do after they get in, and how quickly you detect them.
Segmentation limits what they can reach. Zero trust prevents their credentials from granting broad network access. SIEM and IDS surface their activity. EDR detects their tooling on the endpoints. None of these are perfect in isolation. Layered, they create an environment where the cost of operating undetected is high enough that most attacker objectives become operationally infeasible.