Section 04

Defense in Depth

Defense in Depth is a security strategy that layers multiple security controls throughout an IT system. If one layer fails, other layers continue to provide protection.

The Castle Analogy

Medieval castles had moats, walls, gates, guards, and a keep. Each layer slowed attackers and gave defenders time to respond. Modern systems need the same layered approach.

Security Layers

Layer 1

Physical Security

Data center access controls, surveillance, environmental controls, hardware security.

  • • Biometric access to server rooms
  • • Security cameras and motion sensors
  • • Hardware destruction policies
Layer 2

Network Security

Firewalls, IDS/IPS, network segmentation, DDoS protection, VPNs.

  • • Next-gen firewalls with deep packet inspection
  • • Network segmentation with VLANs
  • • Zero Trust network architecture
Layer 3

Perimeter Security

WAF, API gateways, DDoS mitigation, email security, reverse proxies.

  • • Web Application Firewall (WAF) rules
  • • Rate limiting and throttling
  • • Bot detection and mitigation
Layer 4

Host Security

OS hardening, endpoint protection, host-based firewalls, patch management.

  • • Minimal OS installations
  • • EDR/XDR solutions
  • • Automated patching pipelines
Layer 5

Application Security

Secure coding, input validation, authentication, authorization, SAST/DAST.

  • • Security-focused code reviews
  • • OWASP Top 10 mitigations
  • • Runtime application self-protection (RASP)
Layer 6

Data Security

Encryption, access controls, DLP, backup and recovery, data classification.

  • • Encryption at rest and in transit
  • • Database activity monitoring
  • • Data loss prevention (DLP) rules

Network Segmentation

Network segmentation divides a network into smaller, isolated segments. This limits lateral movement and contains breaches to a single segment.

DMZ Architecture

Isolate public-facing services from internal network.

Internet → [Firewall] → DMZ → [Firewall] → Internal
  • • Web servers in DMZ
  • • Database servers internal
  • • Strict ingress/egress rules

Micro-Segmentation

Granular segmentation at workload level.

App1 ←→ DB1 only
App2 ←→ DB2 only
App1 ✗ DB2 blocked
  • • Software-defined networking
  • • Container network policies
  • • Service mesh enforcement

Practical: Kubernetes Network Policy

network-policy.yaml
yaml
# Default-deny all ingress, then whitelist specific flows
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow-frontend-only
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # Only allow traffic from frontend pods on port 8080
    - from:
        - podSelector:
            matchLabels:
              app: frontend
        - namespaceSelector:
            matchLabels:
              name: production
      ports:
        - protocol: TCP
          port: 8080
  egress:
    # Only allow traffic to the database on port 5432
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    # Allow DNS resolution
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
# Default-deny all ingress, then whitelist specific flows
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow-frontend-only
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # Only allow traffic from frontend pods on port 8080
    - from:
        - podSelector:
            matchLabels:
              app: frontend
        - namespaceSelector:
            matchLabels:
              name: production
      ports:
        - protocol: TCP
          port: 8080
  egress:
    # Only allow traffic to the database on port 5432
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    # Allow DNS resolution
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

Practical: AWS Security Groups with Terraform

security-groups.tf
hcl
# Defense in Depth: layered security groups
# Layer 3 — ALB (public-facing)
resource "aws_security_group" "alb" {
  name_prefix = "alb-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # HTTPS from internet
  }

  egress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]  # Only to app tier
  }
}

# Layer 4 — Application tier (private)
resource "aws_security_group" "app" {
  name_prefix = "app-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id]  # Only from ALB
  }

  egress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.db.id]  # Only to database
  }
}

# Layer 6 — Database tier (isolated)
resource "aws_security_group" "db" {
  name_prefix = "db-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]  # Only from app tier
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = []  # No outbound — fully isolated
  }
}
# Defense in Depth: layered security groups
# Layer 3 — ALB (public-facing)
resource "aws_security_group" "alb" {
  name_prefix = "alb-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # HTTPS from internet
  }

  egress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]  # Only to app tier
  }
}

# Layer 4 — Application tier (private)
resource "aws_security_group" "app" {
  name_prefix = "app-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id]  # Only from ALB
  }

  egress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.db.id]  # Only to database
  }
}

# Layer 6 — Database tier (isolated)
resource "aws_security_group" "db" {
  name_prefix = "db-"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]  # Only from app tier
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = []  # No outbound — fully isolated
  }
}

