Skip to content

fix(translator): attach extension server policies to the target Gateway's listeners only - #10099

Open
vvoytovych wants to merge 2 commits into
envoyproxy:mainfrom
vvoytovych:fix/extension-policy-merged-gateways
Open

vvoytovych wants to merge 2 commits into
envoyproxy:mainfrom
vvoytovych:fix/extension-policy-merged-gateways

Conversation

@vvoytovych

@vvoytovych vvoytovych commented Sep 24, 2026 •

Copy link
Copy Markdown

What this PR does / why we need it:

With mergeGateways: true, an extension server policy that targets one Gateway is attached to the listeners of every Gateway in the GatewayClass.

translateExtServerPolicyForGateway loops over every listener in the IR of the Gateway's IR key. With mergeGateways, that key is the GatewayClass, so the loop covers every Gateway. The sectionName check compares only the last segment of the IR listener name, so it also matches other Gateways' listeners of the same name.

This change takes the listeners from the targeted Gateway, finds each one's IR listener by name, and matches sectionName against that Gateway's own listener names. Without mergeGateways, the result is the same as before.

What changes for users with mergeGateways:

  • A policy is attached only to its target Gateway's listeners, or only to the listener its sectionName names.
  • An HTTPListener post-hook no longer receives other Gateways' policies.
  • A policy whose sectionName names a listener that only another Gateway has is no longer reported Accepted.
  • Attachments grow as policies × the target's listeners, not policies × all listeners. On a copy of a fleet with a few hundred Gateways (766 listeners) and about 100 policies, the attachments fall from 79,664 to 267. On main, after perf: store extension server resources centrally #10071, that saves about 5 MiB. Before perf: store extension server resources centrally #10071, each attachment is a full copy of the policy; there, on v1.7.4, the same fix took the controller from 912 MiB to 71 MiB at rest.

The two lines in translator_test.go make TestTranslateWithExtensionKinds ignore ir.PrivateBytes, as TestTranslate already does. Without them, an extension golden file cannot hold an HTTPS listener, because the key is written as [redacted].

The bug has been present since v1.1.0 (#3371). Please consider a cherry-pick into release-v1.9 and release-v1.8.

Which issue(s) this PR fixes:

Fixes #10097


PR Checklist

  • Authorship & ownership: Coding agents / AI assistants are welcome, but I have reviewed every change, understand how and why it works, can explain and maintain it, and take full responsibility for this PR. I have not submitted generated output I do not understand.
  • DCO: All commits are signed off (git commit -s). See DCO: Sign your work.
  • API agreed first: N/A: no changes under /api.
  • Required checks pass: make generate gen-check, make lint, and go test ./internal/... pass locally.
  • Tests added/updated: a unit test (TestTranslateExtServerPolicyForGateway) and a golden test (extensionpolicy-merged-gateways). Both fail without the fix. The added lines are fully covered.
  • Docs: N/A: no API or configuration change.
  • Release notes: release-notes/current/bug_fixes/10097-extension-server-policy-merged-gateways.md.
  • Generated files committed: N/A: no API, Helm chart or module changes, and make gen-check leaves no diff.
  • Scope & compatibility: six files, all for this fix. No breaking change.
  • Codex review: Requested a Codex review and addressed all of its comments.
  • Copilot review: Requested a Copilot review and addressed all of its comments.

…ay's listeners only

With mergeGateways, the xDS IR of a GatewayClass holds the listeners of all
its Gateways. translateExtServerPolicyForGateway walked that IR, so an
extension server policy that targets one Gateway was referenced from the
listeners of every Gateway in the class, and a policy with a sectionName
from every listener of that name.

Take the listeners from the targeted Gateway and look up each IR listener
by name, as the route-targeted path already does. The sectionName is now
matched only against that Gateway's listeners. Behaviour without
mergeGateways is unchanged.

Add a unit test and a golden test with two merged Gateways that share
listener names. TestTranslateWithExtensionKinds now ignores redacted
private keys, as TestTranslate does, so that its golden files can hold an
HTTPS listener.

Signed-off-by: Viktor Voytovych <vvoytovych@gmail.com>
@vvoytovych
vvoytovych requested a review from a team as a code owner September 24, 2026 09:00
@netlify

netlify Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit 0d2a28d
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6abb6f31c6cb4c0008d703bd
😎 Deploy Preview https://deploy-preview-10099--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vvoytovych

Copy link
Copy Markdown
Author

@codex review

@vvoytovych

Copy link
Copy Markdown
Author

@zirain, could you approve the workflow run for this PR? This is my first PR here, so its four workflows are waiting for approval.

I would like this fix in the October patch, v1.9.3. We are upgrading to v1.9.2, and we run mergeGateways with extension server policies. On a copy of our objects, 79,397 of the 79,664 policy attachments are on another Gateway's listener.

I tried the pick. On release/v1.9 at the v1.9.2 tag, it applies cleanly and go test ./internal/gatewayapi/... passes. The two new tests fail without the fix. On release/v1.8, it conflicts in extensionserverpolicy.go and its test. So I ask for v1.9.3 only, and not for release-v1.8 as the description says.

@cnvergence

Copy link
Copy Markdown
Member

Thanks @vvoytovych, I have approved the workflows

@codecov

codecov Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.44%. Comparing base (f1f4888) to head (0d2a28d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10099      +/-   ##
==========================================
+ Coverage   81.41%   81.44%   +0.02%     
==========================================
  Files         266      266              
  Lines       41300    41296       -4     
==========================================
+ Hits        33626    33634       +8     
+ Misses       7673     7661      -12     
  Partials        1        1              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vvoytovych

Copy link
Copy Markdown
Author

/retest

@vvoytovych

Copy link
Copy Markdown
Author

Thanks @cnvergence for approving the workflows. One e2e job failed on WasmHTTPTLS: the Wasm download from the test's own server got connection refused. The same test passed in the other seven e2e jobs, and the rerun passed.

@guydc @zirain, could one of you review this? #3371 added this code, and #10071 changed it on 09-24.

@vvoytovych

Copy link
Copy Markdown
Author

/retest

@zirain

zirain commented Sep 30, 2026

Copy link
Copy Markdown
Member

To align with other policies, we may want to reject xPolicy to target to a Gateway when mergeGateways is enabled.
Hope #10062 will help.

@vvoytovych

Copy link
Copy Markdown
Author

@zirain, the reason in #10062 is right, and we will change our side.

What we agree with

  • Under mergeGateways, EG passes a Gateway-targeted policy to the extension together with every other Gateway's config (the code comment in #10062).
  • So EG cannot keep that policy to its own Gateway, and Accepted promises more than EG can enforce.

What we will do

  • Move each tenant's WAF policy from the tenant's Gateway to the tenant's HTTPRoutes.
  • EG passes a route-targeted policy with that one route only (extension.go), so EG keeps the isolation itself.
  • A GatewayClass target does not work for us: it no longer says which tenant the policy belongs to.

What we ask

Why we need the time

  • We run one merged class with hundreds of tenant Gateways. Most of our WAF policies target a Gateway today.
  • EG drops a rejected policy before translation (#10062). So a tenant's edit to it no longer triggers a rebuild, and waits for some unrelated change.
  • The move to route targets is a change in our operator. It needs time to build, test and roll out to every edge site.

Other points

Let me know if you have concerns. Thanks.

This branch has not been deployed

No deployments
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.

Extension server policies attach to every Gateway's listeners when mergeGateways is enabled

3 participants