Network Security
- Network Security
Controlling what traffic may go where
Network security controls what traffic can enter, traverse, and leave an environment — it is least privilege applied to the network itself. This page covers segmentation and VLANs, firewalls and secure zoning, DNS security, and DDoS mitigation. It builds on networking fundamentals (TCP/IP, routing, addressing) and connects to the deeper dives elsewhere in the course: firewalls and IDS/IPS, VPNs and IPSec, DNS security and privacy, and email security.
Network Segmentation
Network segmentation divides a network into isolated zones so that compromise of one zone does not automatically grant access to others. It is a foundational defense-in-depth control.
Segmentation principles
- Default deny — traffic between segments is blocked unless explicitly permitted
- Least connectivity — a host should only be reachable by the services that legitimately need to reach it
- Defense in depth — segment boundaries enforce controls independent of host-level controls
- Blast radius reduction — a compromised host in one segment cannot directly attack hosts in other segments
Zone model
A classic three-tier zone model:
Internet
│
▼
[DMZ — Public-facing services]
Web servers, load balancers, reverse proxies
Allowed inbound: 80/tcp, 443/tcp from internet
Allowed outbound: 8080/tcp to Application tier only
│
▼
[Application tier — Business logic]
API servers, microservices
Allowed inbound: 8080/tcp from DMZ only
Allowed outbound: 5432/tcp to Data tier only
│
▼
[Data tier — Databases, storage]
PostgreSQL, Redis, object storage
Allowed inbound: 5432/tcp from Application tier only
Allowed outbound: None (no internet access)
Linux firewall segmentation with nftables
nftables is the modern replacement for iptables on Linux (kernel 3.13+):
# Basic nftables ruleset enforcing the Application tier policy
# /etc/nftables.conf
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Allow established connections
ct state established,related accept
# Allow loopback
iif lo accept
# Allow SSH from management subnet only
ip saddr 10.0.10.0/24 tcp dport 22 accept
# Allow API traffic from DMZ only
ip saddr 10.0.1.0/24 tcp dport 8080 accept
# Drop everything else
log prefix "INPUT-DROP: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
# Allow only database traffic outbound
ip daddr 10.0.3.0/24 tcp dport 5432 accept
# Allow DNS
udp dport 53 accept
# Block all other outbound (comment out for less restrictive)
# log prefix "OUTPUT-DROP: " drop
}
}
# Apply nftables rules
sudo nft -f /etc/nftables.conf
sudo nft list ruleset # verify active rules
sudo systemctl enable nftables
Kubernetes network segmentation
# Enforce strict segmentation between namespaces with NetworkPolicy
# Step 1: Default-deny all traffic in production namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# Step 2: Allow frontend pods to reach backend pods on port 8080
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- protocol: TCP
port: 8080
---
# Step 3: Allow backend to reach database (separate namespace)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-to-db
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
policyTypes:
- Egress
VLANs
VLANs (Virtual Local Area Networks) segment a physical network at Layer 2, creating separate broadcast domains on shared switch infrastructure. VLANs provide network segmentation without requiring separate physical hardware.
VLAN concepts
| Concept | Description |
|---|---|
| VLAN ID | 12-bit number (1–4094) identifying a VLAN; IDs 1 and 4094 reserved |
| Access port | Switch port assigned to one VLAN; carries untagged frames to the host |
| Trunk port | Switch port that carries tagged frames for multiple VLANs (between switches, to routers) |
| 802.1Q tagging | IEEE standard for VLAN tags; inserts a 4-byte tag into the Ethernet frame |
| Inter-VLAN routing | A router or Layer 3 switch routes between VLANs; acts as the enforcement point for segment policy |
Linux VLAN interfaces
Linux can create VLAN-tagged interfaces using the 8021q kernel module:
# Load the 802.1Q module
sudo modprobe 8021q
echo 8021q | sudo tee -a /etc/modules
# Create a VLAN interface (VLAN 100 on eth0)
sudo ip link add link eth0 name eth0.100 type vlan id 100
sudo ip addr add 10.100.0.1/24 dev eth0.100
sudo ip link set eth0.100 up
# Verify
ip -d link show eth0.100 # shows vlan protocol 802.1Q id 100
cat /proc/net/vlan/eth0.100 # VLAN statistics
# Persistent configuration (systemd-networkd)
# /etc/systemd/network/10-eth0.100.netdev
# [NetDev]
# Name=eth0.100
# Kind=vlan
# [VLAN]
# Id=100
# /etc/systemd/network/10-eth0.100.network
# [Match]
# Name=eth0.100
# [Network]
# Address=10.100.0.1/24
VLAN security considerations
- VLAN hopping — an attacker on one VLAN reaches another by exploiting DTP (Dynamic Trunking Protocol) or double-tagging. Mitigate by disabling DTP, changing the native VLAN, and not using VLAN 1.
- Trunk port exposure — trunk ports carry all VLANs; restrict them to uplinks only
- PVLAN (Private VLAN) — isolates hosts within the same VLAN from each other; useful for multi-tenant environments
Firewalls
Firewalls inspect and control traffic based on rules. Modern firewalls are stateful — they track connection state — and many include application-layer inspection.
iptables (legacy, still common)
See Networking for full iptables coverage. Key security rules:
# Hardened INPUT chain baseline
iptables -F INPUT # flush existing rules
iptables -P INPUT DROP # default deny
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -m limit \
--limit 1/second -j ACCEPT # rate-limit ping
# Log and drop everything else
iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
iptables -A INPUT -j DROP
nftables (current standard)
# List all active rules
nft list ruleset
# Add a rule to an existing chain
nft add rule inet filter input tcp dport 8080 accept
# Delete a rule by handle
nft --handle list chain inet filter input # find handle numbers
nft delete rule inet filter input handle 5
# Save and restore rules
nft list ruleset > /etc/nftables.conf
nft -f /etc/nftables.conf
Web Application Firewall (WAF)
A WAF operates at Layer 7 (HTTP) and blocks application-layer attacks that network firewalls cannot inspect:
# ModSecurity with OWASP Core Rule Set (nginx)
# Install
sudo apt install libnginx-mod-security2
# /etc/nginx/nginx.conf
# load_module modules/ngx_http_modsecurity_module.so;
# /etc/nginx/conf.d/modsecurity.conf
# modsecurity on;
# modsecurity_rules_file /etc/nginx/modsec/main.conf;
# /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
Include /usr/share/modsecurity-crs/crs-setup.conf
Include /usr/share/modsecurity-crs/rules/*.conf
# Custom rule: block requests with SQL injection patterns
SecRule ARGS "@detectSQLi" \
"id:1001,phase:2,deny,status:403,\
msg:'SQL Injection Attempt',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'"
# Python: interact with AWS WAF to check blocked requests
import boto3
from datetime import datetime, timedelta
wafv2 = boto3.client('wafv2', region_name='us-east-1')
# Get sampled blocked requests for a web ACL
response = wafv2.get_sampled_requests(
WebAclArn='arn:aws:wafv2:us-east-1:123456789012:regional/webacl/my-waf/abc123',
RuleMetricName='AWSManagedRulesCommonRuleSet',
Scope='REGIONAL',
TimeWindow={
'StartTime': datetime.utcnow() - timedelta(hours=1),
'EndTime': datetime.utcnow(),
},
MaxItems=100,
)
for req in response.get('SampledRequests', []):
http = req['Request']
action = req.get('Action', 'UNKNOWN')
print(f"{action}: {http.get('Method')} {http.get('URI')} "
f"from {http.get('ClientIP')}")
DNS Security
DNS is a frequent attack vector: DNS poisoning redirects users to attacker-controlled servers, DNS exfiltration tunnels data out through DNS queries, and misconfigured DNS exposes internal infrastructure details.
DNSSEC
DNSSEC adds cryptographic signatures to DNS records, allowing resolvers to verify that responses have not been tampered with:
# Check if a domain has DNSSEC enabled
dig +dnssec example.com
dig DS example.com @8.8.8.8 # check for Delegation Signer records
# Validate DNSSEC chain of trust
dig +trace +dnssec example.com
# Check DNSSEC status with delv (DNS lookup and validation)
delv @8.8.8.8 example.com A +rtrace
DNS security monitoring
# Monitor DNS queries with tcpdump
sudo tcpdump -i eth0 port 53 -n
# Log DNS queries with systemd-resolved
resolvectl statistics # resolver stats
journalctl -u systemd-resolved --since today # resolver log
# Check for DNS exfiltration patterns (unusually long or high-entropy subdomains)
# using Suricata rule:
# alert dns any any -> any any (msg:"DNS Exfiltration: Long subdomain";
# dns_query; content:"."; pcre:"/^[a-z0-9]{30,}/i"; sid:2024001;)
# Python: detect high-entropy DNS queries (potential DNS tunneling)
import math
import re
from collections import Counter
def entropy(s: str) -> float:
"""Shannon entropy of a string."""
counts = Counter(s)
total = len(s)
return -sum((c/total) * math.log2(c/total) for c in counts.values())
def analyze_dns_query(fqdn: str) -> dict:
"""Flag suspicious DNS queries."""
labels = fqdn.split('.')
subdomain = '.'.join(labels[:-2]) if len(labels) > 2 else ''
result = {
'fqdn': fqdn,
'subdomain_length': len(subdomain),
'entropy': entropy(subdomain) if subdomain else 0,
'suspicious': False,
'reason': [],
}
if len(subdomain) > 50:
result['suspicious'] = True
result['reason'].append(f"Long subdomain ({len(subdomain)} chars)")
if result['entropy'] > 3.5:
result['suspicious'] = True
result['reason'].append(f"High entropy ({result['entropy']:.2f})")
return result
test_queries = [
"normal.example.com",
"aGVsbG8gd29ybGQgdGhpcyBpcyBiYXNlNjQgZW5jb2RlZA.evil.com",
]
for q in test_queries:
result = analyze_dns_query(q)
if result['suspicious']:
print(f"SUSPICIOUS: {q} — {', '.join(result['reason'])}")
else:
print(f"OK: {q}")
DDoS Mitigation
Distributed Denial of Service (DDoS) attacks exhaust a target’s resources — bandwidth, CPU, connection table — making the service unavailable to legitimate users.
DDoS categories
| Category | Attack type | Example | Mitigation |
|---|---|---|---|
| Volumetric | Bandwidth exhaustion | UDP flood, ICMP flood | Upstream scrubbing, anycast |
| Protocol | State table exhaustion | SYN flood, fragmented packets | SYN cookies, rate limiting |
| Application | L7 resource exhaustion | HTTP flood, Slowloris | Rate limiting, WAF, CAPTCHA |
Linux-level rate limiting
# SYN flood protection: enable SYN cookies
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Persistent:
echo "net.ipv4.tcp_syncookies = 1" >> /etc/sysctl.d/99-security.conf
sysctl -p /etc/sysctl.d/99-security.conf
# Rate limit ICMP with nftables
nft add rule inet filter input \
ip protocol icmp limit rate 10/second \
counter accept
nft add rule inet filter input \
ip protocol icmp \
counter drop
# Rate limit new TCP connections per source IP with iptables
iptables -A INPUT -p tcp --syn \
-m connlimit --connlimit-above 20 --connlimit-mask 32 \
-j REJECT --reject-with tcp-reset
# Rate limit HTTP requests (new connections per IP)
iptables -A INPUT -p tcp --dport 443 \
-m recent --set --name https-limit
iptables -A INPUT -p tcp --dport 443 \
-m recent --update --seconds 60 --hitcount 120 --name https-limit \
-j DROP
nginx rate limiting
# /etc/nginx/nginx.conf: define rate limit zone
http {
# 10 MB zone (holds ~160,000 IPs); limit 30 requests/second per IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
# Allow bursts of 10 above the rate; delay (not reject) excess
limit_req zone=api_limit burst=10 delay=5;
# Limit simultaneous connections per IP
limit_conn conn_limit 20;
# Return 429 instead of default 503 on rate limit
limit_req_status 429;
limit_conn_status 429;
}
}
}
# Python: implement token bucket rate limiting for an API
import time
import threading
from collections import defaultdict
class TokenBucket:
"""Thread-safe token bucket rate limiter."""
def __init__(self, rate: float, capacity: int):
self.rate = rate # tokens per second
self.capacity = capacity # maximum burst
self._buckets = defaultdict(lambda: {'tokens': capacity, 'last': time.time()})
self._lock = threading.Lock()
def allow(self, key: str) -> bool:
with self._lock:
bucket = self._buckets[key]
now = time.time()
elapsed = now - bucket['last']
bucket['tokens'] = min(
self.capacity,
bucket['tokens'] + elapsed * self.rate
)
bucket['last'] = now
if bucket['tokens'] >= 1:
bucket['tokens'] -= 1
return True
return False
# Usage in a Flask API
from flask import Flask, request, abort
app = Flask(__name__)
limiter = TokenBucket(rate=10, capacity=30) # 10 req/s, burst of 30
@app.before_request
def check_rate_limit():
client_ip = request.remote_addr
if not limiter.allow(client_ip):
abort(429, "Rate limit exceeded")
Secure Network Zoning in Practice
Worked example — three-tier web application:
# Assuming three Linux hosts in three zones:
# DMZ: 10.0.1.10 (nginx reverse proxy)
# App: 10.0.2.10 (Flask API)
# Data: 10.0.3.10 (PostgreSQL)
# --- DMZ host (nginx) ---
# Allow only 80/443 inbound from internet; only 8080 outbound to App tier
nft add table inet filter
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport '{ 80, 443 }' accept
nft add rule inet filter input iif lo accept
nft add chain inet filter output '{ type filter hook output priority 0; policy drop; }'
nft add rule inet filter output ct state established,related accept
nft add rule inet filter output ip daddr 10.0.2.10 tcp dport 8080 accept
nft add rule inet filter output udp dport 53 accept # DNS for certificate validation
# --- App host (Flask) ---
# Allow only 8080 from DMZ; only 5432 to Data tier
# (similar nft rules, scoped to 10.0.1.0/24 source and 10.0.3.10 dest)
# --- Data host (PostgreSQL) ---
# /etc/postgresql/16/main/pg_hba.conf: restrict to App tier source IP
# host mydb appuser 10.0.2.10/32 scram-sha-256
# All other connections: reject
Key takeaways
- Network security is least privilege for traffic: default-deny, then explicitly permit only the flows that are needed, in only the directions needed.
- Segmentation (subnets, VLANs, security zones, microsegmentation) limits blast radius — a compromise in one zone shouldn’t reach the others. This is defense in depth at the network layer.
- Firewalls enforce policy at zone boundaries (
nftableson Linux, cloud security groups, NGFW/WAF); a WAF filters application-layer attacks a packet filter can’t see. - DNS and DDoS are recurring targets: sign zones with DNSSEC for integrity (and see DNS security for encrypted transports), and mitigate volumetric/application DDoS with rate limiting, anycast, and upstream scrubbing.
- These controls compose with the rest of the network material — firewalls/IDS, VPNs, and traffic capture for visibility.
References
- NIST SP 800-41 Rev. 1 — Guidelines on Firewalls and Firewall Policy. https://csrc.nist.gov/publications/detail/sp/800/41/rev-1/final
- nftables wiki — the modern Linux packet filter. https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
- OWASP Network Segmentation Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Network_Segmentation_Cheat_Sheet.html
- Kubernetes NetworkPolicy documentation. https://kubernetes.io/docs/concepts/services-networking/network-policies/
- ICANN — DNSSEC: what it is and why it matters. https://www.icann.org/resources/pages/dnssec-what-is-it-why-important-2019-03-05-en
- Cloudflare Learning Center — what is a DDoS attack? https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/
- NIST SP 800-189 — Resilient Interdomain Traffic Exchange (BGP/RPKI). https://csrc.nist.gov/publications/detail/sp/800/189/final
Related course pages: Introduction to Networking · Defensive Measures (firewalls, IDS/IPS) · VPNs and IPSec · DNS Security and Privacy · Email Security · Access Control and Authorization
🛠️ Maintenance note: the concepts are stable, but the tooling and cloud specifics drift —
nftablessyntax, Kubernetes NetworkPolicy/CNI behavior, and cloud security-group models all change. Re-verify the worked examples against current versions, and note this page leans toward a DevSecOps framing (k8s, cloud) even though it now lives in the introsec course.