Inconsistent Geo-blocking Behavior in WAF Policies with Prevention Mode

RJ 0 Reputation points
2026-06-16T12:36:56.8766667+00:00

We have experienced inconsistent behavior between Application Gateway WAF Policies that were provisioned at different times and in different methods--e.g., manually in the Azure Portal or via Terraform--but are otherwise identically configured. Both are in Prevention mode with custom rules that include allowlists based on geo-location using remote addresses as the match variable. The older, existing resource created manually years' ago has the expected behaviors but when trying to provision the resource anew using Terraform, we see that IP addresses in our virtual network are getting geo-blocked, with Access denied with code 403. Found condition 0 in RemoteAddr.

We would like help understanding why what has worked previously and is still working in our original infrastructure is not working the same in these new deployments. It should be noted that this deployment via Terraform has been done before and worked fine, as expected--same Azure region, same resource configuration and no update to Terraform versions--as recently as April 2026.

Azure Web Application Firewall

2 answers

Sort by: Newest
  1. Thanmayi Godithi 11,905 Reputation points Microsoft External Staff Moderator
    2026-06-16T13:46:18.6366667+00:00

    Hey @RJ — that does sound frustrating. Based on what you shared, the key symptoms are:

    • Both WAF policies are identically configured and in Prevention mode
    • The older/manual deployment behaves as expected
    • The new Terraform deployment instead geo-blocks IPs from your virtual network, returning 403 with:
      “Access denied with code 403. Found condition 0 in RemoteAddr”

    This strongly suggests the request is being evaluated against your custom allow/deny logic using RemoteAddr, and for those VN traffic flows, the value WAF is seeing for RemoteAddr is different than expected (or your allow/geo conditions are not matching that value the same way in the new deployment).

    The most important step is to validate the actual value WAF is matching.

    • Enable Application Gateway WAF diagnostic logs (Firewall logs)
    • Query Log Analytics around the time of a blocked request
    • Identify:
      • ruleId that caused the block
        • details (matched variable + value)
          • transactionId to trace the full request

    Since your error explicitly references RemoteAddr, this will confirm whether the IP being evaluated has changed in the Terraform deployment.

    Custom rules are evaluated in priority order (lower number = higher priority), and even small differences can change behavior.

    Recommended structure:

    • 1–100 → Allow trusted CIDRs (Action: Allow, Variable: RemoteAddr)
    • 200–900 → Scoped exceptions
    • 1000+ → Default deny/block

    If the deny rule is evaluated before the allow rule in the Terraform deployment, traffic will be blocked even if configs look identical.

    While you mentioned “ZZ (Unknown)” handling, the more likely issue is not geo itself but:

    The evaluated RemoteAddr differs, so geo/allow logic doesn’t match as expected.

    So the priority remains confirming via logs what value is actually being matched.

    In practice, there can still be effective differences such as:

    • Slight priority/order changes introduced by Terraform
    • Differences in how rules are rendered/applied
    • Traffic path changes affecting the client IP seen by WAF
    • Missing exclusions or implicit tuning from the older deployment

    This is why log-driven validation is key, especially in Prevention mode.

    If you can share the following for one blocked request, it will pinpoint the issue:

    1. WAF type (Application Gateway vs Front Door)
    2. From logs:
      • ruleId
      • details_data_s (matched value)
      • details_file_s (e.g., RemoteAddr)
    3. Custom rule priorities in both policies
    4. Any exclusions or extra rules in the older deployment
    5. Whether this affects all VN IPs or only specific ranges.

    Let me know if there are any results.

    Kindly let us know if the above helps or you need further assistance on this issue.

    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Was this answer helpful?


  2. AI answer

    2026-06-16T12:37:37.55+00:00

    The behavior difference is explained by how geo-filtering works in current WAF custom rules and by best-practice changes that affect internal/private IPs.

    Key points from the current WAF behavior:

    1. Geo-filtering is based on RemoteAddr → country mapping
      • Geo-filtering custom rules work by mapping each request’s IP address to a country/region.
      • When creating geomatch rules with PowerShell/ARM, the match variable must be RemoteAddr and the operator Geomatch.
      • If the IP cannot be mapped to a country/region, it’s treated as “Unknown”.

      “Geo-filtering works based on mapping each request's IP address to a country or region. There might be some IP addresses in the data set that aren't yet mapped to a country or region. To avoid accidentally blocking legitimate users, Application Gateway's WAF allows requests from unknown IP addresses.”

    2. The ZZ (Unknown) country code is now required in geo rules
      • Current guidance explicitly calls out that ZZ must be included whenever geo-filtering is used:

      “Include the country code ZZ whenever you use geo-filtering. The ZZ country code (or Unknown country/region) captures IP addresses that aren't yet mapped to a country or region in our dataset. This avoids false positives.”

      If the new Terraform-based WAF policy’s geomatch rules do not include ZZ in the allowlist, any IPs that resolve to “Unknown” (which often includes private/VNet address space or newly added ranges) can be blocked, resulting in Access denied with code 403. Found condition 0 in RemoteAddr. The older, manually created policy may:
      • Have been created before this stricter guidance, or
      • Implicitly allowed unknown IPs, or
      • Have a slightly different custom-rule ordering or conditions that effectively bypassed this issue.
    3. Custom rules run before managed rules and are decisive
      • WAF policies consist of custom rules and managed rule sets.
      • Custom rules are evaluated first and in priority order; once a match is found, lower-priority rules are not processed.

      “When both types of rules are present, the WAF processes custom rules before it processes the rules in a managed rule set… After the WAF matches a rule with a request, it applies the corresponding action… After the WAF processes such a match, it doesn't process rules that have lower priorities.”

      If the Terraform deployment created a custom geomatch rule with a BLOCK action that:
      • Uses RemoteAddr with Geomatch, and
      • Does not include ZZ in the allowed list,
      then any internal/VNet IPs that map to “Unknown” will be blocked before any other rule can allow them.
    4. Why the old and new policies differ despite “same configuration” Even with nominally identical configuration, differences can arise from:
      • Updated geo-IP datasets: IPs that previously mapped to a specific country may now map to “Unknown” or vice versa.
      • Changes in WAF engine/ruleset behavior: newer ruleset versions and engine improvements can change how unknown IPs are treated unless ZZ is explicitly handled.
      • Slight differences in custom rule definitions or priorities between the portal-created policy and the Terraform-created policy.
      The context explicitly notes that unknown IPs are allowed by default to avoid false positives, but also mandates including ZZ in geo-filtering rules. If the new policy’s geomatch rule is structured as an allowlist (allow specific countries, block everything else) without ZZ, internal addresses can be unintentionally blocked.

    Practical remediation steps based on current guidance:

    1. Review the geomatch custom rules in the new WAF policy
      • Confirm that the match variable is RemoteAddr and operator is Geomatch.
      • Check the list of countries/regions in the allowlist.
    2. Add ZZ to the geomatch rule
      • Ensure the geomatch rule explicitly includes the ZZ country code in the allowed set so that unknown/private/VNet IPs are not blocked.
    3. Verify rule priority and action
      • Confirm that the geomatch rule’s priority and action (ALLOW vs BLOCK) are aligned with the original working policy.
      • Ensure that any BLOCK geomatch rules are not inadvertently catching internal traffic before an ALLOW rule can match.
    4. Run in Detection mode when changing rules
      • As recommended, run the WAF in Detection mode temporarily when adjusting rules to collect logs and confirm that internal/VNet traffic is no longer being flagged before switching back to Prevention mode.

      “Run a newly deployed WAF in detection mode for a short period in a production environment… before transitioning to prevention mode. It also helps reduce the occurrence of unexpected blocked traffic.”

    These differences in how unknown/“ZZ” IPs are handled in geomatch rules explain why the older policy continues to work while the newly provisioned Terraform-based policy geo-blocks VNet IPs.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.