Course outline

24.3

Blocking an IP Address at Each Layer

NACLs, security groups, ALB, NLB, WAF and CloudFront: which one can see the real client IP.

18 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Say, for any architecture, which address each hop sees as the source: the NACL, the security group, the ALB, the NLB and its targets, AWS WAF, CloudFront and an origin behind CloudFront.
  • Block one IP address on an EC2 instance with a public IP: a NACL deny numbered before the allow, why a security group cannot do it, and what a host firewall costs.
  • Block an IP behind an ALB with a NACL on the ALB's subnets or a source-ip listener rule with a fixed 403 response, and explain why nothing behind the ALB can.
  • Block an IP behind an NLB with a NACL, and explain what the NLB's allow-only security groups, client IP preservation and the missing WAF support change.
  • Choose ALB + WAF when the list is long or SQL injection, XSS and rate limiting are needed too, and know the NACL and listener rule quotas that make it necessary.
  • Block at the edge when CloudFront is in front (WAF in us-east-1, geo restriction), explain why the NACL is “not helpful” there, and lock the origin with the CloudFront prefix list, a secret header or a VPC origin.

#One address, five architectures

The education board's exam-results site has a problem every result day: a scraper at 203.0.113.50 downloads every result to sell to coaching centres. “Block that IP” sounds like one task. On AWS it is five different tasks, because the right tool depends on what stands between the client and the server, and each thing in between can change the source address that the next layer sees.

This lesson takes the five designs of slides p813–p817 one by one:

  1. An EC2 instance with a public IP.
  2. EC2 instances behind an ALB.
  3. EC2 instances behind an NLB.
  4. An ALB with AWS WAF.
  5. An ALB behind CloudFront, with WAF.

Almost every building block is already taught: network ACLs and security groups in lesson 3.5, the ALB's source-ip rule, X-Forwarded-For and NLB client IP preservation in lesson 6.3, CloudFront geo restriction and origin locking in lesson 11.2, WAF IP sets and rate-based rules in lesson 21.6. Here we put them together and ask one question at every hop: which IP address does this layer actually see?

#The tools, and what each one sees

ToolWhere it runsCan it deny one IP?What it matches on
Network ACLSubnet boundary, statelessYes: numbered allow and deny rulesThe packet's source address
Security groupEach network interface (instance, ALB, NLB), statefulNo: allow rules onlyThe packet's source address
Host firewall (iptables, nftables, Windows Defender Firewall)Inside the operating systemYesThe packet's source address, as it arrives at the instance
ALB listener rule (source-ip condition)The ALBYes, with a fixed-response such as 403The address of the connection the ALB received
AWS WAF IP set (web ACL)CloudFront, ALB, API Gateway REST API…Yes, up to 10,000 entries per IP setThe connection's source, or an IP in a header such as X-Forwarded-For if you configure it
CloudFront geo restrictionEdge locationWhole countries onlyThe country of the viewer's address

The second column is the key. Every proxy in the path (ALB, CloudFront) ends the client's connection and opens a new one from its own address. Every layer after that proxy sees the proxy, not the client. A pass-through load balancer (the NLB with instance targets) does not end the connection, so the address survives.

#Network ACL recap: order, state and size

From lesson 3.5, the four facts this lesson depends on:

  • First match wins, lowest number first. A deny must have a lower number than every allow it must beat. A deny numbered 200 behind an allow-all numbered 100 is never read.
  • Stateless. Blocking inbound is enough to stop a client, but your allow rules still need the outbound ephemeral ports (1024–65535) for the replies to everybody else.
  • One NACL per subnet. A deny protects only the subnets that NACL is associated with. An ALB or NLB has a node in every AZ it uses, so every one of those subnets needs the rule.
  • Small. 20 inbound and 20 outbound rules per NACL by default, adjustable to at most 40 each, and AWS warns that network performance may suffer at that size. A NACL is a tool for a handful of addresses or ranges, not a blocklist of hundreds.

#Security groups: allow only

