Lab 08 — Edge protection (WAF on an ALB)¶
In one sentence
Put a web app behind an ALB, protect it with an AWS WAF web ACL, trigger each rule type yourself — IP set, custom path rule, managed rules, a managed group in Count mode and a rate-based rule — then find every decision in the WAF logs.
The idea¶
your laptop (MY_IP) ──HTTP:80──► sec8-alb (internet-facing, 2 AZs, SG: port 80 from MY_IP only)
│ ▲
│ └── sec8-web-acl (REGIONAL), evaluated in priority order:
│ 0 block-ip-set IP set sec8-blocked-ips → Block
│ 1 block-admin-path URI starts with /admin → Block
│ 2 aws-common AWSManagedRulesCommonRuleSet → Block
│ 3 aws-sqli-count AWSManagedRulesSQLiRuleSet → Count only
│ 4 rate-limit > 10 req / 60 s per IP → Block
│ default action: Allow
▼ logs → CloudWatch Logs aws-waf-logs-sec8
target group sec8-tg ──► Lambda sec8-app (no EC2 needed)
What to expect when you run it¶
| # | Test | Expected | Rule |
|---|---|---|---|
| 1 | Normal page | ✅ 200 | default Allow |
| 2 | /admin/users |
❌ 403 | block-admin-path |
| 3 | /ADMIN (upper case) |
❌ 403 | LOWERCASE text transformation |
| 4 | <script>alert(1)</script> in a query arg |
❌ 403 | aws-common CrossSiteScripting_QUERYARGUMENTS |
| 5 | No User-Agent header | ❌ 403 | aws-common NoUserAgent_HEADER |
| 6 | id=1' OR '1'='1 |
⚠️ 200 (!) | aws-sqli-count — counts only |
| 7 | Own IP added to the IP set | ❌ 403, back to 200 after removing it | block-ip-set (updates need a LockToken) |
| 8 | 60 requests in 60 s | ⚠️ more than 10 × 200 first, then 403; allowed again once the window drops below the limit | rate-limit (detection has a short delay) |
In the logs: blocked requests carry terminatingRuleId; the SQLi request shows "action":"ALLOW" with a
COUNT match inside ruleGroupList — exactly what it would have blocked. Sampled requests are kept
3 hours without logging.
Key lessons¶
- Priority order, first terminating action wins. Allow / Block / CAPTCHA / Challenge stop evaluation; Count records and continues; the default action applies last.
- Roll out managed groups in Count first, read the logs, then switch the override back to the group's own actions.
- Text transformations matter. Without LOWERCASE,
/ADMINwalks past a/adminrule. - SG = layer 3/4 (who can connect), WAF = layer 7 (what the request contains).
Exam notes¶
- WAF attaches to ALB, CloudFront, API Gateway (REST), AppSync, Cognito user pools, App Runner, Verified Access — not NLB or EC2 directly.
- Scope
REGIONALvsCLOUDFRONT; a CloudFront web ACL must be created in us-east-1. - WCU limit 1,500 per web ACL by default (more costs extra).
- Logs → CloudWatch Logs, S3 or Firehose; name must start with
aws-waf-logs-. Redact fields likeAuthorization/ cookies. - Managed groups: CommonRuleSet (OWASP), KnownBadInputs, SQLi, Linux/Windows/PHP, AmazonIpReputationList, AnonymousIpList (VPN/Tor/hosting); paid: Bot Control, ATP (account takeover), ACFP (fake account creation).
- Rate-based rules: 1/2/5/10-min windows, min limit 10; aggregate by IP, forwarded IP (
X-Forwarded-For, spoofable), header, cookie, query arg; scope-down statement (e.g. only/login). - Shield Standard: free, automatic, L3/4. Shield Advanced: $3,000/month per org, 1-year commitment; SRT 24/7 (needs Business/Enterprise support), DDoS cost protection, automatic application-layer mitigation, WAF included for protected resources; protects EIPs, NLB, ALB, CloudFront, Route 53, Global Accelerator.
- Best DDoS architecture: CloudFront + Route 53 at the edge, WAF on CloudFront, origin only reachable from CloudFront (OAC for S3; for ALB: CloudFront prefix list in the SG + secret header).
- Firewall Manager: central WAF/Shield/SG/Network Firewall policies across the org (needs Config + Organizations); new accounts covered automatically. Network Firewall: stateful L3–L7 VPC firewall (Suricata rules, domain lists) for traffic not going through ALB/CloudFront.
Review questions¶
Question 1
Your API is attacked by a credential-stuffing bot hitting POST /login from thousands of IPs, a few requests each. Will a plain rate-based rule (limit 100 per IP) help? What would?
Show answer
No — each IP stays far below 100, so a per-IP rate rule never triggers. Use the ATP (Account
Takeover Prevention) managed group on the login path (it checks stolen-credential lists and failed
login patterns), plus Bot Control and CAPTCHA/Challenge actions; a rate rule with a scope-down
on /login and a low limit, or aggregated on another key, adds a further layer.
Question 2
You want to deploy the SQLi managed rule group in production without risking false positives. How, and where do you check what it would have blocked?
Show answer
Add the group with its rule actions overridden to Count. Requests are still allowed, but matches are
recorded: check the WAF logs (the COUNT entry in ruleGroupList / nonTerminatingMatchingRules),
CloudWatch metrics per rule and sampled requests. Once you are sure it would only block bad traffic, remove
the override so the group's Block actions apply.
Question 3
A web ACL is in us-east-2 but you can't select your CloudFront distribution. Why?
Show answer
CloudFront is global, so it needs a web ACL with scope CLOUDFRONT, which must be created in
us-east-1. A REGIONAL web ACL in us-east-2 can only protect regional resources there (ALB, API
Gateway, AppSync, Cognito…).
Question 4
Which Shield Advanced feature reimburses you for Auto Scaling/CloudFront charges caused by a DDoS? What else do you need to engage the Shield Response Team?
Show answer
DDoS cost protection (service credits for scaling charges from an attack on a protected resource). To use the SRT you need a Business or Enterprise Support plan, and you grant the SRT an IAM role so it can view and update your WAF/Shield configuration (proactive engagement is an optional extra).
Question 5
The ALB must only accept traffic that came through CloudFront. Name two controls.
Show answer
(1) Allow inbound on the ALB security group only from the CloudFront managed prefix list
(com.amazonaws.global.cloudfront.origin-facing). (2) Have CloudFront add a secret custom header and
only forward requests carrying it — via a WAF rule or an ALB listener rule (rotate the secret).
The prefix list alone isn't enough: anyone's CloudFront distribution uses the same IPs.