Repository: envoyproxy/gateway

Issue:
Bug: Envoy Gateway reports error when `InsecureSkipVerify` is set to true.
Envoy Gateway reports error when `InsecureSkipVerify` is set to true.

```
2025-07-31T05:32:17.552Z	ERROR	watchable	message/watchutil.go:53	observed a panic	{"runner": "xds-translator", "stackTrace": "goroutine 311 [running]:\nruntime/debug.Stack()\n\t/opt/hostedtoolcache/go/1.24.4/x64/src/runtime/debug/stack.go:26 +0x5e\ngithub.com/envoyproxy/gateway/internal/message.handleWithCrashRecovery[...].func1()\n\t/home/runner/work/gateway/gateway/internal/message/watchutil.go:54 +0x1fe\npanic({0x33f2520?, 0xb27d8b0?})\n\t/opt/hostedtoolcache/go/1.24.4/x64/src/runtime/panic.go:792 +0x132\ngithub.com/envoyproxy/gateway/internal/xds/translator.buildXdsUpstreamTLSCASecret(...)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:1158\ngithub.com/envoyproxy/gateway/internal/xds/translator.addXdsCluster(0xc000606be0, 0xc0012dec60)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:1065 +0x387\ngithub.com/envoyproxy/gateway/internal/xds/translator.processXdsCluster(0xc000606be0, {0xc00151bf20?, 0xf?}, {0xc0000ccd88?, 0x1?, 0xffffffffffffffff?}, {0x8b4a880?, 0xc001192340?}, 0x0?, 0xc0015c4fa0)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:1011 +0x4b\ngithub.com/envoyproxy/gateway/internal/xds/translator.(*Translator).addRouteToRouteConfig(0xc0013c98c0, 0xc000606be0, 0xc001225040, 0xc0007fcea0, 0x0, 0x0)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:593 +0xcac\ngithub.com/envoyproxy/gateway/internal/xds/translator.(*Translator).processHTTPListenerXdsTranslation(0xc0013c98c0, 0xc000606be0, {0xc0000ccd78, 0x1, 0xc000606b60?}, 0xc000d6da40, 0x0, 0x0)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:467 +0xa4c\ngithub.com/envoyproxy/gateway/internal/xds/translator.(*Translator).Translate(0xc0013c98c0, 0xc000a85500)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/translator.go:119 +0x125\ngithub.com/envoyproxy/gateway/internal/xds/translator/runner.(*Runner).subscribeAndTranslate.func1({{0xc0019d1690?, 0x35bd630d24018918?}, 0x80?, 0xc000a85500?}, 0xc0008a1490)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/runner/runner.go:94 +0x2ed\ngithub.com/envoyproxy/gateway/internal/message.handleWithCrashRecovery[...](0xc0011d7fa0?, {{0xc0019d1690, 0x0?}, 0x0?, 0xc000a85500?}, {{0x3b36a1d, 0xe}, {0x3b251df, 0x6}}, 0xc0008a1490?)\n\t/home/runner/work/gateway/gateway/internal/message/watchutil.go:60 +0x137\ngithub.com/envoyproxy/gateway/internal/message.HandleSubscription[...]({{0x3b36a1d, 0x0?}, {0x3b251df?, 0x0?}}, 0xc00186f650?, 0xc0013c9fa0)\n\t/home/runner/work/gateway/gateway/internal/message/watchutil.go:99 +0x7b0\ngithub.com/envoyproxy/gateway/internal/xds/translator/runner.(*Runner).subscribeAndTranslate(0xc000f1cc60, 0x0?)\n\t/home/runner/work/gateway/gateway/internal/xds/translator/runner/runner.go:61 +0x50\ncreated by github.com/envoyproxy/gateway/internal/xds/translator/runner.(*Runner).Start in goroutine 127\n\t/home/runner/work/gateway/gateway/internal/xds/translator/runner/runner.go:54 +0x2df\n", "error": "runtime error: invalid memory address or nil pointer dereference"}
```

Discussion:

