Skip to content

Commit deabb79

Browse files
fix(api): restrict BackendTrafficPolicy mergeType to xRoute targets
The mergeType field contract says it cannot be set when targeting a parent resource (Gateway), and the Gateway translation path ignores it, but unlike SecurityPolicy there was no spec-level validation enforcing this, so a Gateway-targeting policy could set a no-op mergeType and still be accepted. Add the same spec-level CEL rule SecurityPolicy uses, covering targetRef, targetRefs, and targetSelectors, regenerate the CRDs, and add CEL validation tests. Signed-off-by: mehara-rothila <rothilamehara22@gmail.com>
1 parent 23e21a2 commit deabb79

7 files changed

Lines changed: 109 additions & 0 deletions

File tree

api/v1alpha1/backendtrafficpolicy_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type BackendTrafficPolicy struct {
4343
// +kubebuilder:validation:XValidation:rule="has(self.targetRef) ? self.targetRef.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute'] : true", message="this policy can only have a targetRef.kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute"
4444
// +kubebuilder:validation:XValidation:rule="has(self.targetRefs) ? self.targetRefs.all(ref, ref.group == 'gateway.networking.k8s.io') : true ", message="this policy can only have a targetRefs[*].group of gateway.networking.k8s.io"
4545
// +kubebuilder:validation:XValidation:rule="has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute']) : true ", message="this policy can only have a targetRefs[*].kind of Gateway/HTTPRoute/GRPCRoute/TCPRoute/UDPRoute/TLSRoute"
46+
// +kubebuilder:validation:XValidation:rule="!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind in ['HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute']) && (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in ['HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute'])) && (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind in ['HTTPRoute', 'GRPCRoute', 'UDPRoute', 'TCPRoute', 'TLSRoute'])))", message="mergeType can only be used with xRoute targets"
4647
// +kubebuilder:validation:XValidation:rule="!has(self.compression) || !has(self.compressor)", message="either compression or compressor can be set, not both"
4748
// +kubebuilder:validation:XValidation:rule="!has(self.requestBuffer) || !has(self.httpUpgrade) || self.httpUpgrade.size() == 0", message="requestBuffer cannot be used together with httpUpgrade"
4849
// +kubebuilder:validation:XValidation:rule="!has(self.admissionControl) || ((!has(self.targetRef) || self.targetRef.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute']) && (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute'])) && (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind in ['Gateway', 'HTTPRoute', 'GRPCRoute'])))", message="admissionControl can only be used with HTTPRoute, GRPCRoute, or Gateway targets"

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,6 +3342,13 @@ spec:
33423342
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
33433343
''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
33443344
: true '
3345+
- message: mergeType can only be used with xRoute targets
3346+
rule: '!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind
3347+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
3348+
&& (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in
3349+
[''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute'']))
3350+
&& (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind
3351+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])))'
33453352
- message: either compression or compressor can be set, not both
33463353
rule: '!has(self.compression) || !has(self.compressor)'
33473354
- message: requestBuffer cannot be used together with httpUpgrade

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,6 +3341,13 @@ spec:
33413341
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
33423342
''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
33433343
: true '
3344+
- message: mergeType can only be used with xRoute targets
3345+
rule: '!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind
3346+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
3347+
&& (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in
3348+
[''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute'']))
3349+
&& (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind
3350+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])))'
33443351
- message: either compression or compressor can be set, not both
33453352
rule: '!has(self.compression) || !has(self.compressor)'
33463353
- message: requestBuffer cannot be used together with httpUpgrade

