Repository: heptio/contour (go)

Issue:
Invalid IngressRoute with TLS still results in open HTTP listener
This issue is related to #1348

**What steps did you take and what happened:**
1. Create a secret in the `heptio-contour` namespace
2. Create an app with the following IngressRoute. Note that the IngressRoute references a TLS certificate in another namespace:

```yaml
apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
  name: app-with-tls-delegation
  namespace: app-with-tls-delegation
spec:
  virtualhost:
    fqdn: app-with-tls-delegation.127.0.0.1.nip.io
    tls:
      secretName: heptio-contour/ssl-cert
  routes:
  - match: '/'
    services:
    - name: app-with-tls-delegation
      port: 80
```

3. Get the IngressRoute and check the status. Notice how the IngressRoute is deemed invalid:

```shell
NAME                      FQDN                                       TLS SECRET                FIRST ROUTE   STATUS    STATUS DESCRIPTION
app-with-tls-delegation   app-with-tls-delegation.127.0.0.1.nip.io   heptio-contour/ssl-cert   /             invalid   heptio-contour/ssl-cert: certificate delegation not permitted

```

4. Access the application on the insecure port:

```shell
$ kubectl -n heptio-contour port-forward envoy-5d699 8080:80 &
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

$ curl -I app-with-tls-delegation.127.0.0.1.nip.io:8080
Handling connection for 8080
HTTP/1.1 200 OK
server: envoy
date: Thu, 05 Sep 2019 13:37:28 GMT
content-type: text/html
content-length: 612
last-modified: Tue, 13 Aug 2019 08:50:00 GMT
etag: "5d5279b8-264"
accept-ranges: bytes
x-envoy-upstream-service-time: 1

```

**What did you expect to happen:**
According to the documentation, the insecure port should be redirecting traffic to the secure port. I am not getting a redirect though.
> Contour also follows a "secure first" approach. When TLS is enabled for a virtual host, any request to the insecure port is redirected to the secure interface with a 301 redirect.

**Anything else you would like to add:**
The DAG:
```
digraph DAG {
rankdir="LR"
"0xc000654360" [shape=record, label="{listener|:80}"]
"0xc00064dd80" [shape=record, label="{http://app-with-tls-delegation.127.0.0.1.nip.io}"]
"0xc0003bec30" [shape=record, label="{prefix|/}"]
"0xc0006542a0" [shape=record, label="{cluster|{app-with-tls-delegation/app-with-ef7df1/80/da39a3ee5e|weight 0}}"]
"0xc000178c40" [shape=record, label="{service|app-with-tls-delegation/app-with-tls-delegation:80}"]
"0xc0006542a0" -> "0xc000178c40"
"0xc0003bec30" -> "0xc0006542a0"
"0xc00064dd80" -> "0xc0003bec30"
"0xc000654360" -> "0xc00064dd80"
}
```

Envoy's config dump:
https://gist.github.com/alexbrand/e299e7d6f22c9dd61d3d538296efbefb



**Environment:**

- Contour version: 
```
Name                       Image
contour-794b5558f6-8vn9h   projectcontour/contour:master
contour-794b5558f6-pgcm5   projectcontour/contour:master
contour-certgen-j29jk      projectcontour/contour:master
envoy-5d699                docker.io/envoyproxy/envoy:v1.11.1
envoy-f56fm                docker.io/envoyproxy/envoy:v1.11.1
envoy-k6bjs                docker.io/envoyproxy/envoy:v1.11.1
```



Pull request description:
internal/dag: mark ingressroute as invalid if tls details incorrect
Fixes #1452

Signed-off-by: Dave Cheney <dave@cheney.net>

Patch:
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 27adaf53..6813b24f 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -9,45 +9,50 @@ For example, if you have not configured any TLS ingress objects then Contour doe
 Because the HTTP and HTTPS listeners both use the same code, if you have no ingress objects deployed in your cluster, or if no ingress objects are permitted to talk on HTTP, then Envoy does not listen on port 8080 (80 in the service object).
 
 To test whether Contour is correctly deployed you can deploy the kuard example service:
