Repository: knative-sandbox/net-kourier
Pull request #806 (2022-03-24 02:12:31)

[main] Upgrade to latest dependencies
Cron -knative-prow-robot

/cc knative-sandbox/networking-wg-leads
/assign knative-sandbox/networking-wg-leads

Produced by: knative-sandbox/knobots/actions/update-deps

Details:
```
bumping knative.dev/networking ec52d71...55757e9:
  > 55757e9 Add HTTPS port variables (# 640)
  > ccab092 Adding code of conduct to reference knative/community's CoC (# 639)
```

knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/net-kourier/pull/806#" title="Author self-approved">knative-automation</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **tcnghia** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @tcnghia` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Fnet-kourier).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/knative-sandbox/net-kourier/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["tcnghia"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative-sandbox/net-kourier/pull/806?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) Report
> Merging [#806](https://codecov.io/gh/knative-sandbox/net-kourier/pull/806?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (00bb755) into [main](https://codecov.io/gh/knative-sandbox/net-kourier/commit/8673409702b1f442f12853ee3de397a418d876ab?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (8673409) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##             main     #806   +/-   ##
=======================================
  Coverage   82.49%   82.49%           
=======================================
  Files          18       18           
  Lines         777      777           
=======================================
  Hits          641      641           
  Misses         99       99           
  Partials       37       37           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/knative-sandbox/net-kourier/pull/806?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative-sandbox/net-kourier/pull/806?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Last update [8673409...00bb755](https://codecov.io/gh/knative-sandbox/net-kourier/pull/806?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).


Patch:
diff --git a/go.mod b/go.mod
index ecdc64b8..76b9c335 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,6 @@ require (
 	k8s.io/client-go v0.23.4
 	k8s.io/code-generator v0.23.4
 	knative.dev/hack v0.0.0-20220318020218-14f832e506f8
-	knative.dev/networking v0.0.0-20220318235444-ec52d7100cd9
+	knative.dev/networking v0.0.0-20220323170318-55757e9c20d6
 	knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765
 )
diff --git a/go.sum b/go.sum
index 64ab6a24..42edf81b 100644
--- a/go.sum
+++ b/go.sum
@@ -1165,8 +1165,8 @@ k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
 knative.dev/hack v0.0.0-20220224013837-e1785985d364/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
 knative.dev/hack v0.0.0-20220318020218-14f832e506f8 h1:7NcKM2USd6d3Vu/jJ4QziMUEUC+Y3yJ9xqusI/Pv0y0=
 knative.dev/hack v0.0.0-20220318020218-14f832e506f8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20220318235444-ec52d7100cd9 h1:YmwtiA/gxZobrxR4FXa/Y/WnR6D6XgLGMMgZ0t6WHUQ=
-knative.dev/networking v0.0.0-20220318235444-ec52d7100cd9/go.mod h1:tI+j9UGI4eHeinQktrQpHNS0pZ+XII1yF7ZtGyemkm0=
+knative.dev/networking v0.0.0-20220323170318-55757e9c20d6 h1:3dutSZL6nk/Rt30n0AAq5WfwRJBkHFBHRLdMosDnDh4=
+knative.dev/networking v0.0.0-20220323170318-55757e9c20d6/go.mod h1:tI+j9UGI4eHeinQktrQpHNS0pZ+XII1yF7ZtGyemkm0=
 knative.dev/pkg v0.0.0-20220318133418-7f16595277b2/go.mod h1:nKJ2L4o7or3j58eqMK843kbIM0SiYnAXXsisfEQECS8=
 knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765 h1:6ma46SWoj3Oiplz29qk8GZiYKhVAmx7CWzl9iHT7iFU=
 knative.dev/pkg v0.0.0-20220318185521-e6e3cf03d765/go.mod h1:nKJ2L4o7or3j58eqMK843kbIM0SiYnAXXsisfEQECS8=
diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh
index 27e18c80..d0e28140 100755
--- a/hack/update-codegen.sh
+++ b/hack/update-codegen.sh
@@ -31,7 +31,8 @@ group "Deepcopy Gen"
 ${GOPATH}/bin/deepcopy-gen \
   -O zz_generated.deepcopy \
   --go-header-file "${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt" \
-  -i knative.dev/net-kourier/pkg/config
+  -i knative.dev/net-kourier/pkg/config \
+  -i knative.dev/net-kourier/pkg/reconciler/ingress/config
 
 # Make sure our dependencies are up-to-date
 ${REPO_ROOT_DIR}/hack/update-deps.sh
diff --git a/pkg/envoy/api/cluster.go b/pkg/envoy/api/cluster.go
index 3b6068ae..a27220ce 100644
--- a/pkg/envoy/api/cluster.go
+++ b/pkg/envoy/api/cluster.go
@@ -19,7 +19,9 @@ package envoy
 import (
 	"time"
 
-	envoyCluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
+	envoyclusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
+	envoycorev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
+
 	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
 	httpOptions "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
 	"google.golang.org/protobuf/types/known/anypb"
@@ -31,12 +33,12 @@ func NewCluster(
 	name string,
 	connectTimeout time.Duration,
 	endpoints []*endpoint.LbEndpoint,
-	isHTTP2 bool,
-	discoveryType envoyCluster.Cluster_DiscoveryType) *envoyCluster.Cluster {
+	isHTTP2 bool, transportSocket *envoycorev3.TransportSocket,
+	discoveryType envoyclusterv3.Cluster_DiscoveryType) *envoyclusterv3.Cluster {
 
-	cluster := &envoyCluster.Cluster{
+	cluster := &envoyclusterv3.Cluster{
 		Name: name,
-		ClusterDiscoveryType: &envoyCluster.Cluster_Type{
+		ClusterDiscoveryType: &envoyclusterv3.Cluster_Type{
 			Type: discoveryType,
 		},
 		ConnectTimeout: durationpb.New(connectTimeout),
@@ -46,6 +48,7 @@ func NewCluster(
 				LbEndpoints: endpoints,
 			}},
 		},
+		TransportSocket: transportSocket,
 	}
 
 	if isHTTP2 {
diff --git a/pkg/generator/ingress_translator.go b/pkg/generator/ingress_translator.go
index 0176a4c9..828a6e9d 100644
--- a/pkg/generator/ingress_translator.go
+++ b/pkg/generator/ingress_translator.go
@@ -24,18 +24,29 @@ import (
 	"time"
 
 	v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
+	envoycorev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
 	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
 	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
+	tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
+	envoymatcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
+	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
+	"google.golang.org/protobuf/types/known/anypb"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/types"
 	envoy "knative.dev/net-kourier/pkg/envoy/api"
+	"knative.dev/net-kourier/pkg/reconciler/ingress/config"
 	"knative.dev/networking/pkg/apis/networking/v1alpha1"
 	"knative.dev/pkg/kmeta"
 	"knative.dev/pkg/logging"
+	"knative.dev/pkg/system"
 	"knative.dev/pkg/tracker"
 )
 
+const (
+	caDataName = "ca.crt"
+)
+
 type translatedIngress struct {
 	name                    types.NamespacedName
 	sniMatches              []*envoy.SNIMatch
@@ -169,7 +180,23 @@ func (translator *IngressTranslator) translateIngress(ctx context.Context, ingre
 				}
 
 				connectTimeout := 5 * time.Second
-				cluster := envoy.NewCluster(splitName, connectTimeout, publicLbEndpoints, http2, typ)
+
+				var transportSocket *envoycorev3.TransportSocket
+
+				// This has to be "OrDefaults" because this path is called before the informers are
+				// running when booting the controller up and prefilling the config before making it
+				// ready.
+				cfg := config.FromContextOrDefaults(ctx)
+
+				// As Ingress with RewriteHost points to ExternalService(kourier-internal), we don't enable TLS.
+				if activatorCA := cfg.Network.ActivatorCA; activatorCA != "" && httpPath.RewriteHost == "" {
+					var err error
+					transportSocket, err = translator.createUpstreamTransportSocket(activatorCA, config.FromContext(ctx).Network.ActivatorSAN, http2)
+					if err != nil {
+						return nil, err
+					}
+				}
+				cluster := envoy.NewCluster(splitName, connectTimeout, publicLbEndpoints, http2, transportSocket, typ)
 				clusters = append(clusters, cluster)
 
 				weightedCluster := envoy.NewWeightedCluster(splitName, uint32(split.Percent), split.AppendHeaders)
@@ -241,6 +268,52 @@ func (translator *IngressTranslator) translateIngress(ctx context.Context, ingre
 	}, nil
 }
 
+func (translator *IngressTranslator) createUpstreamTransportSocket(activatorCA, activatorSAN string, http2 bool) (*envoycorev3.TransportSocket, error) {
+	caSecret, err := translator.secretGetter(system.Namespace(), activatorCA)
+	if err != nil {
+		return nil, fmt.Errorf("failed to fetch activator CA secret: %w", err)
+	}
+	var alpnProtocols string
+	if http2 {
+		alpnProtocols = "h2"
+	}
+	tlsAny, err := anypb.New(createUpstreamTLSContext(caSecret.Data[caDataName], activatorSAN, alpnProtocols))
+	if err != nil {
+		return nil, err
+	}
+	return &envoycorev3.TransportSocket{
+		Name: wellknown.TransportSocketTls,
+		ConfigType: &envoycorev3.TransportSocket_TypedConfig{
+			TypedConfig: tlsAny,
+		},
+	}, nil
+}
+
+func createUpstreamTLSContext(caCertificate []byte, activatorSAN string, alpnProtocols ...string) *tls.UpstreamTlsContext {
+	return &tls.UpstreamTlsContext{
+		CommonTlsContext: &tls.CommonTlsContext{
+			AlpnProtocols: alpnProtocols,
+			TlsParams: &tls.TlsParameters{
+				TlsMinimumProtocolVersion: tls.TlsParameters_TLSv1_2,
+			},
+			ValidationContextType: &tls.CommonTlsContext_ValidationContext{
+				ValidationContext: &tls.CertificateValidationContext{
+					TrustedCa: &envoycorev3.DataSource{
+						Specifier: &envoycorev3.DataSource_InlineBytes{
+							InlineBytes: caCertificate,
+						},
+					},
+					MatchSubjectAltNames: []*envoymatcherv3.StringMatcher{{
+						MatchPattern: &envoymatcherv3.StringMatcher_Exact{
+							Exact: activatorSAN,
+						}},
+					},
+				},
+			},
+		},
+	}
+}
+
 func trackSecret(t tracker.Interface, ns, name string, ingress *v1alpha1.Ingress) error {
 	return t.TrackReference(tracker.Reference{
 		Kind:       "Secret",
diff --git a/pkg/reconciler/ingress/config/store.go b/pkg/reconciler/ingress/config/store.go
index 844c0f82..de9c15b1 100644
--- a/pkg/reconciler/ingress/config/store.go
+++ b/pkg/reconciler/ingress/config/store.go
@@ -20,14 +20,17 @@ import (
 	"context"
 
 	"knative.dev/net-kourier/pkg/config"
+	network "knative.dev/networking/pkg"
 	"knative.dev/pkg/configmap"
 )
 
 type cfgKey struct{}
 
 // Config contains the configmaps requires for revision reconciliation.
+// +k8s:deepcopy-gen=false
 type Config struct {
 	Kourier *config.Kourier
+	Network *network.Config
 }
 
 // FromContext loads the configuration from the context.
@@ -41,6 +44,14 @@ func FromContextOrDefaults(ctx context.Context) *Config {
 	}
 	return &Config{
 		Kourier: config.DefaultConfig(),
+		Network: defaultConfig(),
+	}
+}
+
+func defaultConfig() *network.Config {
+	return &network.Config{
+		ActivatorCA:  "",
+		ActivatorSAN: "",
 	}
 }
 
@@ -50,6 +61,7 @@ func ToContext(ctx context.Context, c *Config) context.Context {
 }
 
 // Store is a typed wrapper around configmap.UntypedStore to handle our configmaps.
+// +k8s:deepcopy-gen=false
 type Store struct {
 	*configmap.UntypedStore
 }
@@ -61,7 +73,8 @@ func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value i
 			"kourier",
 			logger,
 			configmap.Constructors{
-				config.ConfigName: config.NewConfigFromConfigMap,
+				config.ConfigName:  config.NewConfigFromConfigMap,
+				network.ConfigName: network.NewConfigFromConfigMap,
 			},
 			onAfterStore...,
 		),
@@ -78,5 +91,6 @@ func (s *Store) ToContext(ctx context.Context) context.Context {
 func (s *Store) Load() *Config {
 	return &Config{
 		Kourier: s.UntypedLoad(config.ConfigName).(*config.Kourier).DeepCopy(),
+		Network: s.UntypedLoad(network.ConfigName).(*network.Config).DeepCopy(),
 	}
 }
diff --git a/pkg/reconciler/ingress/config/zz_generated.deepcopy.go b/pkg/reconciler/ingress/config/zz_generated.deepcopy.go
new file mode 100644
index 00000000..98b1bd41
--- /dev/null
+++ b/pkg/reconciler/ingress/config/zz_generated.deepcopy.go
@@ -0,0 +1,53 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+/*
+Copyright 2021 The Knative Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by deepcopy-gen. DO NOT EDIT.
+
+package config
+
+import (
+	pkgconfig "knative.dev/net-kourier/pkg/config"
+	pkg "knative.dev/networking/pkg"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Config) DeepCopyInto(out *Config) {
+	*out = *in
+	if in.Kourier != nil {
+		in, out := &in.Kourier, &out.Kourier
+		*out = new(pkgconfig.Kourier)
+		**out = **in
+	}
+	if in.Network != nil {
+		in, out := &in.Network, &out.Network
+		*out = new(pkg.Config)
+		(*in).DeepCopyInto(*out)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config.
+func (in *Config) DeepCopy() *Config {
+	if in == nil {
+		return nil
+	}
+	out := new(Config)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/vendor/knative.dev/networking/pkg/apis/networking/ports.go b/vendor/knative.dev/networking/pkg/apis/networking/ports.go
index 2a64a102..1c5b5301 100644
--- a/vendor/knative.dev/networking/pkg/apis/networking/ports.go
+++ b/vendor/knative.dev/networking/pkg/apis/networking/ports.go
@@ -26,11 +26,18 @@ const (
 	// HTTP/2 endpoints.
 	ServiceHTTP2Port = 81
 
+	// ServiceHTTPSPort is the port that we setup our Serving and Activator K8s services for
+	// HTTPS endpoints.
+	ServiceHTTPSPort = 443
+
 	// ServicePortNameHTTP1 is the name of the external port of the service for HTTP/1.1
 	ServicePortNameHTTP1 = "http"
 
 	// ServicePortNameH2C is the name of the external port of the service for HTTP/2
 	ServicePortNameH2C = "http2"
+
+	// ServicePortNameHTTPS is the name of the external port of the service for HTTPS
+	ServicePortNameHTTPS = "https"
 )
 
 // ServicePortName returns the port for the app level protocol.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f69746b5..2ba45212 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -867,7 +867,7 @@ k8s.io/utils/trace
 # knative.dev/hack v0.0.0-20220318020218-14f832e506f8
 ## explicit
 knative.dev/hack
-# knative.dev/networking v0.0.0-20220318235444-ec52d7100cd9
+# knative.dev/networking v0.0.0-20220323170318-55757e9c20d6
 ## explicit
 knative.dev/networking/config
 knative.dev/networking/pkg


Test patch:
diff --git a/.github/workflows/kind-e2e-upgrade.yaml b/.github/workflows/kind-e2e-upgrade.yaml
index 74fe4db0..06dee89e 100644
--- a/.github/workflows/kind-e2e-upgrade.yaml
+++ b/.github/workflows/kind-e2e-upgrade.yaml
@@ -24,6 +24,11 @@ jobs:
         - v1.22.0
         - v1.23.0
 
+        upstream-traffic:
+        - plain
+        # TODO: Enable tls after 1.14 release.
+        # - tls
+
         # Map between K8s and KinD versions.
         # This is attempting to make it a bit clearer what's being tested.
         # See: https://github.com/kubernetes-sigs/kind/releases
@@ -116,6 +121,13 @@ jobs:
         # Create a cluster!
         kind create cluster --config kind.yaml
 
+    - name: Deploy certificates for upstream traffic
+      if: matrix.upstream-tls == 'tls'
+      run: |
+        set -o pipefail
+        echo ">> Deploy certificate for upstream traffic"
+        ./test/generate-upstream-cert.sh
+
     - name: Run upgrade tests
       run: |
         ./test/e2e-upgrade-kind.sh
diff --git a/.github/workflows/kind-e2e.yaml b/.github/workflows/kind-e2e.yaml
index 6fc0c5f9..e0aeb9ed 100644
--- a/.github/workflows/kind-e2e.yaml
+++ b/.github/workflows/kind-e2e.yaml
@@ -29,6 +29,10 @@ jobs:
         - docker.io/envoyproxy/envoy:v1.19-latest
         - docker.io/envoyproxy/envoy:v1.20-latest
 
+        upstream-tls:
+        - plain
+        - tls
+
         # Map between K8s and KinD versions.
         # This is attempting to make it a bit clearer what's being tested.
         # See: https://github.com/kubernetes-sigs/kind/releases
@@ -118,6 +122,13 @@ jobs:
         # Create a cluster!
         kind create cluster --config kind.yaml
 
+    - name: Deploy certificates for upstream traffic
+      if: matrix.upstream-tls == 'tls'
+      run: |
+        set -o pipefail
+        echo ">> Deploy certificate for upstream traffic"
+        ./test/generate-upstream-cert.sh
+
     - name: Install Knative net-kourier
       run: |
         set -o pipefail
diff --git a/pkg/envoy/api/cluster_test.go b/pkg/envoy/api/cluster_test.go
index 626e9a3b..1fac8de8 100644
--- a/pkg/envoy/api/cluster_test.go
+++ b/pkg/envoy/api/cluster_test.go
@@ -35,13 +35,13 @@ func TestNewCluster(t *testing.T) {
 	endpoints := []*endpoint.LbEndpoint{endpoint1, endpoint2}
 
 	// With HTTP2
-	c := NewCluster(name, connectTimeout, endpoints, true, v3Cluster.Cluster_STATIC)
+	c := NewCluster(name, connectTimeout, endpoints, true, nil, v3Cluster.Cluster_STATIC)
 	assert.Equal(t, c.GetConnectTimeout().Seconds, int64(connectTimeout.Seconds()))
 	assert.Assert(t, c.TypedExtensionProtocolOptions["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"] != nil)
 	assert.Equal(t, c.GetName(), name)
 	assert.DeepEqual(t, c.LoadAssignment.Endpoints[0].LbEndpoints, endpoints, protocmp.Transform())
 
 	// Without HTTP2
-	c = NewCluster(name, connectTimeout, endpoints, false, v3Cluster.Cluster_STATIC)
+	c = NewCluster(name, connectTimeout, endpoints, false, nil, v3Cluster.Cluster_STATIC)
 	assert.Assert(t, c.TypedExtensionProtocolOptions["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"] == nil)
 }
diff --git a/pkg/generator/ingress_translator_test.go b/pkg/generator/ingress_translator_test.go
index d9f6abe9..ee6413fb 100644
--- a/pkg/generator/ingress_translator_test.go
+++ b/pkg/generator/ingress_translator_test.go
@@ -17,14 +17,20 @@ limitations under the License.
 package generator
 
 import (
+	"context"
 	"testing"
 	"time"
 
 	v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
+	envoycorev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
 	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
 	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
+	auth "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
+	envoymatcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
+	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
 	"github.com/google/go-cmp/cmp"
 	"google.golang.org/protobuf/testing/protocmp"
+	"google.golang.org/protobuf/types/known/anypb"
 	"gotest.tools/v3/assert"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -33,6 +39,8 @@ import (
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes/fake"
 	envoy "knative.dev/net-kourier/pkg/envoy/api"
+	"knative.dev/net-kourier/pkg/reconciler/ingress/config"
+	network "knative.dev/networking/pkg"
 	"knative.dev/networking/pkg/apis/networking/v1alpha1"
 	pkgtest "knative.dev/pkg/reconciler/testing"
 )
@@ -86,6 +94,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -152,6 +161,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -235,6 +245,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -304,6 +315,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -381,6 +393,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 					envoy.NewCluster(
@@ -388,6 +401,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 					envoy.NewCluster(
@@ -395,6 +409,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						[]*endpoint.LbEndpoint{envoy.NewLBEndpoint("example.com", 80)},
 						false,
+						nil,
 						v3.Cluster_LOGICAL_DNS,
 					),
 				},
@@ -448,6 +463,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -501,6 +517,7 @@ func TestIngressTranslator(t *testing.T) {
 						5*time.Second,
 						[]*endpoint.LbEndpoint{envoy.NewLBEndpoint("example.com", 80)},
 						false,
+						nil,
 						v3.Cluster_LOGICAL_DNS,
 					),
 				},
@@ -520,7 +537,9 @@ func TestIngressTranslator(t *testing.T) {
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx, _ := pkgtest.SetupFakeContext(t)
+			cfg := defaultConfig.DeepCopy()
+			ctx := (&testConfigStore{config: cfg}).ToContext(context.Background())
+
 			kubeclient := fake.NewSimpleClientset(test.state...)
 
 			translator := NewIngressTranslator(
@@ -546,6 +565,29 @@ func TestIngressTranslator(t *testing.T) {
 	}
 }
 
+type testConfigStore struct {
+	config *config.Config
+}
+
+func (t *testConfigStore) ToContext(ctx context.Context) context.Context {
+	return config.ToContext(ctx, t.config)
+}
+
+var (
+	defaultConfig = &config.Config{
+		Network: &network.Config{
+			AutoTLS: false,
+		},
+	}
+	upstreamTLSConfig = &config.Config{
+		Network: &network.Config{
+			AutoTLS:      false,
+			ActivatorCA:  "test-ca",
+			ActivatorSAN: "test-san",
+		},
+	}
+)
+
 // TestIngressTranslatorWithHTTPOptionDisabled runs same redirect test in TestIngressTranslator with KOURIER_HTTPOPTION_DISABLED env value.
 func TestIngressTranslatorWithHTTPOptionDisabled(t *testing.T) {
 	tests := []struct {
@@ -611,6 +653,7 @@ func TestIngressTranslatorWithHTTPOptionDisabled(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -680,6 +723,7 @@ func TestIngressTranslatorWithHTTPOptionDisabled(t *testing.T) {
 						5*time.Second,
 						lbEndpoints,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -693,7 +737,167 @@ func TestIngressTranslatorWithHTTPOptionDisabled(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			t.Setenv("KOURIER_HTTPOPTION_DISABLED", "true")
-			ctx, _ := pkgtest.SetupFakeContext(t)
+			cfg := defaultConfig.DeepCopy()
+			ctx := (&testConfigStore{config: cfg}).ToContext(context.Background())
+			kubeclient := fake.NewSimpleClientset(test.state...)
+
+			translator := NewIngressTranslator(
+				func(ns, name string) (*corev1.Secret, error) {
+					return kubeclient.CoreV1().Secrets(ns).Get(ctx, name, metav1.GetOptions{})
+				},
+				func(ns, name string) (*corev1.Endpoints, error) {
+					return kubeclient.CoreV1().Endpoints(ns).Get(ctx, name, metav1.GetOptions{})
+				},
+				func(ns, name string) (*corev1.Service, error) {
+					return kubeclient.CoreV1().Services(ns).Get(ctx, name, metav1.GetOptions{})
+				},
+				&pkgtest.FakeTracker{},
+			)
+
+			got, err := translator.translateIngress(ctx, test.in, false)
+			assert.NilError(t, err)
+			assert.DeepEqual(t, got, test.want,
+				cmp.AllowUnexported(translatedIngress{}),
+				protocmp.Transform(),
+			)
+		})
+	}
+}
+
+func TestIngressTranslatorWithUpstreamTLS(t *testing.T) {
+	tests := []struct {
+		name  string
+		in    *v1alpha1.Ingress
+		state []runtime.Object
+		want  *translatedIngress
+	}{{
+		name: "simple",
+		in: ing("simplens", "simplename", func(ing *v1alpha1.Ingress) {
+			ing.Spec.Rules[0].HTTP.Paths[0].RewriteHost = ""
+		}),
+		state: []runtime.Object{
+			svc("servicens", "servicename"),
+			eps("servicens", "servicename"),
+			caSecret,
+		},
+		want: func() *translatedIngress {
+			vHosts := []*route.VirtualHost{
+				envoy.NewVirtualHost(
+					"(simplens/simplename).Rules[0]",
+					[]string{"foo.example.com", "foo.example.com:*"},
+					[]*route.Route{envoy.NewRoute(
+						"(simplens/simplename).Rules[0].Paths[/test]",
+						[]*route.HeaderMatcher{{
+							Name: "testheader",
+							HeaderMatchSpecifier: &route.HeaderMatcher_ExactMatch{
+								ExactMatch: "foo",
+							},
+						}},
+						"/test",
+						[]*route.WeightedCluster_ClusterWeight{
+							envoy.NewWeightedCluster("servicens/servicename", 100, map[string]string{"baz": "gna"}),
+						},
+						0,
+						map[string]string{"foo": "bar"},
+						""),
+					},
+				),
+			}
+
+			return &translatedIngress{
+				name: types.NamespacedName{
+					Namespace: "simplens",
+					Name:      "simplename",
+				},
+				sniMatches: []*envoy.SNIMatch{},
+				clusters: []*v3.Cluster{
+					envoy.NewCluster(
+						"servicens/servicename",
+						5*time.Second,
+						lbEndpoints,
+						false,
+						&envoycorev3.TransportSocket{
+							Name:       wellknown.TransportSocketTls,
+							ConfigType: typedConfig(false /* http2 */),
+						},
+						v3.Cluster_STATIC,
+					),
+				},
+				externalVirtualHosts:    vHosts,
+				externalTLSVirtualHosts: []*route.VirtualHost{},
+				internalVirtualHosts:    vHosts,
+			}
+		}(),
+	}, {
+		name: "http2",
+		in: ing("simplens", "simplename", func(ing *v1alpha1.Ingress) {
+			ing.Spec.Rules[0].HTTP.Paths[0].RewriteHost = ""
+		}),
+		state: []runtime.Object{
+			svc("servicens", "servicename", func(service *corev1.Service) {
+				service.Spec.Ports = []corev1.ServicePort{{
+					Name:       "http2",
+					TargetPort: intstr.FromInt(8080),
+				}}
+			}),
+			eps("servicens", "servicename"),
+			caSecret,
+		},
+		want: func() *translatedIngress {
+			vHosts := []*route.VirtualHost{
+				envoy.NewVirtualHost(
+					"(simplens/simplename).Rules[0]",
+					[]string{"foo.example.com", "foo.example.com:*"},
+					[]*route.Route{envoy.NewRoute(
+						"(simplens/simplename).Rules[0].Paths[/test]",
+						[]*route.HeaderMatcher{{
+							Name: "testheader",
+							HeaderMatchSpecifier: &route.HeaderMatcher_ExactMatch{
+								ExactMatch: "foo",
+							},
+						}},
+						"/test",
+						[]*route.WeightedCluster_ClusterWeight{
+							envoy.NewWeightedCluster("servicens/servicename", 100, map[string]string{"baz": "gna"}),
+						},
+						0,
+						map[string]string{"foo": "bar"},
+						""),
+					},
+				),
+			}
+
+			return &translatedIngress{
+				name: types.NamespacedName{
+					Namespace: "simplens",
+					Name:      "simplename",
+				},
+				sniMatches: []*envoy.SNIMatch{},
+				clusters: []*v3.Cluster{
+					envoy.NewCluster(
+						"servicens/servicename",
+						5*time.Second,
+						lbEndpoints,
+						true, /* http2 */
+						&envoycorev3.TransportSocket{
+							Name:       wellknown.TransportSocketTls,
+							ConfigType: typedConfig(true /* http2 */),
+						},
+						v3.Cluster_STATIC,
+					),
+				},
+				externalVirtualHosts:    vHosts,
+				externalTLSVirtualHosts: []*route.VirtualHost{},
+				internalVirtualHosts:    vHosts,
+			}
+		}(),
+	}}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			cfg := upstreamTLSConfig.DeepCopy()
+			ctx := (&testConfigStore{config: cfg}).ToContext(context.Background())
+
 			kubeclient := fake.NewSimpleClientset(test.state...)
 
 			translator := NewIngressTranslator(
@@ -775,6 +979,7 @@ func TestIngressTranslatorHTTP01Challenge(t *testing.T) {
 						5*time.Second,
 						lbEndpointHTTP01Challenge,
 						false,
+						nil,
 						v3.Cluster_STATIC,
 					),
 				},