test/cel-validation/backendtrafficpolicy_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,79 @@ func TestBackendTrafficPolicyTarget(t *testing.T) {
7575
},
7676
wantErrors: []string{},
7777
},
78+
{
79+
desc: "valid mergeType with xRoute targetRef",
80+
mutate: func(btp *egv1a1.BackendTrafficPolicy) {
81+
btp.Spec = egv1a1.BackendTrafficPolicySpec{
82+
PolicyTargetReferences: egv1a1.PolicyTargetReferences{
83+
TargetRef: &gwapiv1.LocalPolicyTargetReferenceWithSectionName{
84+
LocalPolicyTargetReference: gwapiv1.LocalPolicyTargetReference{
85+
Group: gwapiv1.Group("gateway.networking.k8s.io"),
86+
Kind: gwapiv1.Kind("HTTPRoute"),
87+
Name: gwapiv1.ObjectName("httpbin-route"),
88+
},
89+
},
90+
},
91+
MergeType: new(egv1a1.Replace),
92+
}
93+
},
94+
wantErrors: []string{},
95+
},
96+
{
97+
desc: "mergeType rejected on Gateway targetRef",
98+
mutate: func(btp *egv1a1.BackendTrafficPolicy) {
99+
btp.Spec = egv1a1.BackendTrafficPolicySpec{
100+
PolicyTargetReferences: egv1a1.PolicyTargetReferences{
101+
TargetRef: &gwapiv1.LocalPolicyTargetReferenceWithSectionName{
102+
LocalPolicyTargetReference: gwapiv1.LocalPolicyTargetReference{
103+
Group: gwapiv1.Group("gateway.networking.k8s.io"),
104+
Kind: gwapiv1.Kind("Gateway"),
105+
Name: gwapiv1.ObjectName("eg"),
106+
},
107+
},
108+
},
109+
MergeType: new(egv1a1.Replace),
110+
}
111+
},
112+
wantErrors: []string{"mergeType can only be used with xRoute targets"},
113+
},
114+
{
115+
desc: "mergeType rejected on Gateway targetRefs",
116+
mutate: func(btp *egv1a1.BackendTrafficPolicy) {
117+
btp.Spec = egv1a1.BackendTrafficPolicySpec{
118+
PolicyTargetReferences: egv1a1.PolicyTargetReferences{
119+
TargetRefs: []gwapiv1.LocalPolicyTargetReferenceWithSectionName{
120+
{
121+
LocalPolicyTargetReference: gwapiv1.LocalPolicyTargetReference{
122+
Group: gwapiv1.Group("gateway.networking.k8s.io"),
123+
Kind: gwapiv1.Kind("Gateway"),
124+
Name: gwapiv1.ObjectName("eg"),
125+
},
126+
},
127+
},
128+
},
129+
MergeType: new(egv1a1.StrategicMerge),
130+
}
131+
},
132+
wantErrors: []string{"mergeType can only be used with xRoute targets"},
133+
},
134+
{
135+
desc: "mergeType rejected on Gateway targetSelector",
136+
mutate: func(btp *egv1a1.BackendTrafficPolicy) {
137+
btp.Spec = egv1a1.BackendTrafficPolicySpec{
138+
PolicyTargetReferences: egv1a1.PolicyTargetReferences{
139+
TargetSelectors: []egv1a1.TargetSelector{
140+
{
141+
Kind: gwapiv1.Kind("Gateway"),
142+
MatchLabels: map[string]string{"app": "foo"},
143+
},
144+
},
145+
},
146+
MergeType: new(egv1a1.StrategicMerge),
147+
}
148+
},
149+
wantErrors: []string{"mergeType can only be used with xRoute targets"},
150+
},
78151
{
79152
desc: "valid admissionControl percentage bounds",
80153
mutate: func(btp *egv1a1.BackendTrafficPolicy) {

test/helm/gateway-crds-helm/all.out.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27959,6 +27959,13 @@ spec:
2795927959
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
2796027960
''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
2796127961
: true '
27962+
- message: mergeType can only be used with xRoute targets
27963+
rule: '!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind
27964+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
27965+
&& (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in
27966+
[''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute'']))
27967+
&& (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind
27968+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])))'
2796227969
- message: either compression or compressor can be set, not both
2796327970
rule: '!has(self.compression) || !has(self.compressor)'
2796427971
- message: requestBuffer cannot be used together with httpUpgrade

test/helm/gateway-crds-helm/e2e.out.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3897,6 +3897,13 @@ spec:
38973897
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
38983898
''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
38993899
: true '
3900+
- message: mergeType can only be used with xRoute targets
3901+
rule: '!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind
3902+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
3903+
&& (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in
3904+
[''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute'']))
3905+
&& (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind
3906+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])))'
39003907
- message: either compression or compressor can be set, not both
39013908
rule: '!has(self.compression) || !has(self.compressor)'
39023909
- message: requestBuffer cannot be used together with httpUpgrade

test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3897,6 +3897,13 @@ spec:
38973897
rule: 'has(self.targetRefs) ? self.targetRefs.all(ref, ref.kind in [''Gateway'',
38983898
''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
38993899
: true '
3900+
- message: mergeType can only be used with xRoute targets
3901+
rule: '!has(self.mergeType) || ((!has(self.targetRef) || self.targetRef.kind
3902+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])
3903+
&& (!has(self.targetRefs) || self.targetRefs.all(ref, ref.kind in
3904+
[''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute'']))
3905+
&& (!has(self.targetSelectors) || self.targetSelectors.all(sel, sel.kind
3906+
in [''HTTPRoute'', ''GRPCRoute'', ''UDPRoute'', ''TCPRoute'', ''TLSRoute''])))'
39003907
- message: either compression or compressor can be set, not both
39013908
rule: '!has(self.compression) || !has(self.compressor)'
39023909
- message: requestBuffer cannot be used together with httpUpgrade

0 commit comments

Comments
 (0)