Subchapter 108.8
references/recovering-the-real-client-ip-behind-a-cdn.mdMarkdown9 KBView on GitHub
Domain expertise for making AWS WAF act on the real client IP when it sits behind a third-party content delivery network (CDN) or proxy, where the connection IP is the CDN’s. Covers enabling forwarded-IP configuration on rate-based, IP set, and geographic match rules, forwarding to the origin, and trusting forwarded headers only from a known upstream.
${awswaf:ip:}Does not cover the rules themselves in depth (see the rate-based and IP/geo references); this is the forwarded-IP concern that cuts across them. Pairs with the inbound-header-stripping reference.
Execute commands using the AWS MCP server when connected (sandboxed execution, audit logging, observability). Fall back to the AWS CLI otherwise.
To recover the real client IP end to end, follow the procedure exactly. See the Procedure section below.
The procedure covers:
${awswaf:ip:} to the originBehind a CDN, the connection IP AWS WAF reads is the CDN’s, not the user’s, so IP set rules, rate-based rules, and geographic match rules all act on the wrong address. Customers often do not know AWS WAF can recover the true client IP and conclude their rules are broken.
Constraints:
Forwarded-IP configuration tells the rule to read the client address from a header such as
X-Forwarded-For, True-Client-IP, or a custom header.
Constraints:
${awswaf:ip:} (the resolved client IP) to the origin via interpolation when
the origin needs it, rather than parsing the forwarding header downstreamA forwarding header can be set by anyone unless the upstream is trusted, which lets an attacker forge the client address.
Constraints:
The rules read the CDN IP. Enable forwarded-IP configuration on them (Enable forwarded-IP on the affected rules).
The forwarding header is trusted from an untrusted source. Trust it only from a known upstream and add the strip rule (Trust the header only from a known upstream).
This procedure enables forwarded-IP on the affected rules, optionally forwards the client IP to the origin, and surfaces the console link.
X-Forwarded-For, True-Client-IP, or a custom header the
trusted upstream sets.Constraints for parameter acquisition:
Constraints:
aws sts get-caller-identityConstraints:
You MUST add forwarded-IP configuration (header name and fallback behavior) to the affected rate-based and IP or geo rules
You MUST fetch the current LockToken before update-web-acl and pass the full rule set
You MUST preserve the web ACL’s existing DefaultAction from the get-web-acl response and pass
it back as {default_action}; do not assume Allow={}, since that would silently open all
unmatched traffic on a web ACL whose default action is Block. For example, a geo-match rule
reading the client IP from a forwarding header:
aws wafv2 get-web-acl --name {web_acl_name} --scope {scope} --id {web_acl_id} --region {region}
aws wafv2 update-web-acl --name {web_acl_name} --scope {scope} --id {web_acl_id} \
--lock-token {lock_token} --default-action {default_action} \
--rules '[{"Name":"BlockHighRiskCountries","Priority":1,"Action":{"Block":{}},"Statement":{"GeoMatchStatement":{"CountryCodes":["KP","IR"],"ForwardedIPConfig":{"HeaderName":"{forwarding_header}","FallbackBehavior":"NO_MATCH"}}},"VisibilityConfig":{"SampledRequestsEnabled":true,"CloudWatchMetricsEnabled":true,"MetricName":"BlockHighRiskCountries"}}]' \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName={web_acl_name} \
--region {region}Rate-based rules take the same ForwardedIPConfig under RateBasedStatement; FallbackBehavior
is MATCH or NO_MATCH for when the header is absent
Constraints:
${awswaf:ip:} to the origin if it needs the client IPConstraints:
You MUST present the web ACL console link and tell the customer to confirm the rules read the forwarded IP:
https://us-east-1.console.aws.amazon.com/wafv2/homev2/web-acls?region={region}{
"web_acl_name": "example-webacl",
"web_acl_id": "abc",
"scope": "REGIONAL",
"forwarding_header": "X-Forwarded-For",
"affected_rules": ["RateLimitLogin", "BlockHighRiskCountries"]
}Enabled forwarded-IP (X-Forwarded-For) on the rate-based and geo rules so they act on the real client IP.
Confirmed the CDN is a trusted upstream and added an inbound x-amzn-waf-* strip rule.
Open the web ACL and confirm the rules read the forwarded IP:
https://us-east-1.console.aws.amazon.com/wafv2/homev2/web-acls?region=us-east-1Forwarded-IP is not enabled on them. Add it (Step 2).
Trust the header only from a known upstream and add the strip rule (Step 3).
This procedure modifies a security control, so misconfiguration directly weakens the application’s defenses.
wafv2: actions a task needs (for example wafv2:GetWebACL and wafv2:UpdateWebACL) rather than wafv2:* or the AWSWAFFullAccess managed policy.aws sts assume-role) rather than long-lived IAM user access keys when running these WAF CLI commands.wafv2 management events and set CloudWatch alarms on critical web ACL configuration changes (such as DeleteWebACL and UpdateWebACL rule removals) and on the web ACL’s BlockedRequests and CountedRequests metrics, so rule changes and sudden spikes in blocked or counted traffic are detected.x-amzn-waf-* signal forwarded to the origin can be forged inbound. You MUST add the inbound-header-stripping rule whenever a signal or client IP is forwarded (see stripping-inbound-waf-headers-before-trusting-them); without it the origin trusts a spoofable value.