Repository: envoyproxy/gateway
Pull request #6222 (2025-05-29 12:26:36)

feat(api): add insecureSkipVerify flag to Backend TLS settigns
feat(api): add insecureSkipVerify flag to Backend TLS settigns

**What this PR does / why we need it**:

provides an opportunity for skipping upstream certificate validation 

Fixes https://github.com/envoyproxy/gateway/issues/4595

Decided to add the flag to `Backend.BackendSpec.TLS` instead of `EnvoyProxySpec.BackendTLSConfig` because chosen option provides better granularity – there may be cases where the user wants to disable validation selectively (skip validation only for some of Backends, not for all of them). Also, certificate validation settings within Envoy are already at a level equivalent to the Backend (the setting in Envoy is at the Cluster level, and in EG Backend, after transformations, it maps to the Cluster).

<!--
For any non-trivial changes, you need to provide a brief description of the changes in the release notes.
Please add the description to the release-notes/current.yaml file and include this file in the PR.
-->
Release Notes: Yes/No


AlexKrudu: /retest
AlexKrudu: /retest
AlexKrudu: I messed up - pushed implementation in the same branch and rolled it back

Patch:
diff --git a/api/v1alpha1/backend_types.go b/api/v1alpha1/backend_types.go
index 004accc85..e5891d42e 100644
--- a/api/v1alpha1/backend_types.go
+++ b/api/v1alpha1/backend_types.go
@@ -123,7 +123,6 @@ type UnixSocket struct {
 
 // BackendSpec describes the desired state of BackendSpec.
 // +kubebuilder:validation:XValidation:rule="self.type != 'DynamicResolver' || !has(self.endpoints)",message="DynamicResolver type cannot have endpoints specified"
-// +kubebuilder:validation:XValidation:rule="has(self.tls) ? self.type == 'DynamicResolver' : true",message="TLS settings can only be specified for DynamicResolver backends"
 type BackendSpec struct {
 	// Type defines the type of the backend. Defaults to "Endpoints"
 	//
@@ -161,7 +160,6 @@ type BackendSpec struct {
 }
 
 // BackendTLSSettings holds the TLS settings for the backend.
-// Only used for DynamicResolver backends.
 // +kubebuilder:validation:XValidation:message="must not contain both CACertificateRefs and WellKnownCACertificates",rule="!(has(self.caCertificateRefs) && size(self.caCertificateRefs) > 0 && has(self.wellKnownCACertificates) && self.wellKnownCACertificates != \"\")"
 // +kubebuilder:validation:XValidation:message="must specify either CACertificateRefs or WellKnownCACertificates",rule="(has(self.caCertificateRefs) && size(self.caCertificateRefs) > 0 || has(self.wellKnownCACertificates) && self.wellKnownCACertificates != \"\")"
 type BackendTLSSettings struct {
@@ -176,6 +174,8 @@ type BackendTLSSettings struct {
 	// specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,
 	// not both.
 	//
+	// Only used for DynamicResolver backends.
+	//
 	// +kubebuilder:validation:MaxItems=8
 	// +optional
 	CACertificateRefs []gwapiv1.LocalObjectReference `json:"caCertificateRefs,omitempty"`
@@ -187,8 +187,18 @@ type BackendTLSSettings struct {
 	// must be specified with at least one entry for a valid configuration. Only one of
 	// CACertificateRefs or WellKnownCACertificates may be specified, not both.
 	//
+	// Only used for DynamicResolver backends.
+	//
 	// +optional
 	WellKnownCACertificates *gwapiv1a3.WellKnownCACertificatesType `json:"wellKnownCACertificates,omitempty"`
+
+	// InsecureSkipVerify indicates whether the upstream's certificate verification
+	// should be skipped. Defaults to "false".
+	//
+	// +kubebuilder:default=false
+	// +optional
+	// +notImplementedHide
+	InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty"`
 }
 
 // BackendType defines the type of the Backend.
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 9039df88c..1740518d9 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -554,6 +554,11 @@ func (in *BackendTLSSettings) DeepCopyInto(out *BackendTLSSettings) {
 		*out = new(v1alpha3.WellKnownCACertificatesType)
 		**out = **in
 	}
+	if in.InsecureSkipVerify != nil {
+		in, out := &in.InsecureSkipVerify, &out.InsecureSkipVerify
+		*out = new(bool)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendTLSSettings.
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
index 2a55fa397..eb4d4077b 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
@@ -171,6 +171,8 @@ spec:
                       If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be
                       specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,
                       not both.
+
+                      Only used for DynamicResolver backends.
                     items:
                       description: |-
                         LocalObjectReference identifies an API object within the namespace of the
@@ -208,6 +210,12 @@ spec:
                       type: object
                     maxItems: 8
                     type: array
+                  insecureSkipVerify:
+                    default: false
+                    description: |-
+                      InsecureSkipVerify indicates whether the upstream's certificate verification
+                      should be skipped. Defaults to "false".
+                    type: boolean
                   wellKnownCACertificates:
                     description: |-
                       WellKnownCACertificates specifies whether system CA certificates may be used in
@@ -216,6 +224,8 @@ spec:
                       If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs
                       must be specified with at least one entry for a valid configuration. Only one of
                       CACertificateRefs or WellKnownCACertificates may be specified, not both.
+
+                      Only used for DynamicResolver backends.
                     enum:
                     - System
                     type: string
@@ -240,8 +250,6 @@ spec:
             x-kubernetes-validations:
             - message: DynamicResolver type cannot have endpoints specified
               rule: self.type != 'DynamicResolver' || !has(self.endpoints)
-            - message: TLS settings can only be specified for DynamicResolver backends
-              rule: 'has(self.tls) ? self.type == ''DynamicResolver'' : true'
           status:
             description: Status defines the current status of Backend.
             properties:
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
index 8b45debdc..1b01448c6 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
@@ -170,6 +170,8 @@ spec:
                       If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be
                       specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,
                       not both.
+
+                      Only used for DynamicResolver backends.
                     items:
                       description: |-
                         LocalObjectReference identifies an API object within the namespace of the
@@ -207,6 +209,12 @@ spec:
                       type: object
                     maxItems: 8
                     type: array
+                  insecureSkipVerify:
+                    default: false
+                    description: |-
+                      InsecureSkipVerify indicates whether the upstream's certificate verification
+                      should be skipped. Defaults to "false".
+                    type: boolean
                   wellKnownCACertificates:
                     description: |-
                       WellKnownCACertificates specifies whether system CA certificates may be used in
@@ -215,6 +223,8 @@ spec:
                       If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs
                       must be specified with at least one entry for a valid configuration. Only one of
                       CACertificateRefs or WellKnownCACertificates may be specified, not both.
+
+                      Only used for DynamicResolver backends.
                     enum:
                     - System
                     type: string
@@ -239,8 +249,6 @@ spec:
             x-kubernetes-validations:
             - message: DynamicResolver type cannot have endpoints specified
               rule: self.type != 'DynamicResolver' || !has(self.endpoints)
-            - message: TLS settings can only be specified for DynamicResolver backends
-              rule: 'has(self.tls) ? self.type == ''DynamicResolver'' : true'
           status:
             description: Status defines the current status of Backend.
             properties:
diff --git a/internal/gatewayapi/backend.go b/internal/gatewayapi/backend.go
index e5168ca42..6aa614a05 100644
--- a/internal/gatewayapi/backend.go
+++ b/internal/gatewayapi/backend.go
@@ -48,6 +48,21 @@ func validateBackend(backend *egv1a1.Backend) status.Error {
 				status.RouteReasonInvalidBackendRef,
 			)
 		}
+	} else {
+		if backend.Spec.TLS != nil {
+			if backend.Spec.TLS.WellKnownCACertificates != nil {
+				return status.NewRouteStatusError(
+					fmt.Errorf("TLS.WellKnownCACertificates settings can only be specified for DynamicResolver backends"),
+					status.RouteReasonInvalidBackendRef,
+				)
+			}
+			if len(backend.Spec.TLS.CACertificateRefs) > 0 {
+				return status.NewRouteStatusError(
+					fmt.Errorf("TLS.CACertificateRefs settings can only be specified for DynamicResolver backends"),
+					status.RouteReasonInvalidBackendRef,
+				)
+			}
+		}
 	}
 
 	for _, ep := range backend.Spec.Endpoints {


Test patch:
diff --git a/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.in.yaml b/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.in.yaml
new file mode 100644
index 000000000..ebef4f085
--- /dev/null
+++ b/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.in.yaml
@@ -0,0 +1,30 @@
+backends:
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: Backend
+    metadata:
+      name: backend-1
+      namespace: default
+    spec:
+      tls:
+        caCertificateRefs:
+          - name: backend-ca-certificate
+            group: ""
+            kind: ConfigMap
+      endpoints:
+        - ip:
+            address: 1.1.1.1
+            port: 3001
+          zone: zone1
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: Backend
+    metadata:
+      name: backend-2
+      namespace: default
+    spec:
+      tls:
+        wellKnownCACertificates: System
+      endpoints:
+        - ip:
+            address: 2.2.2.2
+            port: 3001
+          zone: zone2
diff --git a/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.out.yaml b/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.out.yaml
new file mode 100644
index 000000000..48cc40379
--- /dev/null
+++ b/internal/gatewayapi/testdata/backend-invalid-tls-settings-with-endpoints.out.yaml
@@ -0,0 +1,50 @@
+backends:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend-1
+    namespace: default
+  spec:
+    endpoints:
+    - ip:
+        address: 1.1.1.1
+        port: 3001
+      zone: zone1
+    tls:
+      caCertificateRefs:
+      - group: ""
+        kind: ConfigMap
+        name: backend-ca-certificate
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: 'The Backend was not accepted: TLS.CACertificateRefs settings can only
+        be specified for DynamicResolver backends'
+      reason: Accepted
+      status: "False"
+      type: Invalid
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend-2
+    namespace: default
+  spec:
+    endpoints:
+    - ip:
+        address: 2.2.2.2
+        port: 3001
+      zone: zone2
+    tls:
+      wellKnownCACertificates: System
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: 'The Backend was not accepted: TLS.WellKnownCACertificates settings
+        can only be specified for DynamicResolver backends'
+      reason: Accepted
+      status: "False"
+      type: Invalid
+infraIR: {}
+xdsIR: {}
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index b59558dbe..5ba20a80c 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -448,15 +448,14 @@ _Appears in:_
 
 
 BackendTLSSettings holds the TLS settings for the backend.
-Only used for DynamicResolver backends.
 
 _Appears in:_
 - [BackendSpec](#backendspec)
 
 | Field | Type | Required | Default | Description |
 | ---   | ---  | ---      | ---     | ---         |
-| `caCertificateRefs` | _LocalObjectReference array_ |  false  |  | CACertificateRefs contains one or more references to Kubernetes objects that<br />contain TLS certificates of the Certificate Authorities that can be used<br />as a trust anchor to validate the certificates presented by the backend.<br />A single reference to a Kubernetes ConfigMap or a Kubernetes Secret,<br />with the CA certificate in a key named `ca.crt` is currently supported.<br />If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be<br />specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,<br />not both. |
-| `wellKnownCACertificates` | _[WellKnownCACertificatesType](#wellknowncacertificatestype)_ |  false  |  | WellKnownCACertificates specifies whether system CA certificates may be used in<br />the TLS handshake between the gateway and backend pod.<br />If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs<br />must be specified with at least one entry for a valid configuration. Only one of<br />CACertificateRefs or WellKnownCACertificates may be specified, not both. |
+| `caCertificateRefs` | _LocalObjectReference array_ |  false  |  | CACertificateRefs contains one or more references to Kubernetes objects that<br />contain TLS certificates of the Certificate Authorities that can be used<br />as a trust anchor to validate the certificates presented by the backend.<br />A single reference to a Kubernetes ConfigMap or a Kubernetes Secret,<br />with the CA certificate in a key named `ca.crt` is currently supported.<br />If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be<br />specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,<br />not both.<br />Only used for DynamicResolver backends. |
+| `wellKnownCACertificates` | _[WellKnownCACertificatesType](#wellknowncacertificatestype)_ |  false  |  | WellKnownCACertificates specifies whether system CA certificates may be used in<br />the TLS handshake between the gateway and backend pod.<br />If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs<br />must be specified with at least one entry for a valid configuration. Only one of<br />CACertificateRefs or WellKnownCACertificates may be specified, not both.<br />Only used for DynamicResolver backends. |
 
 
 #### BackendTelemetry
diff --git a/test/cel-validation/backend_test.go b/test/cel-validation/backend_test.go
index 10c79511e..698b1533a 100644
--- a/test/cel-validation/backend_test.go
+++ b/test/cel-validation/backend_test.go
@@ -16,7 +16,6 @@ import (
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/ptr"
-	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 )
@@ -284,30 +283,6 @@ func TestBackend(t *testing.T) {
 			},
 			wantErrors: []string{"DynamicResolver type cannot have endpoints specified"},
 		},
-		{
-			desc: "tls settings on non-dynamic resolver",
-			mutate: func(backend *egv1a1.Backend) {
-				backend.Spec = egv1a1.BackendSpec{
-					AppProtocols: []egv1a1.AppProtocolType{egv1a1.AppProtocolTypeH2C},
-					Endpoints: []egv1a1.BackendEndpoint{
-						{
-							FQDN: &egv1a1.FQDNEndpoint{
-								Hostname: "example.com",
-								Port:     443,
-							},
-						},
-					},
-					TLS: &egv1a1.BackendTLSSettings{
-						CACertificateRefs: []gwapiv1.LocalObjectReference{
-							{
-								Name: "ca-certificate",
-							},
-						},
-					},
-				}
-			},
-			wantErrors: []string{"TLS settings can only be specified for DynamicResolver backends"},
-		},
 		{
 			desc: "Invalid Unix socket path length",
 			mutate: func(backend *egv1a1.Backend) {
diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml
index 111971c6b..c1d836963 100644
--- a/test/helm/gateway-crds-helm/all.out.yaml
+++ b/test/helm/gateway-crds-helm/all.out.yaml
@@ -17483,6 +17483,8 @@ spec:
                       If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be
                       specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,
                       not both.
+
+                      Only used for DynamicResolver backends.
                     items:
                       description: |-
                         LocalObjectReference identifies an API object within the namespace of the
@@ -17520,6 +17522,12 @@ spec:
                       type: object
                     maxItems: 8
                     type: array
+                  insecureSkipVerify:
+                    default: false
+                    description: |-
+                      InsecureSkipVerify indicates whether the upstream's certificate verification
+                      should be skipped. Defaults to "false".
+                    type: boolean
                   wellKnownCACertificates:
                     description: |-
                       WellKnownCACertificates specifies whether system CA certificates may be used in
@@ -17528,6 +17536,8 @@ spec:
                       If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs
                       must be specified with at least one entry for a valid configuration. Only one of
                       CACertificateRefs or WellKnownCACertificates may be specified, not both.
+
+                      Only used for DynamicResolver backends.
                     enum:
                     - System
                     type: string
@@ -17552,8 +17562,6 @@ spec:
             x-kubernetes-validations:
             - message: DynamicResolver type cannot have endpoints specified
               rule: self.type != 'DynamicResolver' || !has(self.endpoints)
-            - message: TLS settings can only be specified for DynamicResolver backends
-              rule: 'has(self.tls) ? self.type == ''DynamicResolver'' : true'
           status:
             description: Status defines the current status of Backend.
             properties:
diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
index 1ba17b7fb..9d941d973 100644
--- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
+++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
@@ -171,6 +171,8 @@ spec:
                       If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be
                       specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified,
                       not both.
+
+                      Only used for DynamicResolver backends.
                     items:
                       description: |-
                         LocalObjectReference identifies an API object within the namespace of the
@@ -208,6 +210,12 @@ spec:
                       type: object
                     maxItems: 8
                     type: array
+                  insecureSkipVerify:
+                    default: false
+                    description: |-
+                      InsecureSkipVerify indicates whether the upstream's certificate verification
+                      should be skipped. Defaults to "false".
+                    type: boolean
                   wellKnownCACertificates:
                     description: |-
                       WellKnownCACertificates specifies whether system CA certificates may be used in
@@ -216,6 +224,8 @@ spec:
                       If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs
                       must be specified with at least one entry for a valid configuration. Only one of
                       CACertificateRefs or WellKnownCACertificates may be specified, not both.
+
+                      Only used for DynamicResolver backends.
                     enum:
                     - System
                     type: string
@@ -240,8 +250,6 @@ spec:
             x-kubernetes-validations:
             - message: DynamicResolver type cannot have endpoints specified
               rule: self.type != 'DynamicResolver' || !has(self.endpoints)
-            - message: TLS settings can only be specified for DynamicResolver backends
-              rule: 'has(self.tls) ? self.type == ''DynamicResolver'' : true'
           status:
             description: Status defines the current status of Backend.
             properties: