Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
97753a8
api: cross-namespace policy target selectors
guydc Jan 24, 2025
d28eb68
use gw-api style for namespace selector
guydc Jan 29, 2025
e672802
fix json tag
guydc Jan 29, 2025
ba7b099
Merge branch 'main' into cross-ns-attachment
guydc Feb 5, 2025
289852c
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 5, 2026
b7422f9
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 7, 2026
9044f4e
update API
zhaohuabing Apr 7, 2026
7dbee3d
update API
zhaohuabing Apr 7, 2026
7d277a7
implmentation
zhaohuabing Apr 15, 2026
47b449e
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 21, 2026
1ac43e2
add e2e tests for cross ns policy attachment
zhaohuabing Apr 21, 2026
3066e54
update test
zhaohuabing Apr 21, 2026
f4c2f7a
fix lint
zhaohuabing Apr 21, 2026
dc3d896
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 21, 2026
e507c22
update test
zhaohuabing Apr 21, 2026
044fc0c
add referencegrants to the provider
zhaohuabing Apr 21, 2026
1476f27
fix test
zhaohuabing Apr 23, 2026
2979089
fix test
zhaohuabing Apr 23, 2026
a9de592
simplify code
zhaohuabing Apr 23, 2026
35c3569
address comments
zhaohuabing Apr 23, 2026
89d5c88
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 23, 2026
71bfe52
simplify code
zhaohuabing Apr 23, 2026
ea138b0
simplify code
zhaohuabing Apr 23, 2026
f2c7cf1
rename
zhaohuabing Apr 23, 2026
6382977
fix race
zhaohuabing Apr 23, 2026
ad0157c
remove unnecessary change
zhaohuabing Apr 23, 2026
158b144
simplify code
zhaohuabing Apr 23, 2026
a8855d1
rename
zhaohuabing Apr 23, 2026
77c3a29
refactor
zhaohuabing Apr 24, 2026
b4f0ada
address comments
zhaohuabing Apr 24, 2026
84e9ad3
address comments
zhaohuabing Apr 24, 2026
a0fbe68
add referencegrants for extension server policies
zhaohuabing Apr 24, 2026
0064832
Revert "add referencegrants for extension server policies"
zhaohuabing Apr 24, 2026
ade0ace
remove cross-ns policy attachment for extension server
zhaohuabing Apr 24, 2026
40a6cb3
fix gen
zhaohuabing Apr 24, 2026
3da3e2f
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 24, 2026
ba7e64a
fix lint
zhaohuabing Apr 24, 2026
f0a71ad
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 24, 2026
c38665e
fix test
zhaohuabing Apr 24, 2026
5d0ed71
address comments
zhaohuabing Apr 25, 2026
6600c72
remove unnecessary change
zhaohuabing Apr 25, 2026
879eefb
Merge branch 'main' into cross-ns-attachment
zhaohuabing Apr 26, 2026
8540972
fix cel validation
zhaohuabing Apr 29, 2026
8303114
Merge remote-tracking branch 'origin/main' into cross-ns-attachment
zhaohuabing Apr 29, 2026
5d88fbb
add warning for partially accepted targets
zhaohuabing Apr 29, 2026
33fd9ab
Merge branch 'main' into cross-ns-attachment
zhaohuabing Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/v1alpha1/envoygateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,8 @@ type ExtensionManager struct {
Resources []GroupVersionKind `json:"resources,omitempty"`

// PolicyResources defines the set of K8S resources the extension server will handle
// as directly attached GatewayAPI policies
// as directly attached Gateway API policies. Only policies in the same namespace as
// the target Gateway resources are supported. Cross-namespace attachments are not supported.
//
// +optional
PolicyResources []GroupVersionKind `json:"policyResources,omitempty"`
Expand Down
42 changes: 41 additions & 1 deletion api/v1alpha1/policy_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,18 @@ type TargetSelector struct {
// Kind is the resource kind that this selector targets.
Kind gwapiv1.Kind `json:"kind"`

// MatchLabels are the set of label selectors for identifying the targeted resource
// Namespaces determines which namespaces are considered for target selection.
//
// If unspecified, only targets in the same namespace as this policy are considered.
//
// When specified, the effective set of namespaces is always constrained to the
// namespaces watched by Envoy Gateway.
//
// +optional
Namespaces *TargetSelectorNamespaces `json:"namespaces,omitempty"`
Comment thread
zhaohuabing marked this conversation as resolved.

// MatchLabels are the set of label selectors for identifying the targeted resource.
//
// +optional
MatchLabels map[string]string `json:"matchLabels,omitempty"`

Expand All @@ -62,6 +73,35 @@ type TargetSelector struct {
MatchExpressions []metav1.LabelSelectorRequirement `json:"matchExpressions,omitempty"`
}

type TargetNamespaceFrom string

const (
// TargetNamespaceFromSame limits target selection to the policy's namespace.
TargetNamespaceFromSame TargetNamespaceFrom = "Same"
// TargetNamespaceFromAll allows target selection from all watched namespaces.
TargetNamespaceFromAll TargetNamespaceFrom = "All"
// TargetNamespaceFromSelector allows target selection from watched namespaces matching the selector.
TargetNamespaceFromSelector TargetNamespaceFrom = "Selector"
)

// TargetSelectorNamespaces determines which namespaces are considered for target selection.
// +kubebuilder:validation:XValidation:rule="self.from != 'Selector' || has(self.selector)", message="selector must be specified when from is Selector"
type TargetSelectorNamespaces struct {
// From indicates how namespaces are selected for this target selector.
//
// All means all namespaces watched by Envoy Gateway.
// Selector means namespaces watched by Envoy Gateway that match Selector.
//
// +kubebuilder:validation:Enum=Same;All;Selector
// +kubebuilder:default:=Same
From TargetNamespaceFrom `json:"from"`

// Selector selects namespaces when From is set to Selector.
//
// +optional
Selector *metav1.LabelSelector `json:"selector,omitempty"`

@zhaohuabing zhaohuabing Apr 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I’m a bit hesitant to add Selector support, as we don’t have a similar flexible ReferenceGrant API for it.

Or EG probably shouldn't require ReferenceGrant for cross-ns policy attachment at all. In the Gateway API semantics, ReferenceGrant is used for cross-namespace references to foreign objects, not for attachment relationships.

There is already precedent for this distinction in the Gateway API:

  • cross-namespace Route-to-Gateway attachment is governed by allowedRoutes, no ReferenceGrant required.
  • cross-namespace ListenerSet-to-Gateway attachment is governed by allowedListeners, no ReferenceGrant required.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My concern with allowing this without ReferenceGrant is that app teams could affect cluster-wide resources without the infra team’s knowledge or consent.

In Gateway API model, the affected resource (e.g. Gateway managed by the infra team) has the authority to control who can attach to it. In other words, consent comes from the target side.

By contrast, policy resources can be created by app teams, and a policy in one team’s namespace could target resources owned by other teams, without giving those teams any way to opt in or opt out.

That said, from the infra team’s perspective, this feature is very useful because a single policy can apply across resources in all namespaces.

So I think it's important to be clear about who should have that authority.
Would it make sense to add a toggle in EnvoyGateway to enable or disable this feature, or to allow it only for specific namespaces?

@zhaohuabing zhaohuabing Apr 8, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hi @kkk777-7 That's a good point! I agree the key question is who should have the authority to enable cross-namespace attachment.

One option is to require ReferenceGrant, but this might not be the right semantic fit, since Gateway API generally uses ReferenceGrant for cross-namespace object references rather than attachment-style relationships. A more Gateway API-native model would be target-side consent, for example something like an AllowedPolicies field on Gateways or Routes, though that would likely require upstream API work.

We've got a few options here:

  1. Use ReferenceGrant to explicitly authorize cross-namespace policy attachment.
  2. Disable cross-namespace policy attachment by default, and let operators enable it only for specific namespaces.
type CrossNamespacePolicyAttachment struct {
	Enabled bool `json:"enabled,omitempty"`
	AllowedPolicyNamespaces []string `json:"allowedPolicyNamespaces,omitempty"`
}
  1. Pursue a more target-side consent model, though that likely needs upstream API support. This is not feasible if we want to land it in EG in the near future as it requires some time to discuss this upstream.

Option 1 provides more granular control, while option 2 is simpler and would allow a smoother transition to a more Gateway API-native target-side consent model, such as an AllowedPolicies attachment mechanism in the future.

If we go with option 1, we should also start with a simpler namespace allowlist first rather than a fully flexible Selector, since the latter makes the authorization and UX harder to reason about.

type TargetSelectorNamespaces struct {
	// +kubebuilder:validation:Enum=Same;All;Names
	From TargetNamespaceFrom `json:"from"`

	MatchNames []string `json:"matchNames,omitempty"`
}

In the meantime, we could pursue a more target-side consent model in the upstream Gateway API.

cc @envoyproxy/gateway-maintainers could you please weigh in on the options?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @zhaohuabing :)
I agree that option3 needs some times to discuss this upstream, so prefer option2.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

+1 for option1, since there isnt a direct parent child relationship for policy and target, similar to gateway-route or gateway-listenerSet
take a case where app team in namespace A tries to influence routes in namespace B using a policy A, we dont want this to be the default, and want team B to opt in

I do think we need to think of a way to opt out of explicit ReferenceGrants, to reduce the number of resources needed to author intent, that can be a future follow up

@zhaohuabing zhaohuabing Apr 27, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Raised kubernetes-sigs/gateway-api#4799 in Gateway API to explore an “allow-from-target” approach, similar to Gateway.allowedListeners.

}

func (p PolicyTargetReferences) GetTargetRefs() []gwapiv1.LocalPolicyTargetReferenceWithSectionName {
if p.TargetRef != nil {
return []gwapiv1.LocalPolicyTargetReferenceWithSectionName{*p.TargetRef}
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ const (
// PolicyReasonDeprecatedField is used with the "Warning" condition when the policy
// uses deprecated fields that should be migrated to newer alternatives.
PolicyReasonDeprecatedField gwapiv1.PolicyConditionReason = "DeprecatedField"

// PolicyReasonRefNotPermitted is used when the policy targets a cross-namespace
// object without a matching ReferenceGrant.
PolicyReasonRefNotPermitted gwapiv1.PolicyConditionReason = "RefNotPermitted"
)

// GroupVersionKind unambiguously identifies a Kind.
Expand Down
25 changes: 25 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2805,8 +2805,82 @@ spec:
additionalProperties:
type: string
description: MatchLabels are the set of label selectors for
identifying the targeted resource
identifying the targeted resource.
type: object
namespaces:
description: |-
Namespaces determines which namespaces are considered for target selection.

If unspecified, only targets in the same namespace as this policy are considered.

When specified, the effective set of namespaces is always constrained to the
namespaces watched by Envoy Gateway.
properties:
from:
default: Same
description: |-
From indicates how namespaces are selected for this target selector.

All means all namespaces watched by Envoy Gateway.
Selector means namespaces watched by Envoy Gateway that match Selector.
enum:
- Same
- All
- Selector
type: string
selector:
description: Selector selects namespaces when From is set
to Selector.
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
required:
- from
type: object
x-kubernetes-validations:
- message: selector must be specified when from is Selector
rule: self.from != 'Selector' || has(self.selector)
required:
- kind
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1171,8 +1171,82 @@ spec:
additionalProperties:
type: string
description: MatchLabels are the set of label selectors for
identifying the targeted resource
identifying the targeted resource.
type: object
namespaces:
description: |-
Namespaces determines which namespaces are considered for target selection.

If unspecified, only targets in the same namespace as this policy are considered.

When specified, the effective set of namespaces is always constrained to the
namespaces watched by Envoy Gateway.
properties:
from:
default: Same
description: |-
From indicates how namespaces are selected for this target selector.

All means all namespaces watched by Envoy Gateway.
Selector means namespaces watched by Envoy Gateway that match Selector.
enum:
- Same
- All
- Selector
type: string
selector:
description: Selector selects namespaces when From is set
to Selector.
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
required:
- from
type: object
x-kubernetes-validations:
- message: selector must be specified when from is Selector
rule: self.from != 'Selector' || has(self.selector)
required:
- kind
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1814,8 +1814,82 @@ spec:
additionalProperties:
type: string
description: MatchLabels are the set of label selectors for
identifying the targeted resource
identifying the targeted resource.
type: object
namespaces:
description: |-
Namespaces determines which namespaces are considered for target selection.

If unspecified, only targets in the same namespace as this policy are considered.

When specified, the effective set of namespaces is always constrained to the
namespaces watched by Envoy Gateway.
properties:
from:
default: Same
description: |-
From indicates how namespaces are selected for this target selector.

All means all namespaces watched by Envoy Gateway.
Selector means namespaces watched by Envoy Gateway that match Selector.
enum:
- Same
- All
- Selector
type: string
selector:
description: Selector selects namespaces when From is set
to Selector.
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
required:
- from
type: object
x-kubernetes-validations:
- message: selector must be specified when from is Selector
rule: self.from != 'Selector' || has(self.selector)
required:
- kind
type: object
Expand Down
Loading
Loading