Network Isolation for Security
LEVEL 0
The Problem
You’re running a Docker host with containers from multiple projects:
- Your company’s production web application
- A staging environment for testing
- Development containers for your team
- A third-party monitoring tool
- A database with customer data
Without network isolation, any container can potentially reach any other container. A compromised development container could access the production database. The monitoring tool could be exploited to attack your web application.
This is dangerous. You need security boundaries.
How do you ensure:
- Containers from different projects can’t see each other?
- Sensitive data is protected by network segmentation?
- Even if one container is compromised, the blast radius is limited?
LEVEL 1
The Concept — Security Zones in a Facility
The Concept
Imagine a research facility with different security zones:
Public Zone (Lobby): Anyone can enter. Minimal security.
Employee Zone (Offices): Need an employee badge. General employees can access.
Secure Zone (Labs): Need special clearance. Only authorized researchers.
Maximum Security Zone (Vault): Biometrics, armed guards, double doors. Only top-level personnel.
Each zone has walls and checkpoints. You can’t walk from the lobby directly into the vault.
Docker networks create these security zones. Containers in the “Public Zone” network can’t see or access containers in the “Maximum Security Zone” network.
And just like in a facility, you can have bridge rooms—special areas (containers) that have access to multiple zones, acting as controlled gateways.
LEVEL 2
The Mechanics — Network Segmentation
The Mechanics
Principle 1: One network per trust boundary
Don’t put all containers on the same network. Create isolated networks based on trust levels:
# Public-facing services
docker network create dmz-network
# Internal application services
docker network create app-network
# Sensitive data services
docker network create data-network
# CI/CD and development
docker network create dev-network
Principle 2: Least privilege access
Containers should only be on networks they truly need to access.
Bad (everything on one network):
docker run --network default-bridge web-app
docker run --network default-bridge database
docker run --network default-bridge dev-tool
Good (segmented):
# Web app on DMZ and app networks
docker run --network dmz-network web-app
docker network connect app-network web-app
# Database only on data network
docker run --network data-network database
# API on app and data networks (bridge between them)
docker run --network app-network api
docker network connect data-network api
# Dev tool isolated
docker run --network dev-network dev-tool
Principle 3: Internal networks for maximum security
For networks that should have NO external access:
docker network create --internal secure-processing
Containers on secure-processing can talk to each other but can’t reach the internet or other networks. Perfect for air-gapped workloads.
LEVEL 3
Multi-Network Container Architecture
A common pattern: containers connected to multiple networks act as secure gateways.
Example: Three-tier architecture with security boundaries
# Create networks
docker network create public-dmz
docker network create application-tier
docker network create database-tier --internal
# Public load balancer (only on DMZ)
docker run -d \
--name lb \
--network public-dmz \
-p 443:443 \
nginx
# Web frontend (on DMZ and app tier)
docker run -d \
--name frontend \
--network public-dmz \
my-frontend
docker network connect application-tier frontend
# API backend (on app tier and database tier)
docker run -d \
--name api \
--network application-tier \
my-api
docker network connect database-tier api
# Database (only on database tier, internal network)
docker run -d \
--name postgres \
--network database-tier \
postgres:15
# Redis cache (only on database tier)
docker run -d \
--name cache \
--network database-tier \
redis:7
Security boundaries:
- Load balancer: Exposed to internet, can only reach frontend
- Frontend: Can reach API but NOT database or cache
- API: Can reach database and cache (controlled gateway)
- Database/Cache: Cannot be reached from internet or frontend, only from API
Verification:
# From frontend, try to reach database directly
docker exec frontend ping postgres
# Should fail! Different networks, no route.
# From API, reach database
docker exec api ping postgres
# Works! They're on the same network.
LEVEL 4
Network Policies and Firewall Rules
Docker networks provide isolation at the network layer, but you can add additional security with iptables rules or third-party tools.
Example: iptables rule to restrict inter-container traffic
# Block traffic from one Docker network to another
iptables -I DOCKER-USER -s 172.18.0.0/16 -d 172.19.0.0/16 -j DROP
This prevents containers on the 172.18.x.x network from reaching containers on the 172.19.x.x network, even if both are on the same host.
Network plugins for advanced security:
Tools like Calico, Weave, or Cilium provide:
- Network policies (allow/deny rules between containers)
- Encryption of container-to-container traffic
- Advanced firewall capabilities
LEVEL 5
Security Best Practices
1. Never use the default bridge for production
The default bridge has no network isolation and no DNS. Create custom networks for every project.
2. Use internal networks for sensitive data
docker network create --internal secrets-network
This network can’t access the internet, preventing data exfiltration.
3. Minimize network exposure
Only expose ports that absolutely must be public:
# Bad: Exposing database to host
docker run -p 5432:5432 postgres
# Good: Database only on internal network
docker run --network app-internal postgres
4. Audit network memberships regularly
# See all containers on a network
docker network inspect app-network
# See all networks a container is on
docker inspect container-name --format='{{json .NetworkSettings.Networks}}'
5. Use read-only containers when possible
docker run --read-only --tmpfs /tmp my-app
If a container is compromised, attackers can’t modify the filesystem.
6. Drop unnecessary capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE my-app
Reduces attack surface.