A security group has no Action column. Each rule allows a protocol and port from a source; whatever no rule allows is dropped. You can make the allow list narrower (only the office range, only the CloudFront prefix list, only the ALB's security group), but you can never write “everyone except 203.0.113.50”. A public site has to allow 0.0.0.0/0 on 443, and that includes the attacker.

#Design 1: an EC2 instance with a public IP

Slide p813: client → NACL → EC2 instance in a public subnet with a public IP. Nothing rewrites the address, so every layer sees the client's real IP, and three of them can act on it:

  • NACL deny (the main answer): rule 90 Deny 203.0.113.50/32, rule 100 Allow 0.0.0.0/0 TCP 443. The packet dies at the subnet boundary before the instance spends a cycle on it.
  • Security group: cannot deny (above).
  • Host firewall (optional on the slide): firewall software inside the operating system, iptables or nftables on Linux, Windows Defender Firewall on Windows. It works because the source address is intact, but the packet has already crossed the network and reached the instance, the rule lives on each server separately, and a replacement instance launches without it unless the AMI or user data adds it (lesson 4.3).

One EC2 instance with a public IP

A tea estate’s website runs on one EC2 instance in a public subnet. A scraper at 203.0.113.50 copies every price page. Three layers can stop it: the subnet’s NACL, the security group, and a firewall inside the operating system.

Scenario

Rule 90 denies the scraper before rule 100 allows everyone, so its packets die at the subnet edge.

VPC
Public subnet
Customer198.51.100.20
Scraper203.0.113.50
NACLsubnet edge
Web serverSG + host firewall
TCP 443

Packet at the NACL

Source IP

203.0.113.50

Destination

10.0.1.10:443

Step 1 of 4
1

The scraper sends a request to port 443. Before the packet reaches the instance it crosses the subnet boundary, where the network ACL reads its rules from the lowest number up.

#Design 2: behind an Application Load Balancer

Slide p814: client → NACL → ALB in public subnets → EC2 in private subnets. The ALB is a layer 7 proxy: it terminates the client's TCP and TLS connection, reads the HTTP request, and opens a new connection to the target from its own private IP (the slide's “connection termination”). The client's address reaches the target only inside the X-Forwarded-For header (lesson 6.3).

What follows for blocking:

LayerSource it seesCan block 203.0.113.50?
NACL of the ALB's subnetsClient IPYes: deny rule in every ALB subnet's NACL
ALB security groupClient IPNo: allow only
ALB listener rule source-ipClient IPYes: fixed-response 403 with your message
NACL of the targets' private subnetsThe ALB's private IPNo: the deny never matches
Target security groupThe ALB's private IP (or its security group)No
Host firewall on the targetThe ALB's private IPNo, unless the application itself reads X-Forwarded-For

So there are two good places, the slide's NACL and the ALB itself:

  • NACL on the ALB subnets. Silent (the client sees a timeout), free, and early: the packet never reaches the ALB. The exam's words: “block a specific IP address at the subnet level”, “deny traffic explicitly without additional cost”.
  • ALB listener rule. A rule with the condition source-ip = 203.0.113.50/32 (CIDR form) and the action fixed-response with status 403 and a body you choose. The client gets a real answer: “access denied, contact support”. The exam's words: “return a custom error message for a specific blocked IP”. Limits: five condition values per rule and 100 rules per ALB by default, and rule evaluations beyond the first 10 add to the ALB's capacity units (LCU) charge. A handful of addresses, not thousands.

The source-ip condition uses the address of the connection, not the X-Forwarded-For header. That is what makes it trustworthy here, and also what breaks it behind CloudFront (Design 5).

Blocking an IP behind an ALB

A university admission portal: an internet-facing ALB in public subnets, application servers in private subnets. The ALB terminates every connection, so the servers never see the visitor’s address.

Scenario

The ALB ends the client’s connection and opens a new one from its own private IP; the client’s address travels only in X-Forwarded-For.

VPC
Public
Private
Applicant198.51.100.20
Bot203.0.113.50
NACLALB subnets
ALB10.0.1.25
App serverprivate IP
HTTPS

