Back to Blog

How DDoS Attacks Hit Kubernetes Differently

Kubernetes introduces attack surfaces that bare-metal deployments do not have. Understanding where DDoS traffic can enter your cluster is the starting point for defense.

Attack surface 1: LoadBalancer services. When you expose a service with type: LoadBalancer, your cloud provider allocates a public IP and routes traffic to your node's NodePort. The cloud load balancer is your first line of defense: many cloud providers include basic DDoS protection at the load balancer level. But this protection is often shallow and does not prevent application-layer attacks from reaching your pods.

Attack surface 2: Ingress controllers. Your Nginx, Traefik, or Istio ingress controller terminates HTTP/HTTPS traffic and routes it to services. An HTTP flood targeting your ingress controller exhausts its worker processes, making the entire cluster's HTTP traffic inaccessible even if only one service is being targeted.

Attack surface 3: NodePort services. Any service of type: NodePort exposes ports directly on all cluster nodes. An attacker who discovers your node IPs can bypass your load balancer and attack node ports directly.

Attack surface 4: Node-level network exhaustion. A volumetric attack against a node's network interface saturates the node's bandwidth, affecting all pods running on that node: not just the targeted service. One attacked node takes down collocated pods of unrelated services.

Layer 1: Cloud Load Balancer DDoS Protection

Your cloud provider's load balancer is the furthest upstream point where DDoS mitigation can occur. Enable all available DDoS protection at this layer before configuring anything in Kubernetes.

AWS (EKS / Application Load Balancer)

# Enable AWS Shield Advanced on your ALB (via AWS Console or CLI)
aws shield create-protection \
  --name "EKS-ALB-Protection" \
  --resource-arn arn:aws:elasticloadbalancing:us-east-1:ACCOUNT:loadbalancer/app/my-alb/abc123

# Add WAF WebACL with rate-based rules to the ALB
# (requires AWS WAF configuration - apply to ALB via Console or CLI)
# Rate-based rule: block source IPs sending > 2000 requests in 5 minutes

GKE (Google Kubernetes Engine)

# Create a BackendConfig to enable Cloud Armor on your GKE service
# backend-config.yaml
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: my-backend-config
  namespace: default
spec:
  securityPolicy:
    name: ddos-policy  # Reference to your Cloud Armor security policy
  connectionDraining:
    drainingTimeoutSec: 60

---
# Reference BackendConfig in your Service
apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    cloud.google.com/backend-config: '{"default": "my-backend-config"}'
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080

Azure (AKS / Application Gateway)

# Enable Azure DDoS Network Protection on your VNet via Azure CLI
az network ddos-protection create \
  --name myDdosPlan \
  --resource-group myRG \
  --location eastus

# Associate with your AKS VNet
az network vnet update \
  --name myAKSVNet \
  --resource-group myRG \
  --ddos-protection true \
  --ddos-protection-plan myDdosPlan

Layer 2: Ingress Controller Rate Limiting

Configure rate limiting at your ingress controller to stop HTTP floods before they reach your pods.

Nginx Ingress Controller

# Apply annotations to your Ingress resource
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    # Rate limit: 30 requests per second per IP
    nginx.ingress.kubernetes.io/limit-rps: "30"

    # Burst limit: allow bursts up to 50 above the rate
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "2"

    # Connection limit per IP
    nginx.ingress.kubernetes.io/limit-connections: "20"

    # Return 429 when rate limit is exceeded
    nginx.ingress.kubernetes.io/limit-req-status-code: "429"

    # Custom configuration snippet for additional protection
    nginx.ingress.kubernetes.io/configuration-snippet: |
      limit_req_zone $binary_remote_addr zone=per_ip:10m rate=30r/s;
      limit_req zone=per_ip burst=50 nodelay;
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-api-service
            port:
              number: 80

Traefik Ingress Controller

# Create a RateLimit middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
  namespace: default
spec:
  rateLimit:
    average: 30        # average requests per second
    burst: 50          # maximum burst size
    period: 1s
    sourceCriterion:
      ipStrategy:
        depth: 1        # use first IP in X-Forwarded-For

---
# Reference middleware in IngressRoute
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: my-app-route
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`api.example.com`)
    kind: Rule
    services:
    - name: my-api-service
      port: 80
    middlewares:
    - name: rate-limit

Layer 3: Kubernetes Network Policies

Network policies restrict which pods can communicate with which other pods and which external IPs can reach your services. They are your in-cluster firewall.

# Deny all ingress to your application pods by default, then allow only what is needed
# This limits the blast radius when a DDoS hits: only the explicitly exposed pods
# can be reached, not your internal services

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-isolation
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # Only allow traffic from the ingress controller namespace
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  # Allow inter-service communication within the production namespace
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: production
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # Allow DNS resolution
  - ports:
    - protocol: UDP
      port: 53
  # Allow outbound to your database
  - to:
    - podSelector:
        matchLabels:
          app: postgres
    ports:
    - protocol: TCP
      port: 5432

Network policies require a CNI plugin that supports them: Calico, Cilium, Weave, or Antrea. The default Kubernetes network does not enforce network policies. If you have not installed a CNI plugin, network policies are silently ignored.

Cilium: eBPF-based policies with L7 awareness

# Cilium L7 policy to rate limit HTTP requests to a specific endpoint
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-rate-limit
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/api/.*"
          # Cilium L7 rate limiting (Cilium 1.14+)
          headers:
          - "X-My-Header: exists"

