How to Block Specific IP Addresses on AWS ELB: A Programmer’s Guide


3 views

When working with AWS Elastic Load Balancers (ELB), many developers face the limitation that Security Groups only support allow rules, not deny rules. This becomes problematic when you need to block specific malicious IP addresses while maintaining open access for legitimate traffic.

Here are three effective approaches to implement IP blocking behind an ELB:

# Example Network ACL rule to block IP 203.0.113.42
{
  "RuleNumber": 100,
  "Protocol": "6", # TCP
  "RuleAction": "deny",
  "Egress": false,
  "CidrBlock": "203.0.113.42/32",
  "PortRange": {
    "From": 80,
    "To": 80
  }
}

For more sophisticated protection, AWS WAF can be attached to your ALB:

aws wafv2 create-web-acl \
  --name MyWebACL \
  --scope REGIONAL \
  --default-action Allow={} \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MyWebACLMetrics \
  --rules 'Name=BlockIP,Priority=1,Action=Block,Statement={IPSetReferenceStatement={ARN=arn:aws:wafv2:us-east-1:123456789012:regional/ipset/MyIPSet/b6e6f123-4e9a-4e1a-93e0-123456789abc}}'

When you need immediate protection across all backend instances:

# Block single IP on all instances
sudo iptables -A INPUT -s 203.0.113.42 -j DROP

# Persist rules across reboots (Ubuntu/Debian)
sudo apt-get install iptables-persistent
sudo netfilter-persistent save

For frequently changing IP addresses, consider automating the blocking process:

#!/bin/bash
# Script to update blocked IPs from a file
BLOCKLIST="/etc/iptables/blocked_ips.conf"

while read -r ip; do
  iptables -A INPUT -s "$ip" -j DROP
done < "$BLOCKLIST"

When implementing these solutions:

  • Network ACLs have the least performance impact but are coarse-grained
  • WAF provides the most features but adds latency
  • iptables rules are immediate but require maintenance on all instances

Always verify your blocking rules are working:

# Check iptables rules
sudo iptables -L -n -v

# Test blocked access
curl -v http://your-elb-address -H "X-Forwarded-For: 203.0.113.42"

When working with AWS Elastic Load Balancers (ELB), many developers encounter the limitation that Security Groups (SGs) only support allow rules, not explicit deny rules. This becomes problematic when you need to block specific malicious IPs while maintaining global access to your application.

Here are three effective approaches to implement IP blocking:

1. Network ACLs at the Subnet Level

Network Access Control Lists (NACLs) operate at the subnet level and support explicit deny rules:

{
  "RuleNumber": 100,
  "Protocol": "6",  // TCP
  "RuleAction": "DENY",
  "Egress": false,
  "CidrBlock": "123.45.67.89/32",
  "PortRange": {
    "From": 80,
    "To": 80
  }
}

2. Web Application Firewall (WAF)

AWS WAF provides more granular control with IP matching conditions:

aws waf create-ip-set --name "BlockedIPs" \
--change-token $(aws waf get-change-token --query ChangeToken --output text) \
--region us-west-2

aws waf update-ip-set --ip-set-id "abc123" \
--change-token $(aws waf get-change-token --query ChangeToken --output text) \
--updates '[{"Action": "INSERT", "IPSetDescriptor": {"Type": "IPV4", "Value": "123.45.67.89/32"}}]' \
--region us-west-2

3. Instance-Level iptables Rules

For applications running on EC2 instances behind the ELB:

# Block specific IP
sudo iptables -A INPUT -s 123.45.67.89 -j DROP

# Block IP range
sudo iptables -A INPUT -s 123.45.67.0/24 -j DROP

# Make rules persistent
sudo apt-get install iptables-persistent
sudo netfilter-persistent save

Each approach has trade-offs:

  • NACLs: Stateless filtering affects all traffic in the subnet
  • WAF: Additional cost but provides centralized management
  • iptables: Requires maintenance on all backend instances

For a Rails application with Nginx/Unicorn, here's how to combine WAF with instance-level protection:

# Nginx configuration snippet
location / {
  deny 123.45.67.89;
  allow all;
  proxy_pass http://unicorn_app;
}