-```
-$ kubectl apply -f https://j.hept.io/contour-kuard-example
+
+```sh
+% kubectl apply -f https://raw.githubusercontent.com/heptio/contour/master/examples/example-workload/kuard.yaml
 ```
 
 ## Access the Envoy admin interface remotely
 
 Getting access to the Envoy admin interface can be useful for diagnosing issues with routing or cluster health.
 
-The Envoy admin interface is bound by default to `http://127.0.0.1:9001`. 
+The Envoy admin interface is bound by default to `http://127.0.0.1:9001`.
 To access it from your workstation use `kubectl port-forward` like so,
-```
-# Get one of the pods that matches the examples/daemonset
-CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o jsonpath='{.items[0].metadata.name}')
+
+```sh
+# Get one of the pods that matches the Envoy daemonset
+ENVOY_POD=$(kubectl -n heptio-contour get pod -l app=envoy -o name | head -1)
 # Do the port forward to that pod
-kubectl -n heptio-contour port-forward $CONTOUR_POD 9001
+kubectl -n heptio-contour port-forward $ENVOY_POD 9001
 ```
+
 Then navigate to [http://127.0.0.1:9001/](http://127.0.0.1:9001/) to access the admin interface for the Envoy container running on that pod.
 
 ## Accessing Contour's /debug/pprof service
 
-Contour exposes the [net/http/pprof][5] handlers for `go tool pprof` and `go tool trace` by default on `127.0.0.1:6060`.
-This service is useful for profiling Contour. 
+Contour exposes the [net/http/pprof](https://golang.org/pkg/net/http/pprof/) handlers for `go tool pprof` and `go tool trace` by default on `127.0.0.1:6060`.
+This service is useful for profiling Contour.
 To access it from your workstation use `kubectl port-forward` like so,
-```
-# Get one of the pods that matches the examples/daemonset
-CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o jsonpath='{.items[0].metadata.name}')
+
+```sh
+# Get one of the pods that matches the Contour deployment
+CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o name | head -1)
 # Do the port forward to that pod
 kubectl -n heptio-contour port-forward $CONTOUR_POD 6060
 ```
 
 ## Visualizing Contour's internal directed acyclic graph (DAG)
 
