Repository navigation
fix: Apply section-scoped WAF policies only to the named HTTPProxy rule - #534
Merged
Merged
Conversation
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>
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>
Contributor
Author
|
@ecv could you check one more time. I wanted all passing testes before I promoted |
ecv
approved these changes
Oct 4, 2026
4 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
sectionName.findRouteTPPmatched HTTPRoute policies by route name only, so a rule-scoped policy landed on every rule of the route.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:
Accepted. It now also watches HTTPProxy changes.sectionNamethe HTTPProxy doesn't have, and only warns if the HTTPProxy doesn't exist yet. Updates are validated only whentargetRefschange.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
sectionNamefrom Envoy Gateway route metadata instead of rule positions.Test plan
exempt(/anything/exempt) andprotected(/), plus a TPP withsectionName: protected. A SQLi probe got 403 on both paths, while status saidTargetNotFound.TestApplyTPPRouteConfig_SectionScoping, 9 cases:TestRouteRuleIndex, the cache index test, the controller fallback test, and webhook validator tests.go build ./...,go vet, andgo testacross all non-e2e packages pass.controller-gen(v0.16.4) regeneratesconfig/webhook/manifests.yamlwith no diff.golangci-lintv2.12.2: passes in CI (anunparamfinding in the new test helpers was fixed in a follow-up commit).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 toDEFAULT_SCENARIOS./getand 200 on/anything/exempt.Related to datum-cloud/infra#6702
Related to datum-cloud/infra#6677
🤖 Generated with Claude Code