Arriving at the ALB

Source IP

198.51.100.20

Step 1 of 3
1

An applicant connects to the portal. The NACL on the ALB’s subnets and the ALB itself both see the real source address, 198.51.100.20.

#Design 3: behind a Network Load Balancer

Slide p815: client → NACL → NLB → EC2. The NLB works at layer 4 (TCP, UDP, TLS) with very low latency. It does not read HTTP, so:

  • No listener rules with conditions: there is no source-ip rule, no fixed response.
  • No AWS WAF: WAF cannot be associated with an NLB (lesson 21.6).
  • Security groups since August 2023: optional and chosen at creation (lesson 6.3), and allow-only like every security group. They can turn the NLB into an allowlist of known partners; they cannot deny one address.

What the NLB does keep is the client's address. With instance targets, the target sees the real client IP; with IP targets over TCP or TLS, client IP preservation is off by default and the target sees the NLB's private IP unless you turn preservation on or use Proxy Protocol v2. Traffic arriving through PrivateLink always shows the NLB's address.

So:

  • NACL deny on the NLB's subnets is the exam answer: “block an IP for an NLB”, “block an IP for high-performance TCP traffic”, “layer 4 IP blocking”. Because the address is preserved, a deny in the targets' subnet NACL would also match, but the NLB subnet stops it earlier.
  • A host firewall on the targets works when the address is preserved (instance targets), and does nothing when it is not.
  • AWS Network Firewall, a managed stateful firewall inside the VPC, can also drop the address; it belongs to lesson 22.7.

Blocking an IP behind an NLB

A garments group’s ERP accepts TCP connections from buying houses through an NLB. One partner’s misconfigured system floods it from 203.0.113.50. The NLB passes packets through without reading HTTP.

Scenario

With instance targets the NLB keeps the client’s source address all the way to the server.

VPC
Public
Private
Buying house198.51.100.20
Faulty partner203.0.113.50
NACLNLB subnets
NLBlayer 4
ERP serverinstance target
TCP 5000

Arriving at the ERP server

Source IP

203.0.113.50

Step 1 of 2
1

The partner’s system opens a TCP connection on port 5000. The NLB does not terminate it: it forwards the packets to a target, keeping the source address.

#Design 4: ALB + WAF

Slide p816 adds AWS WAF to the ALB for “IP address filtering”. You create an IP set of bad addresses, reference it from a rule in a web ACL with the action Block, and associate the web ACL with the ALB (same Region). The ALB hands every request to WAF before routing it; a listed address gets 403 Forbidden (or a custom response) and never reaches a target. WAF on an ALB sees the client's real address, because it reads the connection the ALB received.

Why this is the modern default for a web application:

NeedNACLALB listener ruleWAF IP set
How many addresses20 rules by default, 40 at most5 values per rule, 100 rules10,000 per IP set, several sets per web ACL
Changing the listRenumber and edit rulesEdit rulesOne update-ip-set call; the rule does not change
SQL injection, XSSNoNoYes, AWS managed rule groups
Too many requests from one addressNoNoYes, rate-based rules block and release automatically
Answer the clientSilent drop (timeout)Custom fixed response403 or a custom response
CostFreePart of the ALB chargeWeb ACL, rules and requests inspected

Rules in a web ACL run in priority order (lowest first) and a Block stops the evaluation: a typical order is the IP set, then the rate-based rule, then the managed rule groups. The details of web ACLs, rule actions, managed groups and rate-based rules are in lesson 21.6; this lesson needs only the fact that the IP set scales and that the same web ACL adds protection a NACL cannot give.

ALB + WAF: an IP set that scales

An e-commerce API behind an ALB with a web ACL. Its scraper list has grown to 300 addresses, and new attackers keep arriving from addresses nobody has listed yet.

Scenario

A web ACL rule that references an IP set blocks every listed address with a 403.

VPC
Shopper198.51.100.20
Scrapers300 IPs
Web ACLon the ALB
ALBpublic subnets
API servers
GET /products

Request

Source IP

203.0.113.50

Step 1 of 3
1

A request arrives from 203.0.113.50. The ALB hands it to the web ACL before routing it. WAF reads the source address of the connection the ALB received, the real client IP.

#Design 5: ALB, CloudFront and WAF

Slide p817 puts CloudFront in front of the ALB. Every request now hits an edge location first. On a cache miss, CloudFront opens its own connection to the ALB from one of its origin-facing public IPs. That changes everything in the Region:

  • The NACL of the ALB's subnets sees CloudFront's addresses. A deny for 203.0.113.50 never matches, and denying a CloudFront address would block thousands of real users. The slide marks the NACL “NOT helpful”.
  • The ALB's source-ip listener rule fails the same way: the connection comes from CloudFront.
  • A WAF web ACL on the ALB also matches CloudFront's address by default. It can be told to read the client IP from the X-Forwarded-For header instead (the forwarded IP configuration of an IP set rule), but then the request has already crossed the edge and the Region, and the header is only trustworthy if nobody can reach the ALB except your distribution.

The client's address is visible only at the edge, so that is where it must be blocked:

  • AWS WAF on CloudFront: a web ACL with global (CloudFront) scope, created in us-east-1 together with its IP set, associated with the distribution. The listed address gets 403 from the edge location; nothing reaches the VPC, which saves load and cost and keeps attack traffic far from the origin. This is the notes' best practice: attach WAF to CloudFront, not the ALB.
  • CloudFront geo restriction: an allow list or block list of countries, free and built in, answered with 403 at the edge (lesson 11.2). It cannot single out one address; for that, or for a country only on /admin, use WAF.
  • A CloudFront Function can also read the viewer's address and refuse it (lesson 11.3), but WAF is the managed answer the exam expects.

#Closing the side door: lock the origin

Blocking at the edge is worthless if the attacker can skip the edge. A public ALB has a public DNS name, and a blocked scraper will try it. Two layers close the door (lesson 11.2 builds them step by step):

  1. ALB security group allows only CloudFront: one inbound rule that references the AWS managed prefix list com.amazonaws.global.cloudfront.origin-facing on port 443. Direct connections from any other address are dropped. Here the allow-only security group is exactly the right tool, because you are allowing a known list, not denying one address. The prefix list counts as 55 rules toward the security group's quota.
  2. A secret custom header: your distribution adds an origin header such as X-Origin-Verify: <long random value>; the ALB's listener rule forwards only requests carrying that value, and the default rule returns 403. This stops an attacker who creates his own CloudFront distribution pointing at your ALB: his requests come from CloudFront addresses too and pass the prefix list, but they do not carry your secret. Rotate the value from time to time, and keep it out of logs and code repositories.

CloudFront in front: block at the edge

The exam-results site sits behind CloudFront, with a public ALB as origin. Every request now reaches the VPC from a CloudFront address, so the client’s IP has to be judged at the edge.

Scenario

The NACL denies 203.0.113.50, but packets arrive from CloudFront’s addresses, so the deny never matches.

VPC
Public
Student198.51.100.20
Scraper203.0.113.50
CloudFrontwith WAF
Other distributionattacker’s
NACLdeny 203.0.113.50
ALBpublic origin
GET /result

At the edge

Source IP

203.0.113.50

Step 1 of 3
1

The admin copies the old habit: NACL rule 90 denies 203.0.113.50/32. The scraper requests results through CloudFront, as every visitor does.

#Who sees the real client IP?