-Contour models its configuration using a DAG, which can be visualized through a debug endpoint that outputs the DAG in [DOT][6] format. To visualize the graph, you must have [`graphviz`][7] installed on your system.
+Contour models its configuration using a DAG, which can be visualized through a debug endpoint that outputs the DAG in [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) format.
+To visualize the graph, you must have [`graphviz`](https://graphviz.gitlab.io/) installed on your system.
 
 To download the graph and save it as a PNG:
 
 ```sh
 # Port forward into the contour pod
-CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o jsonpath='{.items[0].metadata.name}')
+CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o name | head -1)
 # Do the port forward to that pod
 kubectl -n heptio-contour port-forward $CONTOUR_POD 6060
 # Download and store the DAG in png format
@@ -59,49 +64,24 @@ The following is an example of a DAG that maps `http://kuard.local:80/` to the
 
 ![Sample DAG](./dag-img/kuard-dag.png "Sample DAG")
 
-
 ## Interrogate Contour's gRPC API
 
 Sometimes it's helpful to be able to interrogate Contour to find out exactly the data it is sending to Envoy.
 Contour ships with a `contour cli` subcommand which can be used for this purpose.
 
-Because Contour runs as a sidecar with Envoy, you must run `contour cli` commands _inside_ the pod.
-The easiest way do this is via `kubectl exec`
-```
+Because Contour secures its communications with Envoy using Secrets in the cluster, the easiest way is to run `contour cli` commands _inside_ the pod.
+Do this is via `kubectl exec`:
+
+```sh
 # Get one of the pods that matches the examples/daemonset
 CONTOUR_POD=$(kubectl -n heptio-contour get pod -l app=contour -o jsonpath='{.items[0].metadata.name}')
 # Do the port forward to that pod
-kubectl -n heptio-contour exec $CONTOUR_POD -c contour contour cli lds
+kubectl -n heptio-contour exec $CONTOUR_POD -c contour -- contour cli lds --cafile=/ca/cacert.pem --cert-file=/certs/tls.crt --key-file=/certs/tls.key
 ```
+
 Which will stream changes to the LDS api endpoint to your terminal.
 Replace `contour cli lds` with `contour cli rds` for RDS, `contour cli cds` for CDS, and `contour cli eds` for EDS.
 
 ## I've deployed on Minikube or kind and nothing seems to work
 
-See [the deployment documentation][3] for some tips on using these two deployment options successfully.
-
-## How can I deploy a Contour daemonset directly onto ports 80 or 443?
-
-To set envoy to run on port 80 and port 443, the following additional 
-arguments may be passed into the contour command:
-
-```yaml
-  command: ["contour"]
-  args: 
-  - serve
-  - --incluster
-  - --envoy-service-http-port=80
-  - --envoy-service-https-port=443
-```
-
-See [Issue #547][4]
-
-[0]: https://github.com/jetstack/kube-lego
-[1]: https://github.com/heptio/contour/issues/210
-[2]: https://github.com/envoyproxy/envoy/issues/1269
-[3]: deploy-options.md
-[4]: https://github.com/heptio/contour/issues/547
-[5]: https://golang.org/pkg/net/http/pprof/
-[6]: https://en.wikipedia.org/wiki/DOT_(graph_description_language)
-[7]: https://graphviz.gitlab.io/
-[8]: https://github.com/jetstack/cert-manager
+See [the deployment documentation](deploy-options.md) for some tips on using these two deployment options successfully.
diff --git a/internal/dag/builder.go b/internal/dag/builder.go
index 6481e81f..93576421 100644
--- a/internal/dag/builder.go
+++ b/internal/dag/builder.go
@@ -366,63 +366,63 @@ func (b *Builder) computeIngresses() {
 
 func (b *Builder) computeIngressRoutes() {
 	for _, ir := range b.validIngressRoutes() {
-		if ir.Spec.VirtualHost == nil {
-			// mark delegate ingressroute orphaned.
-			b.setOrphaned(ir.Name, ir.Namespace)
-			continue
-		}
+		b.computeIngressRoute(ir)
+	}
+}
 
-		// ensure root ingressroute lives in allowed namespace
-		if !b.rootAllowed(ir.Namespace) {
-			b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: "root IngressRoute cannot be defined in this namespace"})
-			continue
-		}
+func (b *Builder) computeIngressRoute(ir *ingressroutev1.IngressRoute) {
+	if ir.Spec.VirtualHost == nil {
+		// mark delegate ingressroute orphaned.
+		b.setOrphaned(ir.Name, ir.Namespace)
+		return
+	}
 
-		host := ir.Spec.VirtualHost.Fqdn
-		if isBlank(host) {
-			b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: "Spec.VirtualHost.Fqdn must be specified"})
-			continue
-		}
+	// ensure root ingressroute lives in allowed namespace
+	if !b.rootAllowed(ir.Namespace) {
+		b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: "root IngressRoute cannot be defined in this namespace"})
+		return
+	}
 
-		if strings.Contains(host, "*") {
-			b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("Spec.VirtualHost.Fqdn %q cannot use wildcards", host), Vhost: host})
-			continue
-		}
+	host := ir.Spec.VirtualHost.Fqdn
+	if isBlank(host) {
+		b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: "Spec.VirtualHost.Fqdn must be specified"})
+		return
+	}
 
-		enforceTLS, passthrough := b.configureSecureVirtualHost(ir)
-		if ir.Spec.TCPProxy != nil && (passthrough || enforceTLS) {
-			b.processTCPProxy(ir, nil, host)
-		}
-		b.processIngressRoutes(ir, "", nil, host, ir.Spec.TCPProxy == nil && enforceTLS)
+	if strings.Contains(host, "*") {
+		b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("Spec.VirtualHost.Fqdn %q cannot use wildcards", host), Vhost: host})
+		return
 	}
-}
 
-func (b *Builder) configureSecureVirtualHost(ir *ingressroutev1.IngressRoute) (enforceTLS, passthrough bool) {
-	tls := ir.Spec.VirtualHost.TLS
-	if tls == nil {
-		return false, false
-	}
-	m := splitSecret(tls.SecretName, ir.Namespace)
-	sec := b.lookupSecret(m, validSecret)
-	if sec != nil {
-		if !b.delegationPermitted(m, ir.Namespace) {
-			b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("%s: certificate delegation not permitted", tls.SecretName)})
-			return false, false
+	var enforceTLS, passthrough bool
+	if tls := ir.Spec.VirtualHost.TLS; tls != nil {
+		m := splitSecret(tls.SecretName, ir.Namespace)
+		sec := b.lookupSecret(m, validSecret)
+		if sec != nil {
+			if !b.delegationPermitted(m, ir.Namespace) {
+				b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("%s: certificate delegation not permitted", tls.SecretName)})
+				return
+			}
+			svhost := b.lookupSecureVirtualHost(ir.Spec.VirtualHost.Fqdn)
+			svhost.Secret = sec
+			svhost.MinProtoVersion = MinProtoVersion(ir.Spec.VirtualHost.TLS.MinimumProtocolVersion)
+			enforceTLS = true
+		}
+		// passthrough is true if tls.secretName is not present, and
+		// tls.passthrough is set to true.
+		passthrough = isBlank(tls.SecretName) && tls.Passthrough
+
+		// If not passthrough and secret is invalid, then set status
+		if sec == nil && !passthrough {
+			b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("TLS Secret [%s] not found or is malformed", tls.SecretName)})
+			return
 		}
-		svhost := b.lookupSecureVirtualHost(ir.Spec.VirtualHost.Fqdn)
-		svhost.Secret = sec
-		svhost.MinProtoVersion = MinProtoVersion(ir.Spec.VirtualHost.TLS.MinimumProtocolVersion)
-		enforceTLS = true
 	}
-	// passthrough is true if tls.secretName is not present, and
-	// tls.passthrough is set to true.
-	passthrough = isBlank(tls.SecretName) && tls.Passthrough
 
-	// If not passthrough and secret is invalid, then set status
-	if sec == nil && !passthrough {
-		b.setStatus(Status{Object: ir, Status: StatusInvalid, Description: fmt.Sprintf("TLS Secret [%s] not found or is malformed", tls.SecretName)})
+	if ir.Spec.TCPProxy != nil && (passthrough || enforceTLS) {
+		b.processTCPProxy(ir, nil, host)
 	}
-	return enforceTLS, passthrough
+	b.processIngressRoutes(ir, "", nil, host, ir.Spec.TCPProxy == nil && enforceTLS)
 }
 
 func (b *Builder) computeHTTPLoadBalancers() {
@@ -451,7 +451,6 @@ func (b *Builder) computeHTTPLoadBalancers() {
 		}
 
 		var enforceTLS, passthrough bool
-
 		if tls := httplb.Spec.VirtualHost.TLS; tls != nil {
 			// attach secrets to TLS enabled vhosts
 			m := splitSecret(tls.SecretName, httplb.Namespace)


Test patch:
diff --git a/internal/dag/builder_test.go b/internal/dag/builder_test.go
index 5b9fd105..e4670464 100644
--- a/internal/dag/builder_test.go
+++ b/internal/dag/builder_test.go
@@ -1532,6 +1532,28 @@ func TestDAGInsert(t *testing.T) {
 		},
 	}
 
+	ir19 := &ingressroutev1.IngressRoute{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "app-with-tls-delegation",
+			Namespace: s10.Namespace,
+		},
+		Spec: ingressroutev1.IngressRouteSpec{
+			VirtualHost: &projcontour.VirtualHost{
+				Fqdn: "app-with-tls-delegation.127.0.0.1.nip.io",
+				TLS: &projcontour.TLS{
+					SecretName: "heptio-contour/ssl-cert", // not delegated
+				},
+			},
+			Routes: []ingressroutev1.Route{{
+				Match: "/",
+				Services: []ingressroutev1.Service{{
+					Name: s10.Name,
+					Port: 80,
+				}},
+			}},
+		},
+	}
+
 	httlb1 := &projcontour.HTTPLoadBalancer{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "example-com",
@@ -2821,6 +2843,12 @@ func TestDAGInsert(t *testing.T) {
 				},
 			),
 		},
+		"insert ingressroute with missing tls delegation should not present port 80": {
+			objs: []interface{}{
+				s10, ir19,
+			},
+			want: listeners(), // no listeners, ir19 is invalid
+		},
 		"insert root ingress route and delegate ingress route": {
 			objs: []interface{}{
 				ir5, s4, ir4, s5, ir3,
diff --git a/internal/dag/status_test.go b/internal/dag/status_test.go
index 29efba81..5b874e25 100644
--- a/internal/dag/status_test.go
+++ b/internal/dag/status_test.go
@@ -702,6 +702,28 @@ func TestDAGIngressRouteStatus(t *testing.T) {
 		},
 	}
 
+	ir28 := &ingressroutev1.IngressRoute{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "app-with-tls-delegation",
+			Namespace: s10.Namespace,
+		},
+		Spec: ingressroutev1.IngressRouteSpec{
+			VirtualHost: &projcontour.VirtualHost{
+				Fqdn: "app-with-tls-delegation.127.0.0.1.nip.io",
+				TLS: &projcontour.TLS{
+					SecretName: "heptio-contour/ssl-cert", // not delegated
+				},
+			},
+			Routes: []ingressroutev1.Route{{
+				Match: "/",
+				Services: []ingressroutev1.Service{{
+					Name: s10.Name,
+					Port: 80,
+				}},
+			}},
+		},
+	}
+
 	tests := map[string]struct {
 		objs []interface{}
 		want map[Meta]Status
@@ -937,6 +959,20 @@ func TestDAGIngressRouteStatus(t *testing.T) {
 				},
 			},
 		},
+		// issue 1452
+		"ingressroute with missing secret delegation should be invalid": {
+			objs: []interface{}{
+				s10,
+				ir28,
+			},
+			want: map[Meta]Status{
+				{name: ir28.Name, namespace: ir28.Namespace}: {
+					Object:      ir28,
+					Status:      StatusInvalid,
+					Description: "TLS Secret [heptio-contour/ssl-cert] not found or is malformed",
+				},
+			},
+		},
 	}
 
 	for name, tc := range tests {
diff --git a/internal/e2e/lds_test.go b/internal/e2e/lds_test.go
index 802f3e55..a0c5e93d 100644
--- a/internal/e2e/lds_test.go
+++ b/internal/e2e/lds_test.go
@@ -316,25 +316,39 @@ func TestIngressRouteTLSListener(t *testing.T) {
 		},
 	}
 
+	svc1 := &v1.Service{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "backend",
+			Namespace: secret1.Namespace,
+		},
+		Spec: v1.ServiceSpec{
+			Ports: []v1.ServicePort{{
+				Name:     "http",
+				Protocol: "TCP",
+				Port:     80,
+			}},
+		},
+	}
+
 	// i1 is a tls ingressroute
 	i1 := &ingressroutev1.IngressRoute{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "simple",
-			Namespace: "default",
+			Namespace: secret1.Namespace,
 		},
 		Spec: ingressroutev1.IngressRouteSpec{
 			VirtualHost: &projcontour.VirtualHost{
 				Fqdn: "kuard.example.com",
 				TLS: &projcontour.TLS{
-					SecretName:             "secret",
+					SecretName:             secret1.Name,
 					MinimumProtocolVersion: "1.1",
 				},
 			},
 			Routes: []ingressroutev1.Route{{
 				Match: "/",
 				Services: []ingressroutev1.Service{{
-					Name: "backend",
-					Port: 80,
+					Name: svc1.Name,
+					Port: int(svc1.Spec.Ports[0].Port),
 				}},
 			}},
 		},
@@ -344,40 +358,26 @@ func TestIngressRouteTLSListener(t *testing.T) {
 	i2 := &ingressroutev1.IngressRoute{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "simple",
-			Namespace: "default",
+			Namespace: secret1.Namespace,
 		},
 		Spec: ingressroutev1.IngressRouteSpec{
 			VirtualHost: &projcontour.VirtualHost{
 				Fqdn: "kuard.example.com",
 				TLS: &projcontour.TLS{
-					SecretName:             "secret",
+					SecretName:             secret1.Name,
 					MinimumProtocolVersion: "1.3",
 				},
 			},
 			Routes: []ingressroutev1.Route{{
 				Match: "/",
 				Services: []ingressroutev1.Service{{
-					Name: "backend",
-					Port: 80,
+					Name: svc1.Name,
+					Port: int(svc1.Spec.Ports[0].Port),
 				}},
 			}},
 		},
 	}
 
-	svc1 := &v1.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "backend",
-			Namespace: "default",
-		},
-		Spec: v1.ServiceSpec{
-			Ports: []v1.ServicePort{{
-				Name:     "http",
-				Protocol: "TCP",
-				Port:     80,
-			}},
-		},
-	}
-
 	// add secret
 	rh.OnAdd(secret1)
 
@@ -425,18 +425,12 @@ func TestIngressRouteTLSListener(t *testing.T) {
 		Nonce:   "1",
 	}, streamLDS(t, cc))
 
-	// delete secret and assert that ingress_https is removed
+	// delete secret and assert both listeners are removed because the
+	// ingressroute is no longer valid.
 	rh.OnDelete(secret1)
 	assertEqual(t, &v2.DiscoveryResponse{
 		VersionInfo: "2",
 		Resources: resources(t,
-			&v2.Listener{
-				Name:    "ingress_http",
-				Address: envoy.SocketAddress("0.0.0.0", 8080),
-				FilterChains: envoy.FilterChains(
-					envoy.HTTPConnectionManager("ingress_http", "/dev/stdout"),
-				),
-			},
 			staticListener(),
 		),
 		TypeUrl: listenerType,
@@ -1511,19 +1505,10 @@ func TestIngressRouteTLSCertificateDelegation(t *testing.T) {
 		},
 	})
 
-	ingress_http := &v2.Listener{
-		Name:    "ingress_http",
-		Address: envoy.SocketAddress("0.0.0.0", 8080),
-		FilterChains: envoy.FilterChains(
-			envoy.HTTPConnectionManager("ingress_http", "/dev/stdout"),
-		),
-	}
-
-	// assert there is no ingress_https because there is no matching secret.
+	// assert there are no listeners
 	assertEqual(t, &v2.DiscoveryResponse{
 		VersionInfo: "1",
 		Resources: resources(t,
-			ingress_http,
 			staticListener(),
 		),
 		TypeUrl: listenerType,
@@ -1547,6 +1532,14 @@ func TestIngressRouteTLSCertificateDelegation(t *testing.T) {
 	}
 	rh.OnAdd(t1)
 
+	ingress_http := &v2.Listener{
+		Name:    "ingress_http",
+		Address: envoy.SocketAddress("0.0.0.0", 8080),
+		FilterChains: envoy.FilterChains(
+			envoy.HTTPConnectionManager("ingress_http", "/dev/stdout"),
+		),
+	}
+
 	ingress_https := &v2.Listener{
 		Name:    "ingress_https",
 		Address: envoy.SocketAddress("0.0.0.0", 8443),
@@ -1615,7 +1608,6 @@ func TestIngressRouteTLSCertificateDelegation(t *testing.T) {
 	assertEqual(t, &v2.DiscoveryResponse{
 		VersionInfo: "4",
 		Resources: resources(t,
-			ingress_http,
 			staticListener(),
 		),
 		TypeUrl: listenerType,
@@ -1642,7 +1634,6 @@ func TestIngressRouteTLSCertificateDelegation(t *testing.T) {
 	assertEqual(t, &v2.DiscoveryResponse{
 		VersionInfo: "5",
 		Resources: resources(t,
-			ingress_http,
 			staticListener(),
 		),
 		TypeUrl: listenerType,