@@ -970,4 +1175,45 @@ var (
 			"tls.key": privateKey,
 		},
 	}
+	caSecret = &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: "knative-testing",
+			Name:      "test-ca",
+		},
+		Data: map[string][]byte{
+			caDataName: cert,
+		},
+	}
 )
+
+func typedConfig(http2 bool) *envoycorev3.TransportSocket_TypedConfig {
+	alpn := []string{""}
+	if http2 {
+		alpn = []string{"h2"}
+	}
+	tlsAny, _ := anypb.New(&auth.UpstreamTlsContext{
+		CommonTlsContext: &auth.CommonTlsContext{
+			AlpnProtocols: alpn,
+			TlsParams: &auth.TlsParameters{
+				TlsMinimumProtocolVersion: auth.TlsParameters_TLSv1_2,
+			},
+			ValidationContextType: &auth.CommonTlsContext_ValidationContext{
+				ValidationContext: &auth.CertificateValidationContext{
+					TrustedCa: &envoycorev3.DataSource{
+						Specifier: &envoycorev3.DataSource_InlineBytes{
+							InlineBytes: cert,
+						},
+					},
+					MatchSubjectAltNames: []*envoymatcherv3.StringMatcher{{
+						MatchPattern: &envoymatcherv3.StringMatcher_Exact{
+							Exact: "test-san",
+						}},
+					},
+				},
+			},
+		},
+	})
+	return &envoycorev3.TransportSocket_TypedConfig{
+		TypedConfig: tlsAny,
+	}
+}
diff --git a/pkg/reconciler/ingress/config/store_test.go b/pkg/reconciler/ingress/config/store_test.go
index 10b004ce..cf762df3 100644
--- a/pkg/reconciler/ingress/config/store_test.go
+++ b/pkg/reconciler/ingress/config/store_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	"knative.dev/net-kourier/pkg/config"
+	network "knative.dev/networking/pkg"
 	logtesting "knative.dev/pkg/logging/testing"
 
 	. "knative.dev/pkg/configmap/testing"
@@ -30,7 +31,9 @@ import (
 func TestStoreLoadWithContext(t *testing.T) {
 	store := NewStore(logtesting.TestLogger(t))
 	kourierConfig := ConfigMapFromTestFile(t, config.ConfigName)
+	networkConfig := ConfigMapFromTestFile(t, network.ConfigName)
 	store.OnConfigChanged(kourierConfig)
+	store.OnConfigChanged(networkConfig)
 
 	cfg := FromContext(store.ToContext(context.Background()))
 
@@ -40,9 +43,21 @@ func TestStoreLoadWithContext(t *testing.T) {
 	}
 }
 
+func TestStoreLoadWithDefaults(t *testing.T) {
+	cfg := FromContextOrDefaults(context.Background())
+
+	if diff := cmp.Diff(config.DefaultConfig(), cfg.Kourier); diff != "" {
+		t.Errorf("Unexpected defaults config (-want, +got):\n%v", diff)
+	}
+	if diff := cmp.Diff(defaultConfig(), cfg.Network); diff != "" {
+		t.Errorf("Unexpected defaults config (-want, +got):\n%v", diff)
+	}
+}
+
 func TestStoreImmutableConfig(t *testing.T) {
 	store := NewStore(logtesting.TestLogger(t))
 	store.OnConfigChanged(ConfigMapFromTestFile(t, config.ConfigName))
+	store.OnConfigChanged(ConfigMapFromTestFile(t, network.ConfigName))
 	config := store.Load()
 
 	config.Kourier.EnableServiceAccessLogging = false
diff --git a/pkg/reconciler/ingress/config/testdata/config-network.yaml b/pkg/reconciler/ingress/config/testdata/config-network.yaml
new file mode 120000
index 00000000..69c02b68
--- /dev/null
+++ b/pkg/reconciler/ingress/config/testdata/config-network.yaml
@@ -0,0 +1,1 @@
+../../../../../vendor/knative.dev/networking/config/config-network.yaml
\ No newline at end of file
diff --git a/test/config/config-network.yaml b/test/config/config-network.yaml
new file mode 120000
index 00000000..992b252b
--- /dev/null
+++ b/test/config/config-network.yaml
@@ -0,0 +1,1 @@
+../../vendor/knative.dev/networking/config/config-network.yaml
\ No newline at end of file
diff --git a/test/config/tls/config-network.yaml b/test/config/tls/config-network.yaml
new file mode 100644
index 00000000..51c849bf
--- /dev/null
+++ b/test/config/tls/config-network.yaml
@@ -0,0 +1,26 @@
+# Copyright 2022 The Knative Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: config-network
+  namespace: knative-serving
+  labels:
+    app.kubernetes.io/name: knative-serving
+    app.kubernetes.io/version: devel
+    serving.knative.dev/release: devel
+data:
+  activator-ca: "serving-ca"
+  activator-san: "knative"
diff --git a/test/e2e-kind.sh b/test/e2e-kind.sh
index 68f33b9b..f290bb56 100755
--- a/test/e2e-kind.sh
+++ b/test/e2e-kind.sh
@@ -20,12 +20,18 @@ set -euo pipefail
 
 KOURIER_GATEWAY_NAMESPACE=kourier-system
 KOURIER_CONTROL_NAMESPACE=knative-serving
+TEST_NAMESPACE=serving-tests
 CLUSTER_SUFFIX=${CLUSTER_SUFFIX:-cluster.local}
 
 $(dirname $0)/upload-test-images.sh
 
 echo ">> Setup test resources"
 ko apply -f test/config
+if [[ $(kubectl get secret server-certs -n "${TEST_NAMESPACE}" -o name | wc -l) -eq 1 ]]; then
+  echo ">> Enable tls against upstream"
+  ko apply -f test/config/tls
+  export "UPSTREAM_TLS_CERT=server-certs"
+fi
 
 IPS=( $(kubectl get nodes -lkubernetes.io/hostname!=kind-control-plane -ojsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}') )
 
diff --git a/test/e2e-upgrade-kind.sh b/test/e2e-upgrade-kind.sh
index 510999b3..cc8cb16f 100755
--- a/test/e2e-upgrade-kind.sh
+++ b/test/e2e-upgrade-kind.sh
@@ -29,6 +29,11 @@ $(dirname $0)/upload-test-images.sh
 
 echo ">> Setup test resources"
 ko apply -f test/config
+if [[ $(kubectl get secret server-certs -n "${TEST_NAMESPACE}" -o name | wc -l) -eq 1 ]]; then
+  echo ">> Enable tls against upstream"
+  ko apply -f test/config/tls
+  export "UPSTREAM_TLS_CERT=server-certs"
+fi
 
 # Exclude the control-plane node, which doesn't seem to expose the nodeport service.
 IPS=( $(kubectl get nodes -lkubernetes.io/hostname!=kind-control-plane -ojsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}') )
diff --git a/test/generate-upstream-cert.sh b/test/generate-upstream-cert.sh
new file mode 100755
index 00000000..46472eb8
--- /dev/null
+++ b/test/generate-upstream-cert.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# Copyright 2022 The Knative Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SERVING_SYSTEM_NAMESPACE=knative-serving
+TEST_NAMESPACE=serving-tests
+out_dir="$(mktemp -d /tmp/certs-XXX)"
+san="knative"
+
+kubectl create ns $SERVING_SYSTEM_NAMESPACE
+kubectl create ns $TEST_NAMESPACE
+
+# Generate Root key and cert.
+openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=Example/CN=Example' -keyout "${out_dir}"/root.key -out "${out_dir}"/root.crt
+
+# Create server key
+openssl req -out "${out_dir}"/tls.csr -newkey rsa:2048 -nodes -keyout "${out_dir}"/tls.key -subj "/CN=Example/O=Example" -addext "subjectAltName = DNS:$san"
+
+# Create server certs
+openssl x509 -req -extfile <(printf "subjectAltName=DNS:$san") -days 365 -in "${out_dir}"/tls.csr -CA "${out_dir}"/root.crt -CAkey "${out_dir}"/root.key -CAcreateserial -out "${out_dir}"/tls.crt
+
+# Create secret
+kubectl create -n ${SERVING_SYSTEM_NAMESPACE} secret generic serving-ca \
+    --from-file=ca.crt="${out_dir}"/root.crt --dry-run=client -o yaml | kubectl apply -f -
+
+kubectl create -n ${TEST_NAMESPACE} secret tls server-certs \
+    --key="${out_dir}"/tls.key \
+    --cert="${out_dir}"/tls.crt --dry-run=client -o yaml | kubectl apply -f -