Why the default Docker bridge network is insecure, how network segmentation prevents lateral movement, and the production incidents that happen when containers share flat networks.
Most Docker deployments use the default bridge network. Every container can talk to every other container. A compromised web server can access databases directly. A frontend container can connect to internal APIs meant only for backend services. This is functionally similar to putting all servers on the same VLAN with no firewall rules—it works, but it violates every network security principle.
In pharmaceutical production environments managing AKS clusters under HIPAA and PCI DSS compliance, network segmentation isn’t optional. Payment processing must be isolated from application tier. PHI-containing databases must not be accessible from DMZ containers. Compliance auditors specifically check for network-level isolation between security zones.
This guide covers Docker network security from basics (custom bridge networks) through multi-tier architectures (PCI DSS data isolation), encrypted overlay networks, and the production incidents that happen when containers lack proper network segmentation.
The Problem with Default Bridge Network
When Docker is installed, it creates a default bridge network (bridge). All containers without explicit network configuration attach to this network.
Security Issues with Default Bridge
- Flat network topology: Every container can reach every other container by IP
- No automatic DNS: Must use container IPs (harder to firewall consistently)
- Shared broadcast domain: ARP poisoning affects all containers
- No network policies: Cannot restrict which containers communicate
- Difficult auditing: No visibility into inter-container traffic patterns
Real Impact: Lateral Movement
Attacker compromises a web container. Without network segmentation:
# Inside compromised web container
nmap 172.17.0.0/16 # Scan entire default bridge network
# Finds database at 172.17.0.5:5432
psql -h 172.17.0.5 -U postgres # Direct access - no firewall
With network segmentation, database is on separate network unreachable from web tier.
[IMAGE: Network diagram comparing flat default bridge (all containers connected) vs. segmented custom networks (web/app/data tiers isolated)]
Custom Bridge Networks: The Foundation
Custom bridge networks provide container-level DNS and network isolation.
Creating Custom Networks
# Create custom bridge network
docker network create --driver bridge frontend
# Run container on custom network
docker run -d --name web --network frontend nginx
# Containers can reference each other by name
docker run -d --name app --network frontend myapp
# Inside app container: curl http://web (DNS works automatically)
Network Isolation
Containers on different networks cannot communicate unless explicitly connected:
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx
networks:
- frontend # Web only on frontend network
app:
image: myapp
networks:
- frontend # App on both networks (acts as gateway)
- backend
db:
image: postgres
networks:
- backend # DB only on backend network
networks:
frontend:
backend:
Result: Web cannot directly access DB. App acts as controlled gateway.
[IMAGE: Diagram showing three-tier architecture with frontend/backend networks and app container as the only cross-network bridge]
Internal Networks: Air-Gapped Containers
Internal networks have no gateway to the host or internet. Containers can only communicate with each other.
Use Case: Sensitive Data Processing
# Create internal network (no external access)
docker network create --driver bridge --internal data-processing
# Run ETL pipeline on internal network
docker run -d --name etl --network data-processing my-etl-job
# This container cannot reach internet, cannot be reached from outside
PCI DSS Cardholder Data Environment (CDE)
PCI DSS Requirement 1.2.1: “Restrict inbound and outbound traffic to that which is necessary for the cardholder data environment.”
services:
# CDE - Payment processing (internal network)
payment-processor:
image: payment-gateway
networks:
- cde-internal
environment:
- NO_INTERNET=true
# CDE - Cardholder database (internal network)
card-vault:
image: postgres
networks:
- cde-internal
volumes:
- card-data:/var/lib/postgresql/data
# Gateway (connects CDE to application tier)
payment-api:
image: payment-api-gateway
networks:
- frontend # Accepts requests from application
- cde-internal # Proxies to payment processor
# This is the ONLY container bridging CDE and application tier
networks:
frontend:
# Application tier - has internet access
cde-internal:
internal: true # PCI CDE - no internet access
Compliance benefit: Auditors can verify network-level isolation by inspecting network configuration, not just application firewalls.
Encrypted Overlay Networks (Swarm Mode)
Overlay networks enable container communication across multiple Docker hosts with built-in encryption.
Creating Encrypted Overlay Network
# Initialize Swarm
docker swarm init
# Create encrypted overlay network
docker network create \
--driver overlay \
--opt encrypted \
secure-backend
# Deploy service on overlay network
docker service create \
--name api \
--network secure-backend \
myapi:latest
What Gets Encrypted
- Data plane: All container-to-container traffic encrypted with AES-GCM
- Control plane: Swarm management traffic encrypted with TLS 1.2+
- Secret distribution: Secrets encrypted in transit between manager and worker nodes
Performance impact: ~10-15% throughput reduction due to encryption overhead. Negligible for most workloads, measurable for high-throughput data processing.
[IMAGE: Diagram showing multi-host overlay network with encrypted tunnel between Docker hosts]
Network Policies and Firewall Rules
Docker networks don’t provide Kubernetes-style NetworkPolicy. Implement egress control via iptables or third-party tools.
Restricting Outbound Traffic
# Allow container to only access specific external IPs
docker run -d \
--name restricted-app \
--cap-add=NET_ADMIN \
--network custom-network \
myapp
# Inside container or via host iptables:
iptables -A OUTPUT -d 10.0.1.50 -j ACCEPT # Allow internal API
iptables -A OUTPUT -d 0.0.0.0/0 -j REJECT # Block everything else
Third-Party Tools for Network Policy
- Calico: Kubernetes-style NetworkPolicy for Docker
- Weave Net: Encrypted overlay with built-in policies
- Cilium: eBPF-based network security and observability
Production Failure Scenarios
Scenario 1: Database Compromise via Flat Network
The Setup: A SaaS platform ran all containers on the default bridge network. Web servers, application servers, caching layer, and PostgreSQL database all shared 172.17.0.0/16.
The Failure: A stored XSS vulnerability in the web application allowed attackers to execute JavaScript that exfiltrated user session tokens. Using a compromised admin session, attackers gained shell access to a web container.
From the web container, they scanned the network:
# Inside web container
nmap -p 5432 172.17.0.0/16
# Found PostgreSQL at 172.17.0.8
# Weak password allowed direct connection
psql -h 172.17.0.8 -U postgres
# Full database access - no network firewall between web and database
Attackers exfiltrated 340,000 user records including payment information.
What Should Have Been Done: Three-tier network architecture:
services:
web:
networks:
- frontend # Internet-facing tier
app:
networks:
- frontend # Accepts requests from web
- backend # Can access database
db:
networks:
- backend # NOT accessible from frontend
With this architecture, web container cannot reach database network. Even with shell access, attacker is trapped in frontend network.
Impact: PCI DSS violation, $2.8M settlement with payment processor, mandatory third-party security audit ($150K), customer notification costs ($85K).
Key Lesson: Network segmentation creates mandatory choke points. Even if an attacker gains shell access, they cannot laterally move across network boundaries.
Scenario 2: Internal API Exposed via Shared Network
The Setup: A fintech company ran microservices in Docker. An internal admin API was “secured” via obscurity—it listened on a non-standard port with no authentication, assuming it was unreachable from the internet.
The Failure: All services shared the default bridge network. A developer debugging a frontend container accidentally exposed port 8888:
docker run -p 8888:80 frontend-debug
# Meant to expose port 80, but port 8888 was ALREADY IN USE by admin API
Docker’s port mapping exposed the internal admin API to the internet. The API allowed unauthenticated access to:
- User account modifications
- Transaction overrides
- Audit log deletion
Discovered by security researchers via Shodan scan. Public disclosure before company could patch.
What Should Have Been Done: Internal network for admin services:
services:
admin-api:
networks:
- internal-only # No port mappings, no internet access
management-portal:
networks:
- internal-only # Only accessible via VPN/bastion
- frontend # Can serve UI to authorized users
networks:
internal-only:
internal: true # Cannot be reached from host
Impact: Emergency disclosure to FinCEN, SOC 2 Type II certification suspended, 6-month remediation plan mandated by regulators.
Scenario 3: ARP Spoofing on Shared Broadcast Domain
The Setup: A multi-tenant platform ran customer containers on shared Docker hosts using the default bridge network.
The Failure: A malicious customer deployed a container that performed ARP spoofing:
# Inside attacker's container
arpspoof -i eth0 -t 172.17.0.10 172.17.0.1
# Claims to be the gateway, intercepts traffic from victim container
Because all containers shared the same Layer 2 broadcast domain, ARP spoofing affected every container on the host. Attacker intercepted:
- Database connection strings (captured during app startup)
- API keys in HTTP headers (services using HTTP internally)
- Session tokens (Redis cache connections)
What Should Have Been Done: Isolated networks per customer:
# Customer A's services
services:
customer-a-app:
networks:
- customer-a-network
# Customer B's services (completely isolated)
services:
customer-b-app:
networks:
- customer-b-network
networks:
customer-a-network:
customer-b-network:
Separate networks = separate broadcast domains. ARP spoofing cannot cross network boundaries.
Impact: 23 customer databases compromised, class-action lawsuit filed, platform shutdown for 48 hours during incident response, loss of enterprise customer base.
Key Lesson: Multi-tenancy requires network isolation. Shared Layer 2 domains enable broadcast-based attacks that affect all tenants.
Scenario 4: Unencrypted Cross-Host Communication
The Setup: A healthcare platform ran Docker Swarm with overlay networks but **without encryption** (--opt encrypted flag omitted). Containers communicated across 5 physical hosts.
The Failure: An attacker gained access to the data center network (compromised VPN credentials). They performed packet capture on the network switch:
# From compromised network position
tcpdump -i eth0 -w capture.pcap
# All container-to-container traffic captured in plaintext
Captured traffic included:
- Patient health records in transit between services
- Database credentials (PostgreSQL connection strings)
- JWT tokens for authentication
What Should Have Been Done: Enable overlay network encryption:
docker network create \
--driver overlay \
--opt encrypted \ # <-- CRITICAL FLAG
patient-data-network
Encrypted overlay networks use AES-GCM. Even with network access, attacker captures encrypted traffic.
Impact: HIPAA breach affecting 87,000 patients, HHS OCR investigation, $1.6M fine, mandatory encryption audit of all systems, CIO resignation.
Scenario 5: PCI DSS Audit Failure – Insufficient Network Segmentation
The Setup: An e-commerce platform processed credit cards in Docker containers. During PCI DSS audit, the QSA (Qualified Security Assessor) found that payment processing containers shared a network with general application services.
The Failure: PCI DSS Requirement 1.2.1 mandates restricting inbound and outbound traffic to the CDE. The platform’s architecture:
# FAILED PCI DSS - CDE not isolated
services:
payment-gateway:
networks:
- app-network # Shared with non-CDE services
product-catalog:
networks:
- app-network # Non-CDE service on same network as payment gateway
QSA identified that product catalog could directly connect to payment gateway. This violated network segmentation requirements.
What Should Have Been Done: Isolated CDE network:
services:
# CDE - Payment processing
payment-gateway:
networks:
- cde-internal # Isolated CDE network
# CDE - Card vault
card-vault:
networks:
- cde-internal
# Gateway - ONLY connection between CDE and application
payment-api-proxy:
networks:
- app-network # Application side
- cde-internal # CDE side
# Proxy enforces protocol, validates requests, logs all access
# Non-CDE - Product catalog
product-catalog:
networks:
- app-network # Cannot reach cde-internal
networks:
app-network:
cde-internal:
internal: true # No external access
Impact: Failed PCI DSS audit, payment processing suspended for 72 hours, $480K in lost revenue, emergency architecture redesign ($120K consultant fees), re-audit costs ($35K).
Key Lesson: Compliance frameworks like PCI DSS explicitly require network segmentation. “Application-level” security is not sufficient—network-level isolation is mandatory.
[IMAGE: Side-by-side comparison of failed vs. compliant PCI DSS network architecture with CDE boundaries marked]
Multi-Tier Network Architecture: Reference Implementation
Here’s a production-ready multi-tier architecture with defense in depth:
version: '3.8'
services:
# DMZ / Frontend Tier
nginx-proxy:
image: nginx:1.27.2-alpine3.20
ports:
- "443:443"
networks:
- dmz
deploy:
replicas: 2
# Application Tier
api-gateway:
image: api-gateway:latest
networks:
- dmz # Receives requests from nginx
- app-tier # Forwards to backend services
# NO direct database access
user-service:
image: user-service:latest
networks:
- app-tier # Can be called by API gateway
- data-tier # Can access user database
# Acts as controlled gateway to data tier
# Data Tier
user-db:
image: postgres:16.4-alpine3.20
networks:
- data-tier # NOT accessible from DMZ or app-tier directly
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
volumes:
- user-data:/var/lib/postgresql/data
# Internal Admin (Air-gapped)
admin-api:
image: admin-api:latest
networks:
- admin-internal
# No port mappings - only accessible via docker exec or VPN
admin-db:
image: postgres:16.4-alpine3.20
networks:
- admin-internal
networks:
dmz:
driver: bridge
# Internet-facing tier
app-tier:
driver: bridge
# Application logic tier
data-tier:
driver: bridge
internal: true # No internet access
admin-internal:
driver: bridge
internal: true # Completely air-gapped
secrets:
db_password:
file: ./secrets/db_password.txt
volumes:
user-data:
Network Flow Control
| From | To | Allowed? | Reason |
|---|---|---|---|
| Internet | nginx-proxy | ✅ Yes | Published port 443 |
| nginx-proxy | api-gateway | ✅ Yes | Both on dmz network |
| api-gateway | user-service | ✅ Yes | Both on app-tier network |
| user-service | user-db | ✅ Yes | Both on data-tier network |
| nginx-proxy | user-db | ❌ No | Different networks, not connected |
| api-gateway | user-db | ❌ No | api-gateway not on data-tier network |
| Internet | admin-api | ❌ No | No published ports, internal network |
| user-db | Internet | ❌ No | Internal network, no gateway |
Network Security Best Practices
1. Never Use Default Bridge Network
Always create custom networks with explicit isolation boundaries:
# DON'T
docker run -d myapp
# DO
docker network create app-network
docker run -d --network app-network myapp
2. Use Internal Networks for Data Tier
Databases, caches, message queues should never have internet access:
docker network create --internal data-tier
3. Encrypt Overlay Networks in Production
Always use --opt encrypted for multi-host deployments:
docker network create --driver overlay --opt encrypted prod-backend
4. Implement Network Policies
Use Calico, Weave, or iptables to enforce egress control:
# Allow only specific external IPs
iptables -A OUTPUT -d 10.0.1.0/24 -j ACCEPT
iptables -A OUTPUT -d 0.0.0.0/0 -j REJECT
5. Audit Network Configuration
Regularly verify network isolation:
# List all networks and connected containers
docker network ls
docker network inspect <network-name>
# Verify internal networks have no gateway
docker network inspect data-tier | grep Gateway
# Should show: "Gateway": ""
6. Document Network Boundaries
For compliance audits, maintain network diagrams showing:
- Security zones (DMZ, Application, Data, Admin)
- Network boundaries
- Gateway services bridging networks
- Encryption status
Key Takeaways
- Default bridge network is insecure—flat topology allows lateral movement
- Custom bridge networks provide DNS and isolation—containers on different networks cannot communicate
- Internal networks are air-gapped—no gateway to host or internet, essential for PCI DSS CDE
- Overlay networks enable multi-host communication—always use encryption in production
- Multi-tier architectures create mandatory choke points—attackers cannot bypass network boundaries even with shell access
- Network segmentation is a compliance requirement—PCI DSS, HIPAA, and SOC 2 mandate network-level isolation
- Layer 2 isolation prevents ARP poisoning—separate networks = separate broadcast domains
Network isolation is defense in depth. Application-level security (authentication, authorization) can fail. Network-level isolation ensures that even if an attacker compromises a container, they cannot laterally move to sensitive data tiers. For compliance-driven environments, network segmentation is not optional—it’s mandatory evidence for PCI DSS, HIPAA, and SOC 2 audits.
Previous: Image Supply Chain Security: Scanning, Signing, and SBOM
Next: Container Runtime Security: Escape Techniques and Detection
Hands-on lab: Lab 08: Network Isolation & Segmentation — Build multi-tier architectures, implement PCI DSS CDE isolation, and test network boundaries.