Skip to main content
emnode
Compliance Low severity

AWS Security Hub · ELB

ELB.7: CLBs should have connection draining

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub ELB.7 check?

ELB.7 fails when a Classic Load Balancer does not have connection draining enabled. Draining lets in-flight requests to a deregistering or unhealthy instance complete before the connection is closed.

Why does ELB.7 matter?

Without draining, a CLB severs connections the instant an instance is deregistered (during a deploy, scale-in or health-check flap), so users mid-request see resets and errors instead of a clean response. Enabling it is a one-call change and a Low-severity hygiene item, but it also surfaces a bigger question: Classic Load Balancers are previous-generation, and closing this finding is a good prompt to consider migrating to an ALB or NLB.

How do I fix ELB.7?

  1. Audit CLBs and check the ConnectionDraining attribute with describe-load-balancer-attributes.
  2. Enable it with modify-load-balancer-attributes and set a sensible timeout (e.g. 300s) that matches your longest legitimate request.
  3. Confirm the timeout works with Auto Scaling lifecycle hooks and any long-lived connections.
  4. Consider whether the CLB should be migrated to an ALB or NLB rather than maintained.

Remediation script · bash

# Harden every Application Load Balancer in the region: reject invalid headers and
# require defensive (or strictest) desync mode. Both are instant, non-disruptive flips.
for arn in $(aws elbv2 describe-load-balancers \
    --query 'LoadBalancers[?Type==`application`].LoadBalancerArn' --output text); do
  aws elbv2 modify-load-balancer-attributes --load-balancer-arn "$arn" \
    --attributes \
      Key=routing.http.drop_invalid_header_fields.enabled,Value=true \
      Key=routing.http.desync_mitigation_mode,Value=defensive
  echo "$arn: hardened"
done

# Switch load-balanced Auto Scaling groups to ELB health checks with a safe grace period
# (confirm the target-group probe reflects real app health first).
for g in $(aws autoscaling describe-auto-scaling-groups \
    --query 'AutoScalingGroups[?(LoadBalancerNames!=`[]` || TargetGroupARNs!=`[]`) && HealthCheckType==`EC2`].AutoScalingGroupName' \
    --output text); do
  aws autoscaling update-auto-scaling-group --auto-scaling-group-name "$g" \
    --health-check-type ELB --health-check-grace-period 300
  echo "$g: now using ELB health checks"
done

Full walkthrough (console steps, edge cases and verification) in the lesson Harden load balancers (ALB/NLB/CLB).

Is ELB.7 a false positive?

Connection draining only helps when a target can finish its in-flight request before going away, so a CLB fronting a purely stateless, short-lived workload (or one whose backends terminate connections themselves on deregistration) gets little from it, and an operator may have left it off deliberately. That intentional choice still fails ELB.7, which just checks the ConnectionDraining attribute. Given the Low severity and the one-call cost of enabling it, the cleaner move is usually to turn draining on anyway with a short timeout; but where it is genuinely a no-op, record the rationale and suppress the finding in Security Hub rather than carrying it as a permanent open item.

Part of the learning path Build in resilience
  • ELB.1 ALB serves HTTP without redirecting to HTTPS
  • ELB.2 CLB SSL/HTTPS listeners should use ACM certs
  • ELB.3 CLB listeners should use HTTPS/TLS termination
  • ELB.4 ALB accepts malformed HTTP headers
  • ELB.5 Load balancers are not writing access logs
  • ELB.6 Load balancers can be deleted by accident
  • ELB.8 CLB SSL listeners should use strong policy
  • ELB.9 CLBs should have cross-zone balancing
  • ELB.10 CLBs should span multiple AZs
  • ELB.12 ALB desync mitigation mode
  • ELB.13 A single-AZ load balancer is a data-plane single point of failure
  • ELB.14 CLB desync mitigation mode