Skip to content

Conversation

@maxbrunet
Copy link
Contributor

@maxbrunet maxbrunet commented Oct 30, 2025

What type of PR is this?

Feature

What this PR does / why we need it:

Add support for ExtAuth context extensions in SecurityPolicy:

spec:
  extAuth:
    contextExtensions:
    - name: hello
      inline: world
    - name: foo
      type: ValueRef
      valueRef:
        kind: ConfigMap
        name: my-cm
        key: bar
    - name: bar
      type: ValueRef
      valueRef:
        kind: Secret
        name: my-secret
        key: foo

Which issue(s) this PR fixes:

Closes #6592

Release Notes: Yes

@maxbrunet maxbrunet requested a review from a team as a code owner October 30, 2025 20:37
@maxbrunet maxbrunet force-pushed the feat/extauth/context-extensions branch 5 times, most recently from e1d8c4c to d485d82 Compare October 30, 2025 21:18
@codecov
Copy link

codecov bot commented Oct 30, 2025

Codecov Report

❌ Patch coverage is 78.94737% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.27%. Comparing base (e5c1bb3) to head (c10dcf2).
⚠️ Report is 77 commits behind head on main.

Files with missing lines Patch % Lines
internal/provider/kubernetes/controller.go 60.00% 12 Missing and 4 partials ⚠️
internal/gatewayapi/securitypolicy.go 84.31% 4 Missing and 4 partials ⚠️
internal/provider/kubernetes/indexers.go 92.30% 2 Missing ⚠️
internal/xds/translator/credentialInjector.go 66.66% 0 Missing and 1 partial ⚠️
internal/xds/translator/custom_response.go 66.66% 0 Missing and 1 partial ⚠️
internal/xds/translator/extauth.go 93.33% 0 Missing and 1 partial ⚠️
internal/xds/translator/extproc.go 66.66% 0 Missing and 1 partial ⚠️
internal/xds/translator/lua.go 66.66% 0 Missing and 1 partial ⚠️
internal/xds/translator/wasm.go 66.66% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7383      +/-   ##
==========================================
- Coverage   72.30%   71.27%   -1.04%     
==========================================
  Files         231      274      +43     
  Lines       33939    34990    +1051     
==========================================
+ Hits        24539    24938     +399     
- Misses       7632     8257     +625     
- Partials     1768     1795      +27     

☔ View full report in Codecov by Sentry.
📢 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.

@maxbrunet maxbrunet force-pushed the feat/extauth/context-extensions branch from d485d82 to 0939490 Compare October 30, 2025 23:22
//
// +optional
// +unionMember
Inline string `json:"inline"`
Copy link
Contributor

@arkodg arkodg Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be ptr with a omitempty tag since its optional

Copy link
Contributor Author

@maxbrunet maxbrunet Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed!

btw, I named it Inline for consistency with Lua, but it does sound a little odd to me, maybe just Value would be more appropriate? It'd be consistent with gatewayv1.HTTPHeader

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've used Inline and ValueRef in Lua and Custom Response and Direct Response APIs
I'm not sure which one is better - Value and ValueRef or Inline and ValueRef
ptal @envoyproxy/gateway-maintainers @envoyproxy/gateway-reviewers

// without modifying the proto definition. It maps to the internal opaque
// context in the filter chain.
// +optional
ContextExtensions map[string]PrivateBytes `json:"contextExtensions,omitempty"`
Copy link
Contributor

@arkodg arkodg Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be a struct slice to retain deterministic order
we lose order with map and the same content will trigger further translation which can be avoided

Copy link
Contributor Author

@maxbrunet maxbrunet Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to understand the problem better, where does that lost of order triggering translation happen?

FYI The final data structure is a map: extauthv3.CheckSettings.ContextExtensions

I see APIKeyAuth.Credentials is map and translates to a list, is this one a problem?

gateway/internal/ir/xds.go

Lines 1219 to 1221 in 75f42e5

// The API key to be used for authentication.
// Key is the client id and the value is the API key to be used for authentication.
Credentials map[string]PrivateBytes `json:"credentials,omitempty" yaml:"credentials,omitempty"`

I could understand map to map to list would cause problems with ordering, but I am not clean about why that would be the case with list to map to map

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I'll raise a GH issue to fix Credentials

this is a pub sub system where, if the message is equal, the system avoids sending the message to the subcriber saving on cpu and mem and a redundant translation https://github.com/telepresenceio/watchable/blob/9bb86f92afa73d51a5e3e97aaf2959282d21818f/map.go#L23

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for that 1st bread crumb. This doc helped me on the high level as well: https://gateway.envoyproxy.io/contributions/design/watching/

I guess this is important here for the object refs from ValueRef, this is a list, so it should be all good:

for _, ctxExt := range extAuth.ContextExtensions {

A sort of Gateway resources by creationTimestamp/Namespace/Name happen here

After that I don't see any indication that order matters, especially at the field level.
DeepEqual would always be performed on the entire resource, no? (with reflect.DeepEqual for maps and slices)

When received, it translates everything (entire API SecurityPolicy) to IR

result, err := t.Translate(resources)

The order is lost here when translating to IR:

for _, ext := range contextExtensions {

But updates still seem to be triggered at the resource level, translation of everything (entire IR SecurityPolicy) to Envoy resources:

result, err := t.Translate(val)

And in the final translation, it is map to map, so order does not matter:

for name, value := range privateCtxExts {

Similar when building the indexes from ValueRef, it is a list, the order is still stable

for _, ctxExt := range securityPolicy.Spec.ExtAuth.ContextExtensions {

Am I still missing something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the issue is the IR map, I dont think watchable will be able to detect that the map is same if the content ( key, value) pairs haven't changed , you can try to confirm that with a test in https://github.com/envoyproxy/gateway/blob/main/internal/gatewayapi/runner/runner_test.go

also any YAML tests added in https://github.com/envoyproxy/gateway/tree/main/internal/gatewayapi/testdata will break because map order cannot be garunteed

Copy link
Contributor Author

@maxbrunet maxbrunet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @arkodg for the review

//
// +optional
// +unionMember
Inline string `json:"inline"`
Copy link
Contributor Author

@maxbrunet maxbrunet Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed!

btw, I named it Inline for consistency with Lua, but it does sound a little odd to me, maybe just Value would be more appropriate? It'd be consistent with gatewayv1.HTTPHeader

// without modifying the proto definition. It maps to the internal opaque
// context in the filter chain.
// +optional
ContextExtensions map[string]PrivateBytes `json:"contextExtensions,omitempty"`
Copy link
Contributor Author

@maxbrunet maxbrunet Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to understand the problem better, where does that lost of order triggering translation happen?

FYI The final data structure is a map: extauthv3.CheckSettings.ContextExtensions

I see APIKeyAuth.Credentials is map and translates to a list, is this one a problem?

gateway/internal/ir/xds.go

Lines 1219 to 1221 in 75f42e5

// The API key to be used for authentication.
// Key is the client id and the value is the API key to be used for authentication.
Credentials map[string]PrivateBytes `json:"credentials,omitempty" yaml:"credentials,omitempty"`

I could understand map to map to list would cause problems with ordering, but I am not clean about why that would be the case with list to map to map

@maxbrunet maxbrunet force-pushed the feat/extauth/context-extensions branch from 75f42e5 to c10dcf2 Compare November 19, 2025 19:00
@arkodg arkodg added this to the v1.7.0-rc.1 Release milestone Nov 21, 2025
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.

ExtAuth: allow passing context extensions

2 participants