Filter concepts by levelShowing all levels.

AWS · Section 36

WAF and Edge Security

Level
intermediate
Read
25 min
Concepts
3

AWS WAF inspects HTTP(S) requests before they reach your application. A web ACL holds rules — each with inspection criteria and an action of Allow, Block, Count, CAPTCHA, or Challenge — plus one default action for requests no rule matched, and is associated with a protected resource such as a CloudFront distribution, an Application Load Balancer, or an API Gateway REST API. Rules can live directly in the web ACL or in reusable rule groups, including AWS Managed Rules, which should always be rolled out in Count mode first and then relaxed rule by rule. On top of the signature rules sit the aggregate controls: IP sets for known addresses, rate-based rules that count requests per aggregation key (a header or cookie, not only the source IP), and Bot Control labels for automated traffic. WAF logging is what makes any of it debuggable, because a blocked request never reaches your application logs at all. Underneath both sits AWS Shield: Standard is automatic and free for common layer 3/4 floods, Advanced is a paid subscription adding deeper layer 7 mitigation — but a layer 7 flood is made of valid requests, so the real control there is still an AWS WAF rate-based rule at the edge.

What is true here

  1. A web ACL = rules with actions plus one default action; Allow and Block terminate evaluation, Count does not.
  2. Managed rule groups go out in Count mode first, then per-rule overrides — never straight into Block on production traffic.
  3. Rate-based rules act on volume per aggregation key; keying on a header or cookie beats keying on IP for shared-address clients.
  4. Enable WAF logging before the first rule blocks anything — the WAF log is the only record of a refused request.
  5. Shield Standard is automatic and free; layer 7 floods are shaped by AWS WAF, not by Shield alone.

What you will be able to do

  • Build a web ACL with rules, a default action, and a managed rule group, and attach it to the right resource
  • Roll a managed rule group out safely using Count mode and per-rule overrides
  • Choose between an IP set, a rate-based rule, and a Bot Control label for a given abuse pattern, and pick the right aggregation key
  • Explain what Shield Standard covers, when Shield Advanced is justified, and why a layer 7 flood still needs AWS WAF
From a web ACL to a DDoS-resistant edge
extended bysits ontop of

Web ACLs, rules, rule groups

IP sets, rate limits, bot control, logging

Shield — DDoS underneath it all

  • Web ACLs, rules, rule groups
    • leads to IP sets, rate limits, bot control, logging (extended by)
  • IP sets, rate limits, bot control, logging
    • leads to Shield — DDoS underneath it all (sits on top of)
  • Shield — DDoS underneath it all

WAF and Edge Security

The web ACL object model, the aggregate controls and logging built on it, and the DDoS protection underneath.

Web ACLs, Rules, and Rule Groups

coreintermediate

AWS WAF inspects HTTP(S) requests before they reach your application. You write a web ACL — a list of rules, each with inspection criteria and an action — and associate it with a resource such as a CloudFront distribution, an Application Load Balancer, or an API Gateway REST API. That resource forwards each request to AWS WAF first, and the web ACL decides whether the request goes through.

Think of it as

A web ACL is a bouncer's checklist read top to bottom. Each rule is one line on the list: "if the request looks like this, do that". The default action is what the bouncer does with anyone who reached the bottom without matching anything — and it is a setting, not a guess.

What we're doing: Add the AWS Managed Rules common rule set to an ALB without breaking a legitimate upload endpoint.

rollout-in-count-mode.txttext
Step 1 — add AWSManagedRulesCommonRuleSet with every rule overridden
        to Count. Nothing is blocked yet.

Step 2 — read the WAF logs for a week. SizeRestrictions_BODY matches
        1,900 requests, all of them POST /api/documents (real uploads).

Step 3 — override just SizeRestrictions_BODY to Count, leave the rest of
        the group at its default action, then remove the group-wide override.
2
Count is the safe first position: the rule still evaluates and still logs its matches, but no real traffic is refused while you learn what it catches.
6
A per-rule override keeps the other rules in the managed group active. Disabling the whole group because one rule was noisy is how a managed rule set quietly stops protecting anything.

Why this works: A managed rule group is written for the general case, and your application is not the general case. Rolling out in Count mode turns "will this break production" from a guess into a measurement, and per-rule overrides keep the blast radius of a false positive to one rule instead of the whole group.

Enabling a managed rule group straight into Block on production traffic

Wrong

text
# Add AWSManagedRulesCommonRuleSet at its default actions and ship it

Better

text
# Add it with a group-wide Count override, read the logs, then remove the
# override rule by rule

