Network Security: Segmentation and Firewalls
Application-layer security gets most of the attention these days. We obsess over input validation, authentication tokens, and API security—and rightfully so. But network-level controls remain...
Key Insights
- Network segmentation remains your most effective defense against lateral movement—attackers who breach one system shouldn’t automatically access everything else
- Zero trust architecture isn’t a product you buy; it’s a design principle requiring identity verification at every network hop, not just the perimeter
- Cloud environments demand a different mental model: security groups and network policies replace traditional firewalls, but the core principles of least-privilege access still apply
Introduction to Network Security Fundamentals
Application-layer security gets most of the attention these days. We obsess over input validation, authentication tokens, and API security—and rightfully so. But network-level controls remain foundational to any serious security posture.
Defense in depth isn’t just a buzzword. When your web application firewall fails to catch a novel attack, network segmentation limits blast radius. When an attacker compromises a developer workstation, properly configured firewalls prevent them from pivoting to production databases.
The reality is that most breaches involve lateral movement. Attackers rarely hit their target on the first hop. They compromise something accessible, then move laterally until they find valuable data. Network security controls exist to make that lateral movement as difficult as possible.
Network Segmentation Principles
Segmentation divides your network into isolated zones with controlled traffic flow between them. The goal is simple: systems that don’t need to communicate shouldn’t be able to communicate.
VLANs and Subnets provide the foundational layer. VLANs operate at Layer 2, creating logical broadcast domains. Subnets operate at Layer 3, defining IP address ranges that route through gateways. Together, they create network boundaries.
Trust zones group systems by sensitivity and function. A typical architecture includes:
- Public-facing zone (web servers, load balancers)
- Application zone (business logic, APIs)
- Data zone (databases, file storage)
- Management zone (monitoring, deployment tools)
Micro-segmentation takes this further, applying controls at the workload level rather than network segment level. In containerized environments, this means controlling traffic between individual pods or services.
Here’s a practical Terraform configuration implementing proper VPC segmentation in AWS:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "production-vpc"
}
}
# Public subnet for load balancers and bastion hosts
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "public-subnet-${count.index}"
Tier = "public"
}
}
# Private subnet for application servers
resource "aws_subnet" "application" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 10}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "application-subnet-${count.index}"
Tier = "private"
}
}
# Isolated subnet for databases - no internet access
resource "aws_subnet" "database" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 20}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "database-subnet-${count.index}"
Tier = "isolated"
}
}
# NAT Gateway for private subnet outbound access
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public[0].id
}
# Route table ensuring database subnet has no internet route
resource "aws_route_table" "database" {
vpc_id = aws_vpc.main.id
# No route to internet gateway or NAT - fully isolated
tags = {
Name = "database-route-table"
}
}
This configuration creates clear separation: public resources face the internet, application servers access the internet through NAT for updates, and databases remain completely isolated.
Firewall Types and Architecture
Understanding firewall capabilities helps you choose the right tool for each location in your architecture.
Packet filtering examines individual packets against rules based on source/destination IP, ports, and protocols. Fast but stateless—it can’t track connection state or understand application protocols.
Stateful inspection tracks connection state, allowing return traffic for established connections. This is the baseline for modern firewalls and what you get with iptables or cloud security groups.
Next-generation firewalls (NGFW) add application awareness, inspecting traffic content to identify applications regardless of port. They integrate IDS/IPS, URL filtering, and threat intelligence.
Placement matters. Perimeter firewalls filter traffic entering your network. Internal firewalls control traffic between segments. Host-based firewalls protect individual systems and are essential for defense in depth.
Here’s a practical iptables configuration for a Linux application server:
#!/bin/bash
# Host firewall for application server
# Flush existing rules
iptables -F
iptables -X
# Default policies: deny all incoming, allow outgoing
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# SSH from management subnet only
iptables -A INPUT -p tcp --dport 22 -s 10.0.100.0/24 -j ACCEPT
# Application port from load balancer subnet
iptables -A INPUT -p tcp --dport 8080 -s 10.0.0.0/24 -j ACCEPT
# Health checks from load balancer
iptables -A INPUT -p tcp --dport 8081 -s 10.0.0.0/24 -j ACCEPT
# Prometheus metrics from monitoring subnet
iptables -A INPUT -p tcp --dport 9090 -s 10.0.100.0/24 -j ACCEPT
# Log and drop everything else
iptables -A INPUT -j LOG --log-prefix "DROPPED: "
iptables -A INPUT -j DROP
# Save rules
iptables-save > /etc/iptables/rules.v4
This configuration implements least privilege: only specific ports from specific subnets are allowed. Everything else is logged and dropped.
Implementing Zero Trust Network Architecture
Zero trust abandons the concept of a trusted internal network. Every request must be authenticated and authorized, regardless of network location.
The core principles:
- Verify explicitly: Authenticate and authorize based on all available data points
- Least privilege access: Just-in-time and just-enough access
- Assume breach: Minimize blast radius and segment access
In Kubernetes environments, NetworkPolicies implement zero trust at the pod level:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
# Allow traffic from ingress controller only
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
podSelector:
matchLabels:
app: nginx-ingress
ports:
- protocol: TCP
port: 8080
# Allow Prometheus scraping from monitoring namespace
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
egress:
# Allow DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Allow database access
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Allow external API calls through egress gateway
- to:
- namespaceSelector:
matchLabels:
name: egress
podSelector:
matchLabels:
app: egress-gateway
ports:
- protocol: TCP
port: 443
This policy ensures the API server can only receive traffic from the ingress controller and Prometheus, and can only connect to the database, DNS, and an egress gateway for external calls.
Cloud-Native Network Security
Cloud providers offer network security primitives that differ from traditional firewalls but serve similar purposes.
Security Groups act as stateful firewalls attached to resources. They’re your primary control mechanism.
Network ACLs provide stateless subnet-level filtering. Use them as a backup layer, not your primary control.
Cloud Firewalls (AWS Network Firewall, Azure Firewall, GCP Cloud Firewall) add deep packet inspection and centralized management.
Here’s a CloudFormation template for properly configured security groups:
AWSTemplateFormatVersion: '2010-09-09'
Description: Security groups implementing defense in depth
Resources:
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Public-facing load balancer
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: HTTPS from internet
Tags:
- Key: Name
Value: alb-sg
ApplicationSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application servers
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
Description: Traffic from load balancer only
Tags:
- Key: Name
Value: app-sg
DatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Database servers
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId: !Ref ApplicationSecurityGroup
Description: PostgreSQL from application tier only
Tags:
- Key: Name
Value: db-sg
Notice the pattern: each tier only accepts traffic from the tier above it. The database never sees traffic from the load balancer directly.
Monitoring and Incident Response
Security controls without visibility are incomplete. You need to know when rules trigger and when unusual patterns emerge.
Enable VPC Flow Logs in AWS, NSG Flow Logs in Azure, or VPC Flow Logs in GCP. These capture metadata about every network connection.
Here’s a Python script for parsing firewall logs and detecting potential lateral movement:
#!/usr/bin/env python3
import json
from collections import defaultdict
from datetime import datetime, timedelta
def parse_flow_logs(log_file):
"""Parse VPC flow logs and detect anomalies."""
connections = defaultdict(lambda: defaultdict(set))
rejected_counts = defaultdict(int)
with open(log_file) as f:
for line in f:
record = json.loads(line)
src_ip = record['srcaddr']
dst_ip = record['dstaddr']
dst_port = record['dstport']
action = record['action']
if action == 'REJECT':
rejected_counts[src_ip] += 1
# Track unique destination IPs per source
connections[src_ip]['destinations'].add(dst_ip)
connections[src_ip]['ports'].add(dst_port)
# Detect potential port scanning
for src_ip, data in connections.items():
if len(data['ports']) > 20:
print(f"ALERT: Potential port scan from {src_ip}")
print(f" Unique ports accessed: {len(data['ports'])}")
# Detect potential lateral movement
for src_ip, data in connections.items():
if len(data['destinations']) > 10:
print(f"ALERT: Potential lateral movement from {src_ip}")
print(f" Unique destinations: {len(data['destinations'])}")
# High rejection rates indicate probing
for src_ip, count in rejected_counts.items():
if count > 100:
print(f"ALERT: High rejection count for {src_ip}: {count}")
if __name__ == '__main__':
parse_flow_logs('/var/log/vpc-flow-logs.json')
Common Pitfalls and Best Practices
Over-permissive rules are the most common problem. That “temporary” rule allowing all traffic from the developer subnet has been there for three years. Audit regularly.
Rule sprawl happens when teams add rules without removing obsolete ones. Implement rule expiration and require justification for renewals.
Documentation gaps make incident response slower. Every rule should have a description explaining its purpose and owner.
Hardening checklist:
- Default deny on all firewalls
- No rules allowing 0.0.0.0/0 except public endpoints
- Separate management traffic from application traffic
- Log all denied connections
- Review rules quarterly
- Test rules after changes with actual traffic
- Use infrastructure as code—no manual rule changes
Network security isn’t glamorous, but it’s essential. Implement these controls properly, and you’ll significantly reduce your attack surface and limit damage when breaches occur.