HopEC2 onlyBehind ALBBehind NLBBehind CloudFront + ALB
CloudFront, WAF on CloudFront, geo restriction–––Client
NACL in front of the first AWS hopClientClientClientCloudFront
Security group of the first hopClientClient (ALB SG)Client (NLB SG)CloudFront
ALB listener rule, WAF on the ALB–Client– (not supported)CloudFront (WAF can read X-Forwarded-For)
Target (instance, its SG, its NACL, host firewall)ClientALB's private IPClient with instance targets; NLB's IP with IP targets unless preservation or Proxy Protocol v2ALB's private IP
Application codeClientX-Forwarded-For (right-most entry)Client (or Proxy Protocol v2 header)X-Forwarded-For (client, then CloudFront's address)

Read it as: block at the first hop that sees the client, as early as possible, with a tool that scales to the size of the list.

Now try it yourself. Pick a design and a control, and see whether the block works, cannot exist, or silently does nothing.

Where can I block 203.0.113.50?

Choose an architecture and a control, then try to block the scraper. The answer depends on which address that control actually sees.

Architecture

Control

Pick an architecture and a control, then press the button.

#What goes wrong

  • The deny is in the NACL but the attacker still gets in: the deny's number is higher than an allow that matches first. Renumber it below the allow (90 before 100).
  • After editing the NACL, everybody times out: the NACL is stateless and a rule for the outbound ephemeral ports (1024–65535) was removed or never added.
  • The block works only some of the time: the ALB or NLB spans several subnets with different NACLs, and only one got the deny. Use one NACL for all of the load balancer's subnets, or add the rule to each.
  • A deny on the application servers' subnet does nothing: the servers are behind an ALB and see its private IP. Block at the ALB's subnets, the ALB, or WAF.
  • Looking for “deny” in a security group: it does not exist. Use a NACL, a listener rule or WAF.
  • Ran out of NACL rules: 20 by default, 40 at most. Move the list to a WAF IP set.
  • Looking for “Associate web ACL” on an NLB: WAF does not support NLBs. Use a NACL, or put an ALB or CloudFront in front if the traffic is HTTP.
  • Host firewall on NLB targets matches nothing: IP targets without client IP preservation see the NLB's address. Turn preservation on or read Proxy Protocol v2.
  • The application blocks by X-Forwarded-For and a bot walks past: the code trusts the left-most entry, which the client can fake. Trust the right-most entry from your own proxy.
  • NACL or ALB rule behind CloudFront does nothing: they see CloudFront's addresses. Block in a CloudFront web ACL.
  • The CloudFront web ACL cannot be found when associating: it was created in the ALB's Region; CloudFront web ACLs and their IP sets live in us-east-1 (global scope).
  • WAF on CloudFront, but the scraper still gets data: the ALB is open to the internet. Restrict its security group to the CloudFront prefix list, require the secret header, or move to a VPC origin.
  • The IPv4 block works, the attacker returns over IPv6: a dual-stack site needs the IPv6 address in an IPv6 IP set (IP sets hold one address version) or an IPv6 NACL rule too.

#Blocking IPs in system design

Blocking one address is rarely the whole design. The patterns that come back:

  • Block at the outermost layer that sees the client: the edge for CloudFront sites, the load balancer or its subnets for regional ones. Every hop later costs more and sees less.
  • Use the tool that fits the list: a NACL for a few addresses at no cost, an ALB rule when the client must get a message, a WAF IP set for long or changing lists. Prefer CIDR ranges to single addresses when an attacker hops within a provider's block.
  • IP lists are not enough on their own: attackers change addresses. Combine the IP set with rate-based rules, the IP reputation and anonymous IP managed rule groups, and managed SQL injection and XSS rules (lesson 21.6).
  • Automate the list: detection services can feed it. A common pattern is a GuardDuty finding (lesson 21.7) or a CloudWatch alarm on WAF logs, matched by an EventBridge rule (lesson 19.5), invoking a Lambda function that adds the address to the WAF IP set (or a NACL entry) and removes it after a day.
  • Many accounts: Firewall Manager pushes the same WAF rules, security group policies and network ACL baselines to every account of an Organization (lesson 21.6).
  • Non-HTTP traffic inside the VPC that needs more than a NACL (stateful rules, domain lists, intrusion prevention): AWS Network Firewall, lesson 22.7.
  • Lock every origin: prefix list + secret header for a public ALB, OAC for S3, VPC origins for a private one. An edge block with an open origin is a door with no wall around it.

#Try it yourself

These commands use the AWS CLI v2 with made-up IDs. NACL and security group changes are free; WAF web ACLs, rules and inspected requests cost money, so delete what you create.

# Design 1-3: NACL deny numbered BEFORE the allow (repeat for the NACL of every load balancer subnet)
aws ec2 describe-network-acls --network-acl-ids acl-0a1b2c3d4e5f67890 \
  --query 'NetworkAcls[0].Entries[?Egress==`false`].[RuleNumber,CidrBlock,RuleAction,PortRange.From]' --output text
# 100     0.0.0.0/0          allow   443
# 32767   0.0.0.0/0          deny    None
aws ec2 create-network-acl-entry --network-acl-id acl-0a1b2c3d4e5f67890 \
  --ingress --rule-number 90 --protocol -1 --cidr-block 203.0.113.50/32 --rule-action deny

# From the blocked address: a silent drop looks like a timeout
curl -m 5 -s -o /dev/null -w "%{http_code}\n" https://portal.example.com/
# 000   (curl gave up after 5 seconds: no answer at all)

# Security groups have no deny: this fails (there is no --rule-action for security groups)
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 \
  --ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=0.0.0.0/0}]'