What you see: Legitimate requests start returning 403 from the edge, with nothing in the application logs at all — the request never reached the application, so the only trace is in the WAF logs.

Why: A blocked request is refused before your application sees it, so ordinary application logging shows silence rather than an error. Without a Count-mode period first, the first evidence of a false positive is a customer report.

A request through a web ACL
arrives atforwarded forinspectionevaluates toallowedrequests only

Client request

Protected resource

CloudFront / ALB / API Gateway

Web ACL

rules in priority order

Allow / Block / Count / CAPTCHA

first terminating match wins

Your application

  • Client request
    • leads to Protected resource (arrives at)
  • Protected resource — CloudFront / ALB / API Gateway
    • leads to Web ACL (forwarded for inspection)
  • Web ACL — rules in priority order
    • leads to Allow / Block / Count / CAPTCHA (evaluates to)
  • Allow / Block / Count / CAPTCHA — first terminating match wins
    • leads to Your application (allowed requests only)
  • Your application

Rule actions and what they do to evaluation

Rule actions and what they do to evaluation
ActionEffect on the requestEffect on remaining rules
AllowSent on to the protected resourceTerminating — no further rules run
BlockRejected, by default with HTTP 403 or a custom responseTerminating — no further rules run
CountNothing; the match is only talliedNon-terminating — evaluation continues
CAPTCHAA puzzle is served unless a valid, unexpired token is presentContinues when the token is valid; otherwise terminates with the CAPTCHA response
ChallengeA silent browser check is run unless a valid token is presentContinues when the token is valid; otherwise terminates with the challenge

Together

text
# A CloudFront-scoped web ACL must be created against us-east-1
aws wafv2 create-web-acl --scope=CLOUDFRONT --region=us-east-1 \
  --name public-site --default-action Allow={} \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=publicSite \
  --rules file://rules.json

Remember: A web ACL = rules (each with criteria + an action) plus one default action, attached to a protected resource. Allow and Block are terminating; Count only tallies. Rule groups make rules reusable — AWS Managed Rules is the usual starting point. CloudFront-scoped web ACLs live in us-east-1.

See also: rate limiting bot control and waf logging · shield and ddos protection · cloudfront core vocabulary

IP Sets, Rate-Based Rules, Bot Control, and Logging

coreintermediate

Signature rules catch requests that look malicious. The rules in this concept catch requests that are individually fine but wrong in aggregate — too many from one address, or coming from an automated client pretending to be a browser. IP sets match known addresses, rate-based rules count requests per key over a time window, and Bot Control identifies and labels automated traffic. WAF logging is what tells you which of them fired and on what.

Think of it as

A signature rule asks "is this request malformed?". A rate-based rule asks "how many of these has this client sent?". Bot Control asks "is there a human behind this at all?". Three different questions, and a request that passes all the signature checks can still fail the other two.

What we're doing: Stop credential stuffing against a login endpoint without locking out a customer's office network.

login-rate-limit.txttext
Rule 10: rate-based, scope-down statement = URI path is /login,
         aggregation key = source IP, limit = 100 per 5 minutes,
         action = Challenge (not Block)

Legit office behind one NAT address: 40 logins in 5 min -> under the
limit, nothing happens.

Attacker replaying a credential list: 4,000 attempts -> over the limit,
each further request gets a silent browser challenge, which the script
cannot answer.
1
The scope-down statement keeps the rule from counting all traffic — only requests to /login contribute to the rate.
5
The limit has to survive the largest legitimate client sharing one address. Rate limits set from average traffic block a customer's office, not the attacker.
8
Challenge degrades rather than refuses: a real browser answers it transparently, a script does not. Block would also refuse every human behind that address.

Why this works: A rate-based rule is the only WAF control that can act on volume, and picking the aggregation key is the whole design. Keying on the source IP is right when the abuse is per-machine and wrong when many real users share one address — which is why a header or cookie key is often the better choice.

Setting a rate limit from average traffic instead of peak legitimate traffic

Wrong

text
# Average is 20 requests/min per IP, so set the limit to 50

Better

text
# Deploy the rule in Count mode, read the WAF logs for the real peak per
# key, then set a limit above it

What you see: Real users behind a corporate NAT or a mobile carrier gateway hit the limit during normal use, and the failures look like intermittent 403s that nobody can reproduce.

Why: Averages hide the shape of the traffic. One address can legitimately carry an entire office or an entire mobile network segment, so a limit derived from the mean will be crossed by ordinary users before it is ever crossed by an attacker who spreads across addresses.

Which control answers which abuse pattern

Which control answers which abuse pattern
PatternControlWhy the others do not fit
A known bad address rangeIP set referenced by a Block ruleA rate rule would only act after the abuse volume arrives
Credential stuffing on POST /loginRate-based rule scoped to that URIEach individual request is a valid login attempt
One tenant exhausting a shared APIRate-based rule keyed on the API-key headerKeying on IP groups a whole office behind one NAT address
A scraper imitating ChromeBot Control rule group, acting on its labelsThe requests are well-formed and come from many addresses
Automated traffic with no session stateChallenge actionBlocking outright also refuses legitimate clients from that network

Together

text
# A rate-based rule keyed on a header rather than the source IP
{
  "Name": "PerApiKeyLimit",
  "Priority": 10,
  "Action": { "Block": {} },
  "Statement": {
    "RateBasedStatement": {
      "Limit": 2000,
      "AggregateKeyType": "CUSTOM_KEYS",
      "CustomKeys": [{ "Header": { "Name": "x-api-key",
        "TextTransformations": [{ "Priority": 0, "Type": "NONE" }] } }]
    }
  }
}

Remember: IP sets match known addresses; rate-based rules act on volume per aggregation key (which does not have to be the IP); Bot Control labels automated traffic so other rules can act on it. Enable WAF logging first — a blocked request leaves no trace in your application logs.

See also: web acls rules and rule groups · shield and ddos protection

DDoS Protection and the Role of Shield

standardintermediate

A DDoS attack floods a target from many compromised systems so real users cannot get through. AWS Shield defends against that, in two tiers: Shield Standard is on automatically for every AWS customer at no extra charge, and Shield Advanced is a paid subscription adding deeper application-layer protection and support. Shield handles the flood; AWS WAF is what expresses the application-specific rules underneath it.

Think of it as

Shield is the flood barrier around the building; AWS WAF is the door policy inside it. A barrier stops the water from reaching the door at all, but it has no opinion about who should be let in — and no door policy survives being underwater.

text
# The layered shape of a DDoS-resistant public entry point
Route 53  ->  CloudFront (+ web ACL: managed rules, rate-based rules)
          ->  ALB in private subnets
          ->  application
What defends against what

Layer 3 — volumetric flood

Saturates network capacity · absorbed by Shield

Layer 4 — protocol abuse

TCP SYN flood exhausting connection state · absorbed by Shield

Layer 7 — request flood

Individually valid HTTP requests · shaped by AWS WAF rate-based rules

Application logic

Your handlers, your database — the thing being protected

  1. Layer 3 — volumetric flood — Saturates network capacity · absorbed by Shield
  2. Layer 4 — protocol abuse — TCP SYN flood exhausting connection state · absorbed by Shield
  3. Layer 7 — request flood — Individually valid HTTP requests · shaped by AWS WAF rate-based rules
  4. Application logic — Your handlers, your database — the thing being protected

Assuming Shield covers an application-layer flood without any AWS WAF rules

Wrong

text
# "Shield is on by default, so a request flood is handled."

Better

text
# Put a web ACL with rate-based rules on the edge resource, and consider
# Shield Advanced for public workloads where downtime has a direct cost

What you see: The network never saturates, but the application tips over anyway: every request is a valid HTTP request, they all reach the origin, and the database connection pool is exhausted long before any bandwidth limit is reached.

Why: A layer 7 flood is made of requests that are indistinguishable from legitimate traffic at the packet level. The defense has to be expressed in terms of the application — a rate limit per key, a challenge, a scoped-down URI — which is exactly what AWS WAF provides and what a purely volumetric defense cannot.

Shield Standard vs Shield Advanced

Shield Standard vs Shield Advanced
AspectShield StandardShield Advanced
How you get itAutomatic for every AWS customerPaid subscription you opt into
CostNo extra chargeA monthly subscription plus data transfer
CoverageCommon layer 3 and 4 attacksAdds deeper detection and mitigation, including layer 7 for protected resources
SupportOrdinary AWS supportAccess to the AWS Shield Response Team and attack diagnostics
Typical fitEvery workload, by defaultPublic workloads where an outage has direct revenue or safety cost

Together

text
# Shield Advanced is a subscription, then per-resource protections
aws shield describe-subscription
aws shield list-protections

Remember: Shield Standard is automatic and free and handles common layer 3/4 floods. Shield Advanced is a paid subscription with deeper layer 7 protection and response-team access. A layer 7 flood is valid requests, so the actual control is an AWS WAF rate-based rule at the edge.

See also: rate limiting bot control and waf logging · security services landscape

Advertisement