AWS WAF
Layer 7 firewall. WAF is a global service.
Architecture
The configuration unit is the Web ACL.
A Web ACL can be put in fron of:
-
CloudFront distrubution (the only global)
-
ALB
-
AppSync GraphQL API
-
API Gateway REST API
-
Cognito User Pools
-
App Runner service
-
Verified Access instance
As well as manually manage rules you can update WAF rules in real time using EventBridge.
Web ACL
Web ACLs can protect both regional ad global services, Web ACLs can be reused for protecting other resources but ACLs created for regional services cannot be reused for global ones.
Web ACLs can be associated with multiple resources, but a resource can only have a single Web ACL at a time. If you associate a Web ACL with a resource that’s already associated with a Web ACL, the latter association will be discarded.
Web ACLs contain Rule Groups, which are a collection of Rules, or standalone rules. Rules are processed in order, which can be changed, but this needs to be done carefully.
For example rules can attach labels and other rules may require attached labels to match traffic.
Web ACLs come with a limited compute capacity (default 1.500 WCU, max 5000 with additional charges and support ticket) and rules consume it, so you can’t add as many rules as you want, each rule has a compute cost.
Their starting point is a default action:
-
Allow if you want to accept traffic by default
-
Deny if you want only allow some traffic
Rule Groups
They’re useful to group common purpose rules. They provide the total WCUs of the rules inside them.
Rule groups can be:
-
AWS Managed: they cover a lot of cases and you can also override rule actions, for example
Countinstead of the defaultBlock.-
Free
-
Paid: account creation fraud prevention, account takeover prevention, bot control
-
-
Customer Managed
-
from Marketplace, generally under a subscription.
-
Service owned like Shield or Firewall Manager.
Rules
Rules have a type, one or more statements and an action
Statements decide if the rule matches, and you can have:
-
A single statement:
if (statement) then (action) -
Multiple statements:
-
AND: all the statements must be true.
if (statement1 AND statement2 (AND …) ) then {action} -
OR: at least one statement must be true.
if (statement1 OR statement2 (OR …) ) then {action} -
NOT: the statement must be false.
if !(statement) then {action}
-
Rule Types
-
Regular: they match is something occurs, for example you can allow connections from a source range.
-
Rate-Based: they match if something occurs at a certain rate, for example you can block traffic if connection attempts are too frequent in a certain period.
Rule Statements
What needs to happen for a rule to match.
For Regular Rules you can select based on:
-
Client’s country
-
Wheather the Source IP Address is contained in a defined IP Set. In particular, you can extract the IP address from:
-
the request Source IP Address
-
the IP address in a Header, like
X-Forwarded-For. You can specify the position if the header contains a list (first, last, any of). If there’s no match you can choose wheather to consider this a match or not.
-
-
A Label
-
The Request Content:
-
Headers (one or more)
-
Header Order
-
Query Parameters (one or more)
-
URI Path
-
Query String
-
Body: 2 built-in attack match conditions are present for XSS and SQL Injections.
-
Default body inspection limit: 16 KiB
-
Maximum body inspection limit: 64 KiB (additional charges apply)
-
-
HTTP Method
-
J3A Fingerprint
-
For Rate-based rules you have:
-
A Rate limit (rate threshold): the maximum numbero of requests before the action kicks in.
-
An Evaluation period
-
An Aggregation criterion: which requests for each group should increase the counter.
-
Source IP Address
-
IP Address in a specific header
-
Custom key:
-
Header
-
Query String
-
Query Argument
-
Cookie
-
Label Namespace
-
HTTP Method
-
URI Path
-
-
Custom Statements: all that apply for a Regular rule type, including the ability to use multiple statements in AND and OR, and to negate using NOT.
For instance, I could limit to 10 RPS requests coming from 2.118.101.0/29 if they don’t contain the headerConnection-Tier=unlimited.
-
Rule Actions
For Regular rules action can be one of:
-
Allow
-
Block
-
Count: increase a counter
-
CAPTCHA: requires the end user to solve a CAPTCHA puzzle to prove that a human being is sending the request.
-
Challenge: runs a silent challenge that requires the client session to verify that it’s a browser, and not a bot. The verification runs in the background without involving the end user. It’s a good option for verifying clients that you suspect of being invalid without negatively impacting the end user experience with a CAPTCHA puzzle.
For Rate-based rules Allow is not an option.
For Allow, Count and CAPTCHA you can add a Custom Request: it allows to add arbitrary headers refixed with x-amzn-waf- before forwarding the request to the backend.
For Block you can add a Custom Response to send to the client. It consists of:
-
A custom Response Code
-
A set of Custom headers (optional)
-
A custom Response Body, inline or previously created.
You can also optionally apply a Label. Labels are useful for MULTI-STAGE FLOWS, when the current rule Counts, CAPTCHA or Challenges but one of the next rules will evaluate traffic using that label as well. They’re only internal to WAF, they don’t get to the backend. Using labels relies on the flow not stopping: if you change the order of rules and the flow reaches an Allow or Block, evaluation stops. Be sure to put rules using lables before rules applying Allow or Block.
Logging and Metrics
-
CloudWatch Logs: the log group must start with
aws-waf-logs-. -
S3: delay of 5 minutes
-
Amazon Data Firehose, if you want to quickly react
Pricing
-
Monthly charge per Web ACL: $5
-
Monthly charge per rule: $1
-
Charge for each request: $0.6/1.000.000
-
Additional charges for paid features:
-
Marketplace Rule Groups
-
Intelligent Threat Mitigation
-
Bot Control: $10/month + $1/1.000.000
-
Captcha: $4/10.000
-
Challenge: $0.4/1.000.000
-
Fraud Control and Account Takeover Protection: $107month + $1/1.000 login attempts
-