# Only allow rules exist. To "block", you can only remove 0.0.0.0/0 and allow a narrower list.
# Design 2: ALB listener rule with a custom 403 for one address
aws elbv2 create-rule \
  --listener-arn arn:aws:elasticloadbalancing:ap-south-1:111122223333:listener/app/portal-alb/50dc6c495c0c9188/f2f7dc8efc522ab2 \
  --priority 1 \
  --conditions Field=source-ip,SourceIpConfig='{Values=["203.0.113.50/32"]}' \
  --actions Type=fixed-response,FixedResponseConfig='{StatusCode=403,ContentType=text/plain,MessageBody="Automated access is not allowed. Contact admission@example.com"}'

curl -s -w "\n%{http_code}\n" https://portal.example.com/seats   # from 203.0.113.50
# Automated access is not allowed. Contact admission@example.com
# 403
# Design 3: an NLB target group with IP targets - is the client IP preserved?
aws elbv2 describe-target-group-attributes \
  --target-group-arn arn:aws:elasticloadbalancing:ap-south-1:111122223333:targetgroup/erp-ip-tg/73e2d6bc24d8a067 \
  --query 'Attributes[?Key==`preserve_client_ip.enabled` || Key==`proxy_protocol_v2.enabled`]' --output text
# preserve_client_ip.enabled   false
# proxy_protocol_v2.enabled    false
# Design 4: a regional IP set for the ALB, then add more addresses later without touching the rule
aws wafv2 create-ip-set --name scrapers --scope REGIONAL --region ap-south-1 \
  --ip-address-version IPV4 --addresses 203.0.113.50/32 198.51.100.128/25
# { "Summary": { "Name": "scrapers", "Id": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111", "LockToken": "0f1e2d3c-EXAMPLE", ... } }
aws wafv2 get-ip-set --name scrapers --scope REGIONAL --region ap-south-1 \
  --id a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --query LockToken --output text
# 0f1e2d3c-EXAMPLE
aws wafv2 update-ip-set --name scrapers --scope REGIONAL --region ap-south-1 \
  --id a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --lock-token 0f1e2d3c-EXAMPLE \
  --addresses 203.0.113.50/32 198.51.100.128/25 192.0.2.77/32
# update-ip-set REPLACES the whole list: always send every address you want to keep.
# Design 5: the web ACL for CloudFront lives in us-east-1 with scope CLOUDFRONT
aws wafv2 create-ip-set --name scrapers-edge --scope CLOUDFRONT --region us-east-1 \
  --ip-address-version IPV4 --addresses 203.0.113.50/32
aws wafv2 create-web-acl --name results-edge --scope CLOUDFRONT --region us-east-1 \
  --default-action Allow={} --rules file://edge-rules.json \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=results-edge
# The web ACL is attached by setting WebACLId (its ARN) in the distribution config (update-distribution).