The HPA Problem: DDoS Can Trigger Auto-Scaling Costs

Horizontal Pod Autoscaler (HPA) scales your pod count based on CPU/memory/custom metrics. During a DDoS attack, request volume or CPU usage spikes, and HPA may scale out your deployment significantly, increasing cloud costs without improving availability (since the attacker can simply send more traffic to match).

# Add a maxReplicas ceiling to prevent runaway scaling during attacks
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20       # Set this deliberately: DDoS can drive this to max
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleUp:
      # Add stabilization window to prevent rapid scale-out during brief DDoS
      stabilizationWindowSeconds: 60
      policies:
      - type: Pods
        value: 4          # Scale out at most 4 pods per scaling event
        periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300   # 5 minute cooldown before scale-in

If you use AWS EKS with Shield Advanced, enable DDoS cost protection to be reimbursed for scaling costs caused by DDoS-induced traffic spikes. On GKE, set billing alerts and scale-out notifications to detect abnormal scaling events that may indicate an attack.

Layer 4: Per-Node Detection with Flowtriq

All the Kubernetes-layer controls above operate at the service, pod, or network policy level. They do not give you visibility into what is happening at the node's network interface: the actual packet rates, attack classification, and forensic data your team needs during and after an incident.

Flowtriq runs as a DaemonSet on your Kubernetes nodes, monitoring each node's network interface independently. When an attack saturates one node's bandwidth, Flowtriq detects it within 1-2 seconds, classifies the attack type, fires alerts to your operational channels, and can apply node-level iptables rules to drop attack traffic before it reaches the pod network.

# Deploy Flowtriq as a DaemonSet on all nodes
# (Flowtriq DaemonSet manifest - obtain from docs.flowtriq.com)
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ftagent
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: ftagent
  template:
    metadata:
      labels:
        name: ftagent
    spec:
      hostNetwork: true          # Required: agent must see node network interface
      hostPID: true              # Required: agent needs process namespace access
      priorityClassName: system-node-critical
      tolerations:
      - operator: Exists         # Run on all nodes including control plane
      containers:
      - name: ftagent
        image: flowtriq/ftagent:latest
        securityContext:
          privileged: true       # Required for network interface monitoring
        env:
        - name: FLOWTRIQ_API_KEY
          valueFrom:
            secretKeyRef:
              name: flowtriq-credentials
              key: api-key
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 200m
            memory: 256Mi

With Flowtriq running on each node, you have:

  • Per-node PPS and Mbps metrics with per-second granularity
  • Attack classification (SYN flood, UDP flood, HTTP flood, and more) within 1-2 seconds
  • PCAP capture for every detected attack on every node
  • Instant alerts through Slack, Discord, PagerDuty, or any configured channel
  • Automatic iptables rule injection on the affected node to drop attack traffic
  • BGP webhook triggers for upstream RTBH or scrubbing center diversion

Frequently Asked Questions

Do Kubernetes Network Policies stop DDoS attacks?

Network policies control which pods can communicate with which other pods and services, providing east-west traffic segmentation. They limit the blast radius of a DDoS attack by preventing it from spreading to internal services. However, network policies operate at the Kubernetes network overlay level and do not protect against volumetric attacks that saturate a node's physical network interface before traffic reaches the pod network. A 10 Gbps UDP flood against a node will saturate the node's uplink regardless of network policies, because the packets arrive at the physical interface before any network policy evaluation occurs. Network policies are necessary but not sufficient for DDoS protection.

Can I use Flowtriq with managed Kubernetes (EKS, GKE, AKS)?

Yes. Flowtriq's DaemonSet runs on worker nodes across all managed Kubernetes platforms. Worker nodes in EKS, GKE, and AKS are Linux VMs, and Flowtriq's agent monitors their network interfaces directly. For EKS, you deploy the DaemonSet to your node groups. For GKE, deploy to your node pools with appropriate tolerations. For AKS, deploy to your Linux agent node pools. Control plane nodes (which are managed by the cloud provider and not accessible) do not need Flowtriq coverage as they do not handle customer traffic directly.

What happens to my cluster if a DDoS attack saturates one node?

If a volumetric attack saturates a node's network interface bandwidth, all pods on that node experience packet loss: not just the pods associated with the targeted service. This is one of the reasons pod placement strategy matters for DDoS resilience. Using pod anti-affinity rules to distribute critical services across multiple nodes limits the blast radius: if one node is saturated, pods on other nodes continue operating normally. Flowtriq's per-node detection alerts you when one node is under attack, giving you the information to drain the affected node and reschedule pods before the attack fully impacts availability.

Should I block traffic at the ingress controller or at the network policy level?

Both, for different threat types. The ingress controller (Nginx, Traefik) is the right place to enforce HTTP-layer controls: rate limiting, connection limits, bad user agent blocking, geographic filtering. These operate on HTTP semantics that network policies cannot see. Network policies are the right place to enforce pod-to-pod isolation and restrict which external sources can reach internal services. For volumetric attacks that operate below the HTTP layer (SYN floods, UDP floods), neither the ingress controller nor network policies help: you need node-level detection and upstream mitigation. Use all three layers: ingress controller for L7, network policies for east-west isolation, and Flowtriq for node-level L3/L4 detection.

Per-node DDoS detection for every Kubernetes worker

Flowtriq's DaemonSet gives you 1-second detection, attack classification, PCAP forensics, and instant alerts across every node in your cluster. $9.99/node/month with a 7-day free trial.

Start your free trial →
Back to Blog

Related Articles