Configuring Firewalls
Purpose
Guide engineers through configuring firewalls across host-based (iptables, nftables, UFW), cloud-based (AWS Security Groups, NACLs), and container-based (Kubernetes NetworkPolicies) environments with practical rule examples and safety patterns to prevent lockouts and security misconfigurations.
When to Use This Skill
Trigger Phrases:
- "Configure firewall for [server/service]"
- "Set up security groups for [AWS resource]"
- "Allow port [X] through firewall"
- "Block IP address [X.X.X.X]"
- "Set up UFW on Ubuntu server"
- "Create iptables/nftables rules"
- "Configure bastion host firewall"
- "Implement egress filtering"
Common Scenarios:
- Initial server setup and hardening
- Exposing a new service (web server, API, database)
- Implementing network segmentation
- Creating bastion host or jump box
- Migrating from iptables to nftables
- Configuring cloud security groups
- Troubleshooting connectivity issues
Decision Framework: Which Firewall Tool?
Cloud Environments
AWS:
- Instance-level control → Security Groups (stateful, allow-only rules)
- Subnet-level enforcement → Network ACLs (stateless, allow + deny rules)
- Use both for defense-in-depth
GCP:
- Use VPC Firewall Rules (stateful, priority-based)
Azure:
- Use Network Security Groups (NSGs) (stateful, priority-based)
Host-Based Linux Firewalls
Ubuntu/Debian + Simplicity:
- Use UFW (Uncomplicated Firewall) - recommended for most users
- Front-end for iptables/nftables with simplified syntax
RHEL/CentOS/Fedora:
- Use firewalld (default on Red Hat ecosystem)
- Zone-based configuration with dynamic updates
Modern Distro + Advanced Control:
- Use nftables (best performance, modern standard)
- O(log n) performance vs iptables O(n)
- Unified IPv4/IPv6/NAT syntax
Legacy Systems:
- Use iptables (migrate to nftables when feasible)
- Required for older kernels (< 4.14)
Kubernetes/Containers
- Use NetworkPolicies (requires CNI plugin: Calico, Cilium, Weave)
- See references/k8s-networkpolicies.md
Stateful vs Stateless
Stateful (recommended for most cases):
- Automatically allows return traffic
- Simpler configuration
- Examples: Security Groups, UFW, nftables default
Stateless (specialized use):
- Must explicitly allow both directions
- Fine-grained control, less state tracking
- Examples: Network ACLs, custom nftables rules
Quick Start Examples
UFW (Ubuntu/Debian)
# 1. Set defaults
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 2. CRITICAL: Allow SSH before enabling (prevent lockout)
sudo ufw allow ssh
sudo ufw limit ssh # Rate-limit to prevent brute force
# 3. Allow web traffic
sudo ufw allow http # Port 80
sudo ufw allow https # Port 443
# 4. Allow from specific IP (e.g., database access)
sudo ufw allow from 192.168.1.100 to any port 5432
# 5. Enable firewall
sudo ufw enable
# 6. Verify rules
sudo ufw status verbose
For complete UFW patterns, see references/ufw-patterns.md
nftables (Modern Linux)
#!/usr/sbin/nft -f
# /etc/nftables.conf
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Accept loopback
iif "lo" accept
# Accept established connections (stateful)
ct state established,related accept
# Drop invalid packets
ct state invalid drop
# Allow SSH
tcp dport 22 accept
# Allow HTTP/HTTPS
tcp dport { 80, 443 } accept
# Log dropped packets
log prefix "nftables-drop: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Apply: sudo nft -f /etc/nftables.conf
Enable on boot: sudo systemctl enable nftables
For advanced patterns (sets, maps), see references/nftables-patterns.md
AWS Security Groups (Terraform)
# Web server security group
resource "aws_security_group" "web" {
name = "web-server-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
# Allow HTTP/HTTPS from anywhere
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow SSH from bastion only
ingress {
description = "SSH from bastion"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}
# Allow all outbound
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "web-server-sg"
}
}
For Security Groups vs NACLs guide, see references/aws-security-groups.md
Safety Checklist
Before enabling any firewall:
- Always allow SSH before enabling (prevent lockout)
- Test rules before enabling (dry-run when possible)
- Enable logging for debugging
- Document rules in version control (Git)
- Verify externally with nmap:
nmap -Pn <server-ip> - Have console access (cloud) or physical access (on-prem)
- Start with default deny, explicitly allow required traffic
- Use rate limiting for SSH (
ufw limit ssh)
Common Patterns
Pattern 1: Basic Web Server
Requirements:
- Allow HTTP (80) and HTTPS (443) from anywhere
- Allow SSH from specific IP or bastion only
- Default deny all other inbound traffic
UFW:
sudo ufw default deny incoming
sudo ufw allow from 203.0.113.0/24 to any port 22 # Office IP
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
nftables: See references/nftables-patterns.md for complete example
AWS Security Group: See references/aws-security-groups.md for Terraform module
Pattern 2: Database Server (Private)
Requirements:
- Allow database port (5432, 3306, etc.) from app tier only
- No public internet access
- SSH from bastion only
See references/database-patterns.md for implementation
Pattern 3: Bastion Host (Jump Box)
Purpose: Single hardened entry point for SSH access
See references/bastion-pattern.md for complete implementation
Pattern 4: Egress Filtering
Purpose: Control outbound traffic to prevent data exfiltration
See references/egress-filtering.md for implementation
Key Concepts
Stateful Firewalls
Track connection state (established, related, new):
- Automatically allow return traffic
- Simpler rule configuration
- Used by: Security Groups, UFW, nftables (default)
Stateless Firewalls
No connection tracking:
- Must explicitly allow both directions
- Must allow ephemeral ports (1024-65535) for return traffic
- Used by: Network ACLs
Defense-in-Depth
Layer multiple firewall controls:
- Cloud: Security Groups + NACLs
- Host: UFW/nftables + fail2ban
- Container: NetworkPolicies
Rule Evaluation
Security Groups (AWS): All rules evaluated, most permissive wins Network ACLs (AWS): Sequential evaluation, first match wins nftables/iptables: Sequential, first match wins UFW: Sequential by rule number
Universal Best Practices
- Default Deny: Start with deny-all, explicitly allow required traffic
- Principle of Least Privilege: Only open necessary ports/IPs
- No 0.0.0.0/0 on Sensitive Ports: Never allow SSH/RDP/database from anywhere
- Version Control: Store firewall rules in Git
- Logging: Enable and monitor firewall logs
- Regular Audits: Review rules quarterly, remove unused
- Don't Mix Tools: Avoid running iptables and nftables simultaneously
- Test Before Production: Use staging environment first
Advanced Topics
Bastion Host Architecture: See references/bastion-pattern.md for single entry point patterns
DMZ (Demilitarized Zone): See references/dmz-pattern.md