# Lock the ALB: find the CloudFront origin-facing prefix list and allow only it on 443
aws ec2 describe-managed-prefix-lists \
  --filters Name=prefix-list-name,Values=com.amazonaws.global.cloudfront.origin-facing \
  --query 'PrefixLists[].[PrefixListId,PrefixListName,MaxEntries]' --output text
# pl-3b927c52   com.amazonaws.global.cloudfront.origin-facing   55
aws ec2 revoke-security-group-ingress --group-id sg-0alb1234567890abc \
  --ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=0.0.0.0/0}]'
aws ec2 authorize-security-group-ingress --group-id sg-0alb1234567890abc \
  --ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,PrefixListIds=[{PrefixListId=pl-3b927c52}]'

# Secret header: forward only when it matches, make the default action a 403
aws elbv2 create-rule --listener-arn arn:aws:elasticloadbalancing:ap-south-1:111122223333:listener/app/results-alb/6d0ecf831eec9f09/0f1a2b3c4d5e6f70 \
  --priority 1 \
  --conditions 'Field=http-header,HttpHeaderConfig={HttpHeaderName=X-Origin-Verify,Values=[EXAMPLE-long-random-value]}' \
  --actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:ap-south-1:111122223333:targetgroup/results-tg/943f017f100becff
aws elbv2 modify-listener --listener-arn arn:aws:elasticloadbalancing:ap-south-1:111122223333:listener/app/results-alb/6d0ecf831eec9f09/0f1a2b3c4d5e6f70 \
  --default-actions Type=fixed-response,FixedResponseConfig='{StatusCode=403,ContentType=text/plain,MessageBody=Forbidden}'

# Test: through CloudFront from the scraper, then straight at the ALB
curl -s -o /dev/null -w "%{http_code}\n" https://results.example.com/result?roll=482913   # from 203.0.113.50
# 403   (blocked at the edge by the web ACL)
curl -m 5 -s -o /dev/null -w "%{http_code}\n" https://results-alb-1234567890.ap-south-1.elb.amazonaws.com/
# 000   (dropped by the security group: not a CloudFront address)

edge-rules.json holds one rule with an IPSetReferenceStatement pointing at the scrapers-edge ARN and "Action": { "Block": {} }, as in lesson 21.6. Clean up with delete-network-acl-entry, delete-rule, delete-web-acl and delete-ip-set.

#Summary

Key takeaways

  • Block at the first hop that sees the client's address. Proxies (ALB, CloudFront) end the connection and hide the client from every layer behind them; the NLB (instance targets) passes it through.
  • Security groups only allow: never the answer to “deny one IP”. They suit allowlists (known partners, the CloudFront prefix list).
  • NACL: allow and deny, lowest number first (deny before the allow), stateless (outbound ephemeral ports), on every subnet of the load balancer, 20 rules per direction (max 40), free. Exam: “subnet level”, “no additional cost”, “NLB”, “layer 4”.
  • EC2 with a public IP (p813): NACL deny; optional host firewall (works, but per instance and after the packet arrives).
  • ALB (p814): NACL on the ALB's subnets, or a source-ip listener rule → fixed-response 403 for a custom message (5 values per rule). Targets see the ALB's private IP; the client is in X-Forwarded-For (trust the right-most entry).
  • NLB (p815): NACL is the exam answer; no WAF, no listener rules; security groups (since 2023) still allow-only; client IP preserved for instance targets (IP targets need preservation or Proxy Protocol v2).
  • ALB + WAF (p816): IP set (10,000 entries) in a web ACL rule with Block; plus managed SQLi/XSS rules and rate-based rules. Exam: “block IPs and SQL injection/XSS”, “too many requests”.
  • CloudFront + ALB + WAF (p817): the NACL and ALB rules see CloudFront's IPs (“not helpful”). Block with WAF on CloudFront (created in us-east-1) or geo restriction (countries). Lock the origin: ALB SG allows only com.amazonaws.global.cloudfront.origin-facing, plus a secret header checked by a listener rule; or a VPC origin (2024) with an internal ALB.