Practical: Linux Host Hardening with iptables

iptables-hardening.sh
bash
#!/bin/bash
# Host-level defense — Layer 4 hardening
set -euo pipefail

# Flush existing rules
iptables -F
iptables -X

# Default deny all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# Allow loopback
iptables -A INPUT  -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow established/related connections
iptables -A INPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH from management VLAN only (Layer 2 segmentation ties in here)
iptables -A INPUT -s 10.10.50.0/24 -p tcp --dport 22 -j ACCEPT

# Allow HTTPS inbound (app port)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow DNS outbound
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

# Allow NTP outbound (time sync)
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT

# Allow HTTPS outbound (package updates, APIs)
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT

# Rate-limit ICMP to prevent ping floods
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 1/s --limit-burst 4 -j ACCEPT

# Log dropped packets for monitoring (Layer 7 tie-in)
iptables -A INPUT  -j LOG --log-prefix "IPT-DROP-IN: "
iptables -A OUTPUT -j LOG --log-prefix "IPT-DROP-OUT: "

echo "[+] iptables hardened — default deny active"
#!/bin/bash
# Host-level defense — Layer 4 hardening
set -euo pipefail

# Flush existing rules
iptables -F
iptables -X

# Default deny all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# Allow loopback
iptables -A INPUT  -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow established/related connections
iptables -A INPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH from management VLAN only (Layer 2 segmentation ties in here)
iptables -A INPUT -s 10.10.50.0/24 -p tcp --dport 22 -j ACCEPT

# Allow HTTPS inbound (app port)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow DNS outbound
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

# Allow NTP outbound (time sync)
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT

# Allow HTTPS outbound (package updates, APIs)
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT

# Rate-limit ICMP to prevent ping floods
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 1/s --limit-burst 4 -j ACCEPT

# Log dropped packets for monitoring (Layer 7 tie-in)
iptables -A INPUT  -j LOG --log-prefix "IPT-DROP-IN: "
iptables -A OUTPUT -j LOG --log-prefix "IPT-DROP-OUT: "

echo "[+] iptables hardened — default deny active"

Defense-in-Depth Tools

Layer Tool Purpose
Network Calico / Cilium K8s network policies, eBPF-powered segmentation
Perimeter AWS WAF / Cloudflare Web application firewall, DDoS protection
Host CrowdStrike / Wazuh EDR/XDR, host-based IDS, file integrity
Application Falco / Snyk Runtime detection, SCA, vulnerability scanning
Data AWS KMS / Vault Key management, encryption, secrets

Principle of Least Privilege

Every user, process, and system should have only the minimum permissions necessary to perform their function. Nothing more.

User Accounts

  • • No standing admin privileges—use just-in-time access
  • • Separate accounts for admin and daily work
  • • Regular access reviews and recertification
  • • Automatic deprovisioning when roles change

Service Accounts

  • • Unique service account per application
  • • No interactive login allowed
  • • Scoped permissions to specific resources
  • • Credential rotation policies

Database Access

  • • Application accounts with only needed tables/procedures
  • • Read-only replicas for reporting
  • • No direct production database access
  • • Stored procedures instead of direct queries

Fail-Safe Defaults

Deny by Default

  • • Firewall: Block all, allow specific
  • • IAM: No permissions until granted
  • • API: Require authentication
  • • Features: Opt-in, not opt-out

Fail Securely

  • • Errors don't expose sensitive data
  • • Auth failures deny access, don't skip
  • • Exceptions caught and handled safely
  • • Timeouts close connections cleanly

Redundancy & Resilience

No Single Points of Failure

Critical security controls should have redundancy. If one WAF fails, another takes over.

Graceful Degradation

Systems should maintain security even when components fail. Read-only mode is safer than complete shutdown.

Circuit Breakers

Automatically stop calling failing services to prevent cascade failures and resource exhaustion.

Framework Alignment

NIST CSF 2.0: PR.AC (Access Control), PR.DS (Data Security), PR.IP (Information Protection), DE.CM (Continuous Monitoring)
ISO 27002:2022: A.8.20 (Network Security), A.8.21 (Web Filtering), A.8.22 (Network Segmentation), A.8.23 (Web Filtering)
CIS Controls v8.1: 3 (Data Protection), 4 (Secure Config), 12 (Network Infrastructure), 13 (Network Monitoring/Defense)
Related: Security Frameworks →