Solution patch:
diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go
index 862d8d713..d04b7d965 100644
--- a/internal/xds/translator/translator.go
+++ b/internal/xds/translator/translator.go
@@ -1060,7 +1060,8 @@ func addXdsCluster(tCtx *types.ResourceVersionTable, args *xdsClusterArgs) error
 	preferLocal := ptr.Deref(args.loadBalancer, ir.LoadBalancer{}).PreferLocal
 	xdsEndpoints := buildXdsClusterLoadAssignment(args.name, args.settings, preferLocal)
 	for _, ds := range args.settings {
-		if ds.TLS != nil {
+		shouldValidateTLS := ds.TLS != nil && !ds.TLS.InsecureSkipVerify
+		if shouldValidateTLS {
 			// Create an SDS secret for the CA certificate - either with inline bytes or with a filesystem ref
 			secret := buildXdsUpstreamTLSCASecret(ds.TLS)
 			if err := tCtx.AddXdsResource(resourcev3.SecretType, secret); err != nil {



Test patch:
diff --git a/internal/xds/translator/testdata/in/xds-ir/backend-tls-skip-verify.yaml b/internal/xds/translator/testdata/in/xds-ir/backend-tls-skip-verify.yaml
index fc74c38f3..f446ca58e 100644
--- a/internal/xds/translator/testdata/in/xds-ir/backend-tls-skip-verify.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/backend-tls-skip-verify.yaml
@@ -19,7 +19,3 @@ http:
               name: "first-route-dest/backend/0"
               tls:
                 insecureSkipVerify: true
-                useSystemTrustStore: true
-                CACertificate:
-                  name: policy-btls/default-ca
-                sni: example.com
diff --git a/internal/xds/translator/testdata/out/xds-ir/backend-tls-skip-verify.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/backend-tls-skip-verify.clusters.yaml
index 540ba4fd7..915a64ca8 100644
--- a/internal/xds/translator/testdata/out/xds-ir/backend-tls-skip-verify.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/backend-tls-skip-verify.clusters.yaml
@@ -30,5 +30,4 @@
       typedConfig:
         '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
         commonTlsContext: {}
-        sni: example.com
   type: EDS
diff --git a/test/e2e/testdata/backend-tls.yaml b/test/e2e/testdata/backend-tls.yaml
index b95dbaa90..1f6f7d063 100644
--- a/test/e2e/testdata/backend-tls.yaml
+++ b/test/e2e/testdata/backend-tls.yaml
@@ -153,7 +153,7 @@ spec:
 apiVersion: gateway.envoyproxy.io/v1alpha1
 kind: Backend
 metadata:
-  name: backend-insecure-tls-verify
+  name: backend-insecure-tls-verify-and-mismatch-ca
   namespace: gateway-conformance-infra
 spec:
   endpoints:
@@ -166,7 +166,7 @@ spec:
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
 metadata:
-  name: http-with-backend-insecure-skip-verify
+  name: http-with-backend-insecure-skip-verify-and-mismatch-ca
   namespace: gateway-conformance-infra
 spec:
   parentRefs:
@@ -175,9 +175,40 @@ spec:
     - matches:
         - path:
             type: PathPrefix
-            value: /backend-tls-skip-verify
+            value: /backend-tls-skip-verify-and-mismatch-ca
       backendRefs:
-        - name: backend-insecure-tls-verify
+        - name: backend-insecure-tls-verify-and-mismatch-ca
+          group: gateway.envoyproxy.io
+          kind: Backend
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: Backend
+metadata:
+  name: backend-insecure-tls-verify-without-backend-tls-policy
+  namespace: gateway-conformance-infra
+spec:
+  endpoints:
+    - fqdn:
+        hostname: tls-backend-2.gateway-conformance-infra.svc.cluster.local
+        port: 443
+  tls:
+    insecureSkipVerify: true
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: http-with-backend-insecure-skip-verify-without-backend-tls-policy
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: same-namespace
+  rules:
+    - matches:
+        - path:
+            type: PathPrefix
+            value: /backend-tls-skip-verify-without-backend-tls-policy
+      backendRefs:
+        - name: backend-insecure-tls-verify-without-backend-tls-policy
           group: gateway.envoyproxy.io
           kind: Backend
 ---
diff --git a/test/e2e/tests/backend_tls.go b/test/e2e/tests/backend_tls.go
index bb76ed9ef..e711f7949 100644
--- a/test/e2e/tests/backend_tls.go
+++ b/test/e2e/tests/backend_tls.go
@@ -88,12 +88,29 @@ var BackendTLSTest = suite.ConformanceTest{
 		})
 
 		t.Run("with CA mismatch and skip tls verify", func(t *testing.T) {
-			routeNN := types.NamespacedName{Name: "http-with-backend-insecure-skip-verify", Namespace: ConformanceInfraNamespace}
+			routeNN := types.NamespacedName{Name: "http-with-backend-insecure-skip-verify-and-mismatch-ca", Namespace: ConformanceInfraNamespace}
 			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
 
 			expectedResponse := http.ExpectedResponse{
 				Request: http.Request{
-					Path: "/backend-tls-skip-verify",
+					Path: "/backend-tls-skip-verify-and-mismatch-ca",
+				},
+				Response: http.Response{
+					StatusCode: 200, // Bad Request: Client sent an HTTP request to an HTTPS server
+				},
+				Namespace: ConformanceInfraNamespace,
+			}
+
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse)
+		})
+
+		t.Run("without BackendTLSPolicy and skip tls verify", func(t *testing.T) {
+			routeNN := types.NamespacedName{Name: "http-with-backend-insecure-skip-verify-without-backend-tls-policy", Namespace: ConformanceInfraNamespace}
+			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+
+			expectedResponse := http.ExpectedResponse{
+				Request: http.Request{
+					Path: "/backend-tls-skip-verify-without-backend-tls-policy",
 				},
 				Response: http.Response{
 					StatusCode: 200, // Bad Request: Client sent an HTTP request to an HTTPS server