Skip to content

fix: Apply section-scoped WAF policies only to the named HTTPProxy rule - #534

Merged
bmertens-datum merged 2 commits into
mainfrom
fix/tpp-section-scoping
Oct 4, 2026
Merged

bmertens-datum merged 2 commits into
mainfrom
fix/tpp-section-scoping

Conversation

@bmertens-datum

@bmertens-datum bmertens-datum commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A TrafficProtectionPolicy that targets a single HTTPProxy rule (targetRefs[].sectionName) is applied to the whole route at the edge, while its status says it isn't attached at all (Accepted=False, TargetNotFound). Customers trying to leave one path out of the WAF, such as a streaming endpoint, get the opposite of what they asked for, with a status that says otherwise.

There are two causes:

  • The edge ignores sectionName. findRouteTPP matched HTTPRoute policies by route name only, so a rule-scoped policy landed on every rule of the route.
  • Status can't resolve the name. The project control plane's HTTPRoute CRD is Gateway API v1.3.0 standard, which has no rules[].name. The rule name NSO copies is pruned, so the controller never finds the section.

This resolves section names against the HTTPProxy's own rule names, by rule position, so it works without a Gateway API CRD upgrade:

  • Edge: the extension server indexes each replicated HTTPProxy's rule names. It works out each Envoy route's rule index from its cluster, or from the route name for redirect-only rules, and applies policies in order of precedence: rule-level, then route-level, then gateway-level. A section that can't be resolved applies to nothing, which matches the status.
  • Status: the TPP controller falls back to the owning or same-named HTTPProxy's rule names, so a valid section reports Accepted. It now also watches HTTPProxy changes.
  • Guard: a new validating webhook rejects a policy whose sectionName the HTTPProxy doesn't have, and only warns if the HTTPProxy doesn't exist yet. Updates are validated only when targetRefs change.

Important

Behaviour change: existing section-scoped policies, which today wrongly cover the whole route, will cover only their named rule after this ships.

Upgrading the project control plane's Gateway API CRDs to v1.4+ (so HTTPRoute keeps rule names natively) is still worth doing later. With it, the edge could read sectionName from Envoy Gateway route metadata instead of rule positions.

Test plan

  • Reproduced live first: HTTPProxy rules exempt (/anything/exempt) and protected (/), plus a TPP with sectionName: protected. A SQLi probe got 403 on both paths, while status said TargetNotFound.
  • Unit tests: TestApplyTPPRouteConfig_SectionScoping, 9 cases:
    • a scoped policy covers only its rule
    • redirect-only rules are handled
    • a route-level policy covers all rules
    • rule-level beats route-level and gateway-level
    • unresolvable sections and unknown proxies apply to nothing
    • unnamed rules don't match
  • TestRouteRuleIndex, the cache index test, the controller fallback test, and webhook validator tests.
  • go build ./..., go vet, and go test across all non-e2e packages pass.
  • controller-gen (v0.16.4) regenerates config/webhook/manifests.yaml with no diff.
  • golangci-lint v2.12.2: passes in CI (an unparam finding in the new test helpers was fixed in a follow-up commit).
  • New e2e-edge scenario test/e2e-edge/waf-section-scoping: passes in the Federated E2E (Karmada) suite (23 s). It checks that the policy is Accepted, the protected path blocks SQLi (403), benign requests pass (200), and the exempt path is not blocked (200). It's also added to DEFAULT_SCENARIOS.
  • After deploy: rerun the live repro and expect 403 on /get and 200 on /anything/exempt.

Related to datum-cloud/infra#6702
Related to datum-cloud/infra#6677

🤖 Generated with Claude Code

A TrafficProtectionPolicy targeting an HTTPRoute with sectionName was broken
in two ways (datum-cloud/infra#6702):

1. Upstream status was Accepted=False/TargetNotFound. The controller looked
   for the section in HTTPRoute rules[].name, but the project control plane's
   HTTPRoute CRD (Gateway API v1.3.0 standard) has no rules[].name, so the
   field is pruned.
2. The edge applied the WAF to the whole route. findRouteTPP matched on kind
   and name only and ignored sectionName.

Approach: resolve section names against the HTTPProxy, which does keep rule
names. HTTPProxy rule i is HTTPRoute rule i, and Envoy Gateway names routes
and clusters with that index, so no CRD change is needed.

- Edge: the policy index records each HTTPProxy's rule names by position. A
  route's rule index is parsed from its cluster, or from its route name for
  redirect-only rules. Precedence is rule-level, then route-level, then
  Gateway-level. A ref with a sectionName never matches another rule, and an
  unresolvable section applies to nothing. Gateway listener sectionName is
  unchanged.
- Controller: when HTTPRoute rule names are absent, fall back to the owning or
  same-named HTTPProxy rule names. HTTPProxy changes now requeue the policy
  namespace.
- Webhook: new validating webhook rejects an HTTPRoute sectionName that the
  same-named HTTPProxy does not define; warns if the HTTPProxy does not exist
  yet. Updates only validate when targetRefs change. The webhook manifest entry
  was added by hand (controller-gen could not run here).
- Tests: unit tests for scoping and precedence, index, controller fallback and
  webhook; new e2e-edge waf-section-scoping chainsaw scenario (not run).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bmertens-datum
bmertens-datum requested a review from a team as a code owner October 3, 2026 22:56
ecv
ecv previously approved these changes Oct 4, 2026
golangci-lint's unparam flagged sectionTPP and envoyRoute: routeName was
always "alb". Use a shared constant instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bmertens-datum

Copy link
Copy Markdown
Contributor Author

@ecv could you check one more time. I wanted all passing testes before I promoted

@bmertens-datum
bmertens-datum requested a review from ecv October 4, 2026 17:01
@bmertens-datum
bmertens-datum merged commit 346077b into main Oct 4, 2026
16 of 17 checks passed
@bmertens-datum
bmertens-datum deleted the fix/tpp-section-scoping branch October 4, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants