Repository: linkerd/linkerd2
Pull request #5840 (2021-02-26 22:38:51)

Fix Helm chart not setting the proxy-version annotation
In #5694 we set many Helm values to empty (like version tags), and then the
templates became responsible to filling out to proper default values. We missed
doing that for the `linkerd.io/proxy-version` annotation built in the
`_metadata.tpl` template. This fixes that, and also stops setting
`proxy.image.version` in `helm install|upgrade` in the Helm integration tests,
which is what avoided catching this error .

kleimkuhler: And thanks for fixing this in the tests. I was wondering how that got through.

Patch:
diff --git a/charts/linkerd2/templates/controller.yaml b/charts/linkerd2/templates/controller.yaml
index 791989503..1c1ad9abf 100644
--- a/charts/linkerd2/templates/controller.yaml
+++ b/charts/linkerd2/templates/controller.yaml
@@ -72,7 +72,7 @@ spec:
     metadata:
       annotations:
         {{ include "partials.annotations.created-by" . }}
-        {{- include "partials.proxy.annotations" .Values.proxy| nindent 8}}
+        {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/control-plane-component: controller
diff --git a/charts/linkerd2/templates/destination.yaml b/charts/linkerd2/templates/destination.yaml
index 21bec1dcc..37a3709cb 100644
--- a/charts/linkerd2/templates/destination.yaml
+++ b/charts/linkerd2/templates/destination.yaml
@@ -91,7 +91,7 @@ spec:
     metadata:
       annotations:
         {{ include "partials.annotations.created-by" . }}
-        {{- include "partials.proxy.annotations" .Values.proxy| nindent 8}}
+        {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/control-plane-component: destination
@@ -119,6 +119,7 @@ spec:
         - -enable-endpoint-slices={{.Values.enableEndpointSlices}}
         - -cluster-domain={{.Values.clusterDomain}}
         - -identity-trust-domain={{.Values.identityTrustDomain | default .Values.clusterDomain}}
+        - -default-opaque-ports={{.Values.proxy.opaquePorts}}
         {{- include "partials.linkerd.trace" . | nindent 8 -}}
         image: {{.Values.controllerImage}}:{{default .Values.linkerdVersion .Values.controllerImageVersion}}
         imagePullPolicy: {{.Values.imagePullPolicy}}
diff --git a/charts/linkerd2/templates/identity.yaml b/charts/linkerd2/templates/identity.yaml
index 2492efa8e..5578e9f07 100644
--- a/charts/linkerd2/templates/identity.yaml
+++ b/charts/linkerd2/templates/identity.yaml
@@ -110,7 +110,7 @@ spec:
     metadata:
       annotations:
         {{ include "partials.annotations.created-by" . }}
-        {{- include "partials.proxy.annotations" .Values.proxy| nindent 8}}
+        {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/control-plane-component: identity
diff --git a/charts/linkerd2/templates/proxy-injector.yaml b/charts/linkerd2/templates/proxy-injector.yaml
index 0ec351109..26ad212ce 100644
--- a/charts/linkerd2/templates/proxy-injector.yaml
+++ b/charts/linkerd2/templates/proxy-injector.yaml
@@ -36,7 +36,7 @@ spec:
         checksum/config: {{ include (print $.Template.BasePath "/proxy-injector-rbac.yaml") . | sha256sum }}
         {{- end }}
         {{ include "partials.annotations.created-by" . }}
-        {{- include "partials.proxy.annotations" .Values.proxy| nindent 8}}
+        {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/control-plane-component: proxy-injector
diff --git a/charts/linkerd2/templates/sp-validator.yaml b/charts/linkerd2/templates/sp-validator.yaml
index bff04477a..39589c11c 100644
--- a/charts/linkerd2/templates/sp-validator.yaml
+++ b/charts/linkerd2/templates/sp-validator.yaml
@@ -73,7 +73,7 @@ spec:
         checksum/config: {{ include (print $.Template.BasePath "/sp-validator-rbac.yaml") . | sha256sum }}
         {{- end }}
         {{ include "partials.annotations.created-by" . }}
-        {{- include "partials.proxy.annotations" .Values.proxy| nindent 8}}
+        {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
       labels:
         linkerd.io/control-plane-component: sp-validator
diff --git a/charts/partials/templates/_metadata.tpl b/charts/partials/templates/_metadata.tpl
index 637afed32..7cf074458 100644
--- a/charts/partials/templates/_metadata.tpl
+++ b/charts/partials/templates/_metadata.tpl
@@ -3,8 +3,8 @@ linkerd.io/created-by: {{ .Values.cliVersion | default (printf "linkerd/helm %s"
 {{- end -}}
 
 {{- define "partials.proxy.annotations" -}}
-linkerd.io/identity-mode: {{ternary "default" "disabled" (not .disableIdentity)}}
-linkerd.io/proxy-version: {{.image.version}}
+linkerd.io/identity-mode: {{ternary "default" "disabled" (not .Values.proxy.disableIdentity)}}
+linkerd.io/proxy-version: {{.Values.proxy.image.version | default .Values.linkerdVersion}}
 {{- end -}}
 
 {{/*
diff --git a/controller/api/destination/endpoint_translator.go b/controller/api/destination/endpoint_translator.go
index 3a849da1d..3fb4b6648 100644
--- a/controller/api/destination/endpoint_translator.go
+++ b/controller/api/destination/endpoint_translator.go
@@ -10,7 +10,6 @@ import (
 	"github.com/linkerd/linkerd2/controller/api/destination/watcher"
 	"github.com/linkerd/linkerd2/pkg/addr"
 	"github.com/linkerd/linkerd2/pkg/k8s"
-	"github.com/linkerd/linkerd2/pkg/opaqueports"
 	logging "github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
 	coreinformers "k8s.io/client-go/informers/core/v1"
@@ -30,6 +29,7 @@ type endpointTranslator struct {
 	identityTrustDomain string
 	enableH2Upgrade     bool
 	nodeTopologyLabels  map[string]string
+	defaultOpaquePorts  map[uint32]struct{}
 
 	availableEndpoints watcher.AddressSet
 	filteredSnapshot   watcher.AddressSet
@@ -43,6 +43,7 @@ func newEndpointTranslator(
 	enableH2Upgrade bool,
 	service string,
 	srcNodeName string,
+	defaultOpaquePorts map[uint32]struct{},
 	nodes coreinformers.NodeInformer,
 	stream pb.Destination_GetServer,
 	log *logging.Entry,
@@ -65,6 +66,7 @@ func newEndpointTranslator(
 		identityTrustDomain,
 		enableH2Upgrade,
 		nodeTopologyLabels,
+		defaultOpaquePorts,
 		availableEndpoints,
 		filteredSnapshot,
 		stream,
@@ -221,7 +223,7 @@ func (et *endpointTranslator) sendClientAdd(set watcher.AddressSet) {
 			// If the opaque ports annotation was not set, then set the
 			// endpoint's opaque ports to the default value.
 			if !ok {
-				opaquePorts = opaqueports.DefaultOpaquePorts
+				opaquePorts = et.defaultOpaquePorts
 			}
 			wa, err = toWeightedAddr(address, opaquePorts, et.enableH2Upgrade, et.identityTrustDomain, et.controllerNS, et.log)
 		} else {
diff --git a/controller/api/destination/server.go b/controller/api/destination/server.go
index 34ab39d77..da0e8b50c 100644
--- a/controller/api/destination/server.go
+++ b/controller/api/destination/server.go
@@ -12,7 +12,6 @@ import (
 	sp "github.com/linkerd/linkerd2/controller/gen/apis/serviceprofile/v1alpha2"
 	"github.com/linkerd/linkerd2/controller/k8s"
 	labels "github.com/linkerd/linkerd2/pkg/k8s"
-	"github.com/linkerd/linkerd2/pkg/opaqueports"
 	"github.com/linkerd/linkerd2/pkg/prometheus"
 	"github.com/linkerd/linkerd2/pkg/util"
 	logging "github.com/sirupsen/logrus"
@@ -37,6 +36,7 @@ type (
 		controllerNS        string
 		identityTrustDomain string
 		clusterDomain       string
+		defaultOpaquePorts  map[uint32]struct{}
 
 		k8sAPI   *k8s.API
 		log      *logging.Entry
@@ -64,14 +64,16 @@ func NewServer(
 	enableEndpointSlices bool,
 	k8sAPI *k8s.API,
 	clusterDomain string,
+	defaultOpaquePorts map[uint32]struct{},
 	shutdown <-chan struct{},
 ) *grpc.Server {
 	log := logging.WithFields(logging.Fields{
 		"addr":      addr,
 		"component": "server",
 	})
+
 	endpoints := watcher.NewEndpointsWatcher(k8sAPI, log, enableEndpointSlices)
-	opaquePorts := watcher.NewOpaquePortsWatcher(k8sAPI, log)
+	opaquePorts := watcher.NewOpaquePortsWatcher(k8sAPI, log, defaultOpaquePorts)
 	profiles := watcher.NewProfileWatcher(k8sAPI, log)
 	trafficSplits := watcher.NewTrafficSplitWatcher(k8sAPI, log)
 	ips := watcher.NewIPWatcher(k8sAPI, endpoints, log)
@@ -87,6 +89,7 @@ func NewServer(
 		controllerNS,
 		identityTrustDomain,
 		clusterDomain,
+		defaultOpaquePorts,
 		k8sAPI,
 		log,
 		shutdown,
@@ -118,6 +121,7 @@ func (s *server) Get(dest *pb.GetDestination, stream pb.Destination_GetServer) e
 		s.enableH2Upgrade,
 		dest.GetPath(),
 		token.NodeName,
+		s.defaultOpaquePorts,
 		s.nodes,
 		stream,
 		log,
@@ -225,7 +229,7 @@ func (s *server) GetProfile(dest *pb.GetDestination, stream pb.Destination_GetPr
 				// If the opaque ports annotation was not set, then set the
 				// endpoint's opaque ports to the default value.
 				if !ok {
-					opaquePorts = opaqueports.DefaultOpaquePorts
+					opaquePorts = s.defaultOpaquePorts
 				}
 				endpoint, err = toWeightedAddr(podSet.Addresses[podID], opaquePorts, s.enableH2Upgrade, s.identityTrustDomain, s.controllerNS, log)
 				if err != nil {
diff --git a/controller/api/destination/watcher/opaque_ports_watcher.go b/controller/api/destination/watcher/opaque_ports_watcher.go
index 33a45304a..02b828085 100644
--- a/controller/api/destination/watcher/opaque_ports_watcher.go
+++ b/controller/api/destination/watcher/opaque_ports_watcher.go
@@ -7,7 +7,6 @@ import (
 	"github.com/linkerd/linkerd2-proxy-init/ports"
 	"github.com/linkerd/linkerd2/controller/k8s"
 	labels "github.com/linkerd/linkerd2/pkg/k8s"
-	"github.com/linkerd/linkerd2/pkg/opaqueports"
 	"github.com/linkerd/linkerd2/pkg/util"
 	log "github.com/sirupsen/logrus"
 	logging "github.com/sirupsen/logrus"
@@ -20,9 +19,10 @@ type (
 	// opaque ports annotation is added to a service, the watcher will update
 	// listeners—if any—subscribed to that service.
 	OpaquePortsWatcher struct {
-		subscriptions map[ServiceID]*svcSubscriptions
-		k8sAPI        *k8s.API
-		log           *logging.Entry
+		subscriptions      map[ServiceID]*svcSubscriptions
+		k8sAPI             *k8s.API
+		log                *logging.Entry
+		defaultOpaquePorts map[uint32]struct{}
 		sync.RWMutex
 	}
 
@@ -39,11 +39,12 @@ type (
 
 // NewOpaquePortsWatcher creates a OpaquePortsWatcher and begins watching for
 // k8sAPI for service changes.
-func NewOpaquePortsWatcher(k8sAPI *k8s.API, log *logging.Entry) *OpaquePortsWatcher {
+func NewOpaquePortsWatcher(k8sAPI *k8s.API, log *logging.Entry, opaquePorts map[uint32]struct{}) *OpaquePortsWatcher {
 	opw := &OpaquePortsWatcher{
-		subscriptions: make(map[ServiceID]*svcSubscriptions),
-		k8sAPI:        k8sAPI,
-		log:           log.WithField("component", "opaque-ports-watcher"),
+		subscriptions:      make(map[ServiceID]*svcSubscriptions),
+		k8sAPI:             k8sAPI,
+		log:                log.WithField("component", "opaque-ports-watcher"),
+		defaultOpaquePorts: opaquePorts,
 	}
 	k8sAPI.Svc().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
 		AddFunc:    opw.addService,
@@ -69,7 +70,7 @@ func (opw *OpaquePortsWatcher) Subscribe(id ServiceID, listener OpaquePortsUpdat
 	// and no opaque ports
 	if !ok {
 		opw.subscriptions[id] = &svcSubscriptions{
-			opaquePorts: opaqueports.DefaultOpaquePorts,
+			opaquePorts: opw.defaultOpaquePorts,
 			listeners:   []OpaquePortsUpdateListener{listener},
 		}
 		return nil
@@ -121,7 +122,7 @@ func (opw *OpaquePortsWatcher) addService(obj interface{}) {
 	// If the opaque ports annotation was not set, then set the service's
 	// opaque ports to the default value.
 	if !ok {
-		opaquePorts = opaqueports.DefaultOpaquePorts
+		opaquePorts = opw.defaultOpaquePorts
 	}
 	ss, ok := opw.subscriptions[id]
 	// If there are no subscriptions for this service, create one with the
@@ -172,7 +173,7 @@ func (opw *OpaquePortsWatcher) deleteService(obj interface{}) {
 		return
 	}
 	old := ss.opaquePorts
-	ss.opaquePorts = opaqueports.DefaultOpaquePorts
+	ss.opaquePorts = opw.defaultOpaquePorts
 	// Do not send an update if the service already had the default opaque ports
 	if portsEqual(old, ss.opaquePorts) {
 		return
diff --git a/controller/cmd/destination/main.go b/controller/cmd/destination/main.go
index 02ff3ae9f..197d33886 100644
--- a/controller/cmd/destination/main.go
+++ b/controller/cmd/destination/main.go
@@ -14,6 +14,7 @@ import (
 	"github.com/linkerd/linkerd2/pkg/flags"
 	pkgK8s "github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/pkg/trace"
+	"github.com/linkerd/linkerd2/pkg/util"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -30,6 +31,8 @@ func Main(args []string) {
 	enableEndpointSlices := cmd.Bool("enable-endpoint-slices", false, "Enable the usage of EndpointSlice informers and resources")
 	trustDomain := cmd.String("identity-trust-domain", "", "configures the name suffix used for identities")
 	clusterDomain := cmd.String("cluster-domain", "", "kubernetes cluster domain")
+	defaultOpaquePorts := cmd.String("default-opaque-ports", "", "configures the default opaque ports")
+
 	traceCollector := flags.AddTraceFlags(cmd)
 
 	flags.ConfigureAndParse(cmd, args)
@@ -58,6 +61,13 @@ func Main(args []string) {
 		log.Warnf("expected cluster domain through args (falling back to %s)", *clusterDomain)
 	}
 
+	opaquePorts, err := util.ParsePorts(*defaultOpaquePorts)
+	if err != nil {
+		log.Fatalf("Failed to parse opaque Ports %s: %s", *defaultOpaquePorts, err)
+	}
+
+	log.Infof("Using default opaque ports: %v", opaquePorts)
+
 	if *traceCollector != "" {
 		if err := trace.InitializeTracing("linkerd-destination", *traceCollector); err != nil {
 			log.Warnf("failed to initialize tracing: %s", err)
@@ -106,6 +116,7 @@ func Main(args []string) {
 		*enableEndpointSlices,
 		k8sAPI,
 		*clusterDomain,
+		opaquePorts,
 		done,
 	)
 
diff --git a/pkg/opaqueports/defaults.go b/pkg/opaqueports/defaults.go
deleted file mode 100644
index 11b142553..000000000
--- a/pkg/opaqueports/defaults.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package opaqueports
-
-// DefaultOpaquePorts is the default list of opaque ports that the destination
-// server will use to determine whether a destination is an opaque protocol.
-// When a pod or service already has its own annotation, that value will have
-// priority of this.
-//
-// Note: Keep in sync with proxy.opaquePorts in values.yaml
-var DefaultOpaquePorts = map[uint32]struct{}{
-	25:    {},
-	443:   {},
-	587:   {},
-	3306:  {},
-	5432:  {},
-	11211: {},
-}
diff --git a/pkg/util/parsing.go b/pkg/util/parsing.go
index 7f1fba0a0..4ee6de48c 100644
--- a/pkg/util/parsing.go
+++ b/pkg/util/parsing.go
@@ -10,6 +10,28 @@ import (
 	corev1 "k8s.io/api/core/v1"
 )
 
+// ParsePorts parses the given ports string into a map of ports;
+// this includes converting port ranges into separate ports
+func ParsePorts(portsString string) (map[uint32]struct{}, error) {
+	opaquePorts := make(map[uint32]struct{})
+	if portsString != "" {
+		portRanges := GetPortRanges(portsString)
+		for _, portRange := range portRanges {
+			pr := portRange.GetPortRange()
+			portsRange, err := ports.ParsePortRange(pr)
+			if err != nil {
+				log.Warnf("Invalid port range [%v]: %s", pr, err)
+				continue
+			}
+			for i := portsRange.LowerBound; i <= portsRange.UpperBound; i++ {
+				opaquePorts[uint32(i)] = struct{}{}
+			}
+
+		}
+	}
+	return opaquePorts, nil
+}
+
 // ParseContainerOpaquePorts parses the opaque ports annotation into a list of ports;
 // this includes converting port ranges into separate ports and named ports
 // into their port number equivalents.
diff --git a/viz/pkg/healthcheck/healthcheck.go b/viz/pkg/healthcheck/healthcheck.go
index 2d94000c0..3417d6d69 100644
--- a/viz/pkg/healthcheck/healthcheck.go
+++ b/viz/pkg/healthcheck/healthcheck.go
@@ -212,7 +212,7 @@ func (hc *HealthChecker) VizCategory() healthcheck.Category {
 				return
 			}),
 		*healthcheck.NewChecker("viz extension self-check").
-			WithHintAnchor("l5d-api-control-api").
+			WithHintAnchor("l5d-viz-metrics-api").
 			Fatal().
 			// to avoid confusing users with a prometheus readiness error, we only show
 			// "waiting for check to complete" while things converge. If after the timeout


Test patch:
diff --git a/cli/cmd/install_test.go b/cli/cmd/install_test.go
index f4c790c3a..5ee4f0978 100644
--- a/cli/cmd/install_test.go
+++ b/cli/cmd/install_test.go
@@ -78,7 +78,8 @@ func TestRender(t *testing.T) {
 				Inbound:  4143,
 				Outbound: 4140,
 			},
-			UID: 2102,
+			UID:         2102,
+			OpaquePorts: "25,443,587,3306,5432,11211",
 		},
 		ProxyInit: &charts.ProxyInit{
 			Image: &charts.Image{
diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden
index b67acbe96..deb04f448 100644
--- a/cli/cmd/testdata/install_controlplane_tracing_output.golden
+++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden
@@ -1619,6 +1619,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         - -trace-collector=collector.linkerd-jaeger.svc.cluster.local:55678
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
diff --git a/cli/cmd/testdata/install_custom_domain.golden b/cli/cmd/testdata/install_custom_domain.golden
index 6da98a44a..18524aa90 100644
--- a/cli/cmd/testdata/install_custom_domain.golden
+++ b/cli/cmd/testdata/install_custom_domain.golden
@@ -1617,6 +1617,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden
index 71e1e2718..104711aa4 100644
--- a/cli/cmd/testdata/install_custom_registry.golden
+++ b/cli/cmd/testdata/install_custom_registry.golden
@@ -1617,6 +1617,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: my.custom.registry/linkerd-io/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 811a82bc9..94649d6d9 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -1617,6 +1617,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_default_override_dst_get_nets.golden b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
index 37c2b3bfa..93d971b1b 100644
--- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden
+++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
@@ -1617,6 +1617,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index 943372ff1..6ea3bd78a 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -1792,6 +1792,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index 7f21547f3..e457b3ce5 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -1792,6 +1792,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_heartbeat_disabled_output.golden b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
index 991aa9d41..3ac825c96 100644
--- a/cli/cmd/testdata/install_heartbeat_disabled_output.golden
+++ b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
@@ -1545,6 +1545,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_helm_output.golden b/cli/cmd/testdata/install_helm_output.golden
index 923177b0c..4c3c01cc6 100644
--- a/cli/cmd/testdata/install_helm_output.golden
+++ b/cli/cmd/testdata/install_helm_output.golden
@@ -1603,6 +1603,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_helm_output_ha.golden b/cli/cmd/testdata/install_helm_output_ha.golden
index 8135f2b5f..dcd81da22 100644
--- a/cli/cmd/testdata/install_helm_output_ha.golden
+++ b/cli/cmd/testdata/install_helm_output_ha.golden
@@ -1778,6 +1778,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_helm_output_ha_labels.golden b/cli/cmd/testdata/install_helm_output_ha_labels.golden
index c053d9d61..75cc3ead9 100644
--- a/cli/cmd/testdata/install_helm_output_ha_labels.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_labels.golden
@@ -1794,6 +1794,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
index 03682e791..47dd4fc3c 100644
--- a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
@@ -1778,6 +1778,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index 7345bccd2..95bb08791 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -1538,6 +1538,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index 2a02b20cd..e79feddbb 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -966,7 +966,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: ""
+      opaquePorts: 25,443,587,3306,5432,11211
       outboundConnectTimeout: ""
       ports:
         admin: 4191
@@ -1177,6 +1177,8 @@ spec:
           value: 10000ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
+        - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+          value: "25,443,587,3306,5432,11211"
         - name: _pod_ns
           valueFrom:
             fieldRef:
@@ -1409,6 +1411,8 @@ spec:
           value: 10000ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
+        - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+          value: "25,443,587,3306,5432,11211"
         - name: _pod_ns
           valueFrom:
             fieldRef:
@@ -1617,6 +1621,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: ControllerImage:ControllerImageVersion
         imagePullPolicy: ImagePullPolicy
         livenessProbe:
@@ -1660,6 +1665,8 @@ spec:
           value: 10000ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
+        - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+          value: "25,443,587,3306,5432,11211"
         - name: _pod_ns
           valueFrom:
             fieldRef:
@@ -1921,6 +1928,8 @@ spec:
           value: 10000ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
+        - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+          value: "25,443,587,3306,5432,11211"
         - name: _pod_ns
           valueFrom:
             fieldRef:
@@ -2175,6 +2184,8 @@ spec:
           value: 10000ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
+        - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
+          value: "25,443,587,3306,5432,11211"
         - name: _pod_ns
           valueFrom:
             fieldRef:
@@ -2302,7 +2313,7 @@ spec:
 ---
 apiVersion: v1
 data:
-  linkerd-config-overrides: Y2xpVmVyc2lvbjogQ2xpVmVyc2lvbgpjbHVzdGVyTmV0d29ya3M6IENsdXN0ZXJOZXR3b3Jrcwpjb250cm9sUGxhbmVUcmFjaW5nTmFtZXNwYWNlOiAiIgpjb250cm9sbGVySW1hZ2U6IENvbnRyb2xsZXJJbWFnZQpjb250cm9sbGVySW1hZ2VWZXJzaW9uOiBDb250cm9sbGVySW1hZ2VWZXJzaW9uCmNvbnRyb2xsZXJMb2dGb3JtYXQ6IENvbnRyb2xsZXJMb2dGb3JtYXQKY29udHJvbGxlckxvZ0xldmVsOiBDb250cm9sbGVyTG9nTGV2ZWwKZGVidWdDb250YWluZXI6CiAgaW1hZ2U6CiAgICBuYW1lOiBEZWJ1Z0ltYWdlTmFtZQogICAgcHVsbFBvbGljeTogRGVidWdJbWFnZVB1bGxQb2xpY3kKICAgIHZlcnNpb246IERlYnVnVmVyc2lvbgpoZWFydGJlYXRTY2hlZHVsZTogIiIKaWRlbnRpdHk6CiAgaXNzdWVyOgogICAgY3J0RXhwaXJ5OiAiMjAzMC0wOC0yNlQwNzoxMzo0N1oiCiAgICB0bHM6CiAgICAgIGNydFBFTTogfAogICAgICAgIC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQogICAgICAgIE1JSUJ3RENDQVdlZ0F3SUJBZ0lSQUpSSWdaOFJ0TzhFd2cxWGVwZjhUNDR3Q2dZSUtvWkl6ajBFQXdJd0tURW4KICAgICAgICBNQ1VHQTFVRUF4TWVhV1JsYm5ScGRIa3ViR2x1YTJWeVpDNWpiSFZ6ZEdWeUxteHZZMkZzTUI0WERUSXdNRGd5CiAgICAgICAgT0RBM01UTTBOMW9YRFRNd01EZ3lOakEzTVRNME4xb3dLVEVuTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdQogICAgICAgIGEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTEvRnAKICAgICAgICBmY1JuRGNlZEw2QWpVYVhZUHY0RElNQmFKdWZPSTVOV3R5K1hTWDdKalhnWnRNNzJkUXZSYVlhbnV4RDM2RHQxCiAgICAgICAgMi9KeHlpU2d4S1dSZG9heSthTndNRzR3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQgogICAgICAgIEFmOENBUUF3SFFZRFZSME9CQllFRkkxV25ycU1ZS2FISE9vK3pweWlpRHEycE8wS01Da0dBMVVkRVFRaU1DQ0MKICAgICAgICBIbWxrWlc1MGFYUjVMbXhwYm10bGNtUXVZMngxYzNSbGNpNXNiMk5oYkRBS0JnZ3Foa2pPUFFRREFnTkhBREJFCiAgICAgICAgQWlBdHVvSTVYdUN0ckdWUnpTbVJUbDJyYTI4YVY5TXlUVTdkNXFuVEFGSEtTZ0lnUktDdmx1T1NnQTVPMjFwNQogICAgICAgIDUxdGRybWtIRVpScjBxbExTSmRIWWdFZk16az0KICAgICAgICAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiAgICAgIGtleVBFTTogfAogICAgICAgIC0tLS0tQkVHSU4gRUMgUFJJVkFURSBLRVktLS0tLQogICAgICAgIE1IY0NBUUVFSUFBZThuZmJ6WnU5Yy9PQjIrOHhKTTBGejdOVXdUUWF6dWxrRk5zNFRJNStvQW9HQ0NxR1NNNDkKICAgICAgICBBd0VIb1VRRFFnQUUxL0ZwZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyCiAgICAgICAgZFF2UmFZYW51eEQzNkR0MTIvSnh5aVNneEtXUmRvYXkrUT09CiAgICAgICAgLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQppZGVudGl0eVRydXN0QW5jaG9yc1BFTTogfAogIC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQogIE1JSUJ3VENDQVdhZ0F3SUJBZ0lRZURacDVsRGFJeWdRNVVmTUtackZBVEFLQmdncWhrak9QUVFEQWpBcE1TY3cKICBKUVlEVlFRREV4NXBaR1Z1ZEdsMGVTNXNhVzVyWlhKa0xtTnNkWE4wWlhJdWJHOWpZV3d3SGhjTk1qQXdPREk0CiAgTURjeE1qUTNXaGNOTXpBd09ESTJNRGN4TWpRM1dqQXBNU2N3SlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1cgogIFpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFScWM3MFoKICBsMXZndzc5cmpCNXVTSVRJQ1VBNkd5ZnZTRmZjdUlpczdCL1hGU2trd0FIVTVTL3MxQUFQK1IwVFg3SEJXVUM0CiAgdWFHNFdXc2l3SktObjdtZ28zQXdiakFPQmdOVkhROEJBZjhFQkFNQ0FRWXdFZ1lEVlIwVEFRSC9CQWd3QmdFQgogIC93SUJBVEFkQmdOVkhRNEVGZ1FVNVl0alZWUGZkN0k3TkxIc24yQzI2RUJ5R1Ywd0tRWURWUjBSQkNJd0lJSWUKICBhV1JsYm5ScGRIa3ViR2x1YTJWeVpDNWpiSFZ6ZEdWeUxteHZZMkZzTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCiAgSVFDTjdsQkZMRER2ang2VjArWGtqcEtFUlJzSllmNWFkTXZubG9GbDQ4aWxKZ0loQU50eGhuZGNyK1FKUHVDOAogIHZnVUMwZDIvOUZNdWVJVk1iKzQ2V1RDT2pzcXIKICAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCmltYWdlUHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CmltYWdlUHVsbFNlY3JldHM6IG51bGwKbGlua2VyZFZlcnNpb246ICIiCnByb2ZpbGVWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHByb2ZpbGUgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJvZmlsZSB2YWxpZGF0b3IgY3J0CiAga2V5UEVNOiBwcm9maWxlIHZhbGlkYXRvciBrZXkKcHJveHk6CiAgaW1hZ2U6CiAgICBuYW1lOiBQcm94eUltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQcm94eVZlcnNpb24KICBpbmJvdW5kQ29ubmVjdFRpbWVvdXQ6ICIiCiAgb3BhcXVlUG9ydHM6ICIiCiAgb3V0Ym91bmRDb25uZWN0VGltZW91dDogIiIKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIGxpbWl0OiBjcHUtbGltaXQKICAgICAgcmVxdWVzdDogY3B1LXJlcXVlc3QKICAgIG1lbW9yeToKICAgICAgbGltaXQ6IG1lbW9yeS1saW1pdAogICAgICByZXF1ZXN0OiBtZW1vcnktcmVxdWVzdApwcm94eUNvbnRhaW5lck5hbWU6IFByb3h5Q29udGFpbmVyTmFtZQpwcm94eUluaXQ6CiAgaWdub3JlT3V0Ym91bmRQb3J0czogIjQ0MyIKICBpbWFnZToKICAgIG5hbWU6IFByb3h5SW5pdEltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQcm94eUluaXRWZXJzaW9uCnByb3h5SW5qZWN0b3I6CiAgY2FCdW5kbGU6IHByb3h5IGluamVjdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJveHkgaW5qZWN0b3IgY3J0CiAga2V5UEVNOiBwcm94eSBpbmplY3RvciBrZXkKd2ViaG9va0ZhaWx1cmVQb2xpY3k6IFdlYmhvb2tGYWlsdXJlUG9saWN5Cg==
+  linkerd-config-overrides: Y2xpVmVyc2lvbjogQ2xpVmVyc2lvbgpjbHVzdGVyTmV0d29ya3M6IENsdXN0ZXJOZXR3b3Jrcwpjb250cm9sUGxhbmVUcmFjaW5nTmFtZXNwYWNlOiAiIgpjb250cm9sbGVySW1hZ2U6IENvbnRyb2xsZXJJbWFnZQpjb250cm9sbGVySW1hZ2VWZXJzaW9uOiBDb250cm9sbGVySW1hZ2VWZXJzaW9uCmNvbnRyb2xsZXJMb2dGb3JtYXQ6IENvbnRyb2xsZXJMb2dGb3JtYXQKY29udHJvbGxlckxvZ0xldmVsOiBDb250cm9sbGVyTG9nTGV2ZWwKZGVidWdDb250YWluZXI6CiAgaW1hZ2U6CiAgICBuYW1lOiBEZWJ1Z0ltYWdlTmFtZQogICAgcHVsbFBvbGljeTogRGVidWdJbWFnZVB1bGxQb2xpY3kKICAgIHZlcnNpb246IERlYnVnVmVyc2lvbgpoZWFydGJlYXRTY2hlZHVsZTogIiIKaWRlbnRpdHk6CiAgaXNzdWVyOgogICAgY3J0RXhwaXJ5OiAiMjAzMC0wOC0yNlQwNzoxMzo0N1oiCiAgICB0bHM6CiAgICAgIGNydFBFTTogfAogICAgICAgIC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQogICAgICAgIE1JSUJ3RENDQVdlZ0F3SUJBZ0lSQUpSSWdaOFJ0TzhFd2cxWGVwZjhUNDR3Q2dZSUtvWkl6ajBFQXdJd0tURW4KICAgICAgICBNQ1VHQTFVRUF4TWVhV1JsYm5ScGRIa3ViR2x1YTJWeVpDNWpiSFZ6ZEdWeUxteHZZMkZzTUI0WERUSXdNRGd5CiAgICAgICAgT0RBM01UTTBOMW9YRFRNd01EZ3lOakEzTVRNME4xb3dLVEVuTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdQogICAgICAgIGEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTEvRnAKICAgICAgICBmY1JuRGNlZEw2QWpVYVhZUHY0RElNQmFKdWZPSTVOV3R5K1hTWDdKalhnWnRNNzJkUXZSYVlhbnV4RDM2RHQxCiAgICAgICAgMi9KeHlpU2d4S1dSZG9heSthTndNRzR3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQgogICAgICAgIEFmOENBUUF3SFFZRFZSME9CQllFRkkxV25ycU1ZS2FISE9vK3pweWlpRHEycE8wS01Da0dBMVVkRVFRaU1DQ0MKICAgICAgICBIbWxrWlc1MGFYUjVMbXhwYm10bGNtUXVZMngxYzNSbGNpNXNiMk5oYkRBS0JnZ3Foa2pPUFFRREFnTkhBREJFCiAgICAgICAgQWlBdHVvSTVYdUN0ckdWUnpTbVJUbDJyYTI4YVY5TXlUVTdkNXFuVEFGSEtTZ0lnUktDdmx1T1NnQTVPMjFwNQogICAgICAgIDUxdGRybWtIRVpScjBxbExTSmRIWWdFZk16az0KICAgICAgICAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiAgICAgIGtleVBFTTogfAogICAgICAgIC0tLS0tQkVHSU4gRUMgUFJJVkFURSBLRVktLS0tLQogICAgICAgIE1IY0NBUUVFSUFBZThuZmJ6WnU5Yy9PQjIrOHhKTTBGejdOVXdUUWF6dWxrRk5zNFRJNStvQW9HQ0NxR1NNNDkKICAgICAgICBBd0VIb1VRRFFnQUUxL0ZwZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyCiAgICAgICAgZFF2UmFZYW51eEQzNkR0MTIvSnh5aVNneEtXUmRvYXkrUT09CiAgICAgICAgLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQppZGVudGl0eVRydXN0QW5jaG9yc1BFTTogfAogIC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQogIE1JSUJ3VENDQVdhZ0F3SUJBZ0lRZURacDVsRGFJeWdRNVVmTUtackZBVEFLQmdncWhrak9QUVFEQWpBcE1TY3cKICBKUVlEVlFRREV4NXBaR1Z1ZEdsMGVTNXNhVzVyWlhKa0xtTnNkWE4wWlhJdWJHOWpZV3d3SGhjTk1qQXdPREk0CiAgTURjeE1qUTNXaGNOTXpBd09ESTJNRGN4TWpRM1dqQXBNU2N3SlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1cgogIFpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFScWM3MFoKICBsMXZndzc5cmpCNXVTSVRJQ1VBNkd5ZnZTRmZjdUlpczdCL1hGU2trd0FIVTVTL3MxQUFQK1IwVFg3SEJXVUM0CiAgdWFHNFdXc2l3SktObjdtZ28zQXdiakFPQmdOVkhROEJBZjhFQkFNQ0FRWXdFZ1lEVlIwVEFRSC9CQWd3QmdFQgogIC93SUJBVEFkQmdOVkhRNEVGZ1FVNVl0alZWUGZkN0k3TkxIc24yQzI2RUJ5R1Ywd0tRWURWUjBSQkNJd0lJSWUKICBhV1JsYm5ScGRIa3ViR2x1YTJWeVpDNWpiSFZ6ZEdWeUxteHZZMkZzTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCiAgSVFDTjdsQkZMRER2ang2VjArWGtqcEtFUlJzSllmNWFkTXZubG9GbDQ4aWxKZ0loQU50eGhuZGNyK1FKUHVDOAogIHZnVUMwZDIvOUZNdWVJVk1iKzQ2V1RDT2pzcXIKICAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCmltYWdlUHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CmltYWdlUHVsbFNlY3JldHM6IG51bGwKbGlua2VyZFZlcnNpb246ICIiCnByb2ZpbGVWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHByb2ZpbGUgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJvZmlsZSB2YWxpZGF0b3IgY3J0CiAga2V5UEVNOiBwcm9maWxlIHZhbGlkYXRvciBrZXkKcHJveHk6CiAgaW1hZ2U6CiAgICBuYW1lOiBQcm94eUltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQcm94eVZlcnNpb24KICBpbmJvdW5kQ29ubmVjdFRpbWVvdXQ6ICIiCiAgb3V0Ym91bmRDb25uZWN0VGltZW91dDogIiIKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIGxpbWl0OiBjcHUtbGltaXQKICAgICAgcmVxdWVzdDogY3B1LXJlcXVlc3QKICAgIG1lbW9yeToKICAgICAgbGltaXQ6IG1lbW9yeS1saW1pdAogICAgICByZXF1ZXN0OiBtZW1vcnktcmVxdWVzdApwcm94eUNvbnRhaW5lck5hbWU6IFByb3h5Q29udGFpbmVyTmFtZQpwcm94eUluaXQ6CiAgaWdub3JlT3V0Ym91bmRQb3J0czogIjQ0MyIKICBpbWFnZToKICAgIG5hbWU6IFByb3h5SW5pdEltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQcm94eUluaXRWZXJzaW9uCnByb3h5SW5qZWN0b3I6CiAgY2FCdW5kbGU6IHByb3h5IGluamVjdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJveHkgaW5qZWN0b3IgY3J0CiAga2V5UEVNOiBwcm94eSBpbmplY3RvciBrZXkKd2ViaG9va0ZhaWx1cmVQb2xpY3k6IFdlYmhvb2tGYWlsdXJlUG9saWN5Cg==
 kind: Secret
 metadata:
   creationTimestamp: null
diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden
index bd162b8f6..787e1eeb0 100644
--- a/cli/cmd/testdata/install_proxy_ignores.golden
+++ b/cli/cmd/testdata/install_proxy_ignores.golden
@@ -1617,6 +1617,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/cli/cmd/testdata/install_values_file.golden b/cli/cmd/testdata/install_values_file.golden
index 92464eb57..128ceb248 100644
--- a/cli/cmd/testdata/install_values_file.golden
+++ b/cli/cmd/testdata/install_values_file.golden
@@ -1603,6 +1603,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=example.com
         - -identity-trust-domain=example.com
+        - -default-opaque-ports=25,443,587,3306,5432,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
diff --git a/controller/api/destination/endpoint_translator_test.go b/controller/api/destination/endpoint_translator_test.go
index 77be5e817..24a5b74dc 100644
--- a/controller/api/destination/endpoint_translator_test.go
+++ b/controller/api/destination/endpoint_translator_test.go
@@ -146,6 +146,7 @@ metadata:
 		true,
 		"service-name.service-ns",
 		"test-123",
+		map[uint32]struct{}{},
 		k8sAPI.Node(),
 		mockGetServer,
 		logging.WithField("test", t.Name()),
diff --git a/controller/api/destination/server_test.go b/controller/api/destination/server_test.go
index e5d994151..d94f94a50 100644
--- a/controller/api/destination/server_test.go
+++ b/controller/api/destination/server_test.go
@@ -217,9 +217,17 @@ metadata:
 		t.Fatalf("NewFakeAPI returned an error: %s", err)
 	}
 	log := logging.WithField("test", t.Name())
+	defaultOpaquePorts := map[uint32]struct{}{
+		25:    {},
+		443:   {},
+		587:   {},
+		3306:  {},
+		5432:  {},
+		11211: {},
+	}
 
 	endpoints := watcher.NewEndpointsWatcher(k8sAPI, log, false)
-	opaquePorts := watcher.NewOpaquePortsWatcher(k8sAPI, log)
+	opaquePorts := watcher.NewOpaquePortsWatcher(k8sAPI, log, defaultOpaquePorts)
 	profiles := watcher.NewProfileWatcher(k8sAPI, log)
 	trafficSplits := watcher.NewTrafficSplitWatcher(k8sAPI, log)
 	ips := watcher.NewIPWatcher(k8sAPI, endpoints, log)
@@ -239,6 +247,7 @@ metadata:
 		"linkerd",
 		"trust.domain",
 		"mycluster.local",
+		defaultOpaquePorts,
 		k8sAPI,
 		log,
 		make(<-chan struct{}),
diff --git a/controller/api/destination/watcher/opaque_ports_watcher_test.go b/controller/api/destination/watcher/opaque_ports_watcher_test.go
index 30dfab373..caa165c62 100644
--- a/controller/api/destination/watcher/opaque_ports_watcher_test.go
+++ b/controller/api/destination/watcher/opaque_ports_watcher_test.go
@@ -88,6 +88,15 @@ func (bopl *testOpaquePortsListener) UpdateService(ports map[uint32]struct{}) {
 }
 
 func TestOpaquePortsWatcher(t *testing.T) {
+	defaultOpaquePorts := map[uint32]struct{}{
+		25:    {},
+		443:   {},
+		587:   {},
+		3306:  {},
+		5432:  {},
+		11211: {},
+	}
+
 	for _, tt := range []struct {
 		name                string
 		initialState        []string
@@ -176,7 +185,7 @@ func TestOpaquePortsWatcher(t *testing.T) {
 		if err != nil {
 			t.Fatalf("NewFakeAPI returned an error: %s", err)
 		}
-		watcher := NewOpaquePortsWatcher(k8sAPI, logging.WithField("test", t.Name()))
+		watcher := NewOpaquePortsWatcher(k8sAPI, logging.WithField("test", t.Name()), defaultOpaquePorts)
 		k8sAPI.Sync(nil)
 		listener := newTestOpaquePortsListener()
 		watcher.Subscribe(tt.service, listener)
diff --git a/pkg/util/parsing_test.go b/pkg/util/parsing_test.go
new file mode 100644
index 000000000..ee9c365d3
--- /dev/null
+++ b/pkg/util/parsing_test.go
@@ -0,0 +1,57 @@
+package util
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func TestParsePorts(t *testing.T) {
+	testCases := []struct {
+		ports  string
+		result map[uint32]struct{}
+	}{
+		{
+			"25,443,587,3306,5432,11211",
+			map[uint32]struct{}{
+				25:    {},
+				443:   {},
+				587:   {},
+				3306:  {},
+				5432:  {},
+				11211: {},
+			},
+		},
+		{
+			"25,443-447,3306,5432-5435,11211",
+			map[uint32]struct{}{
+				25:    {},
+				443:   {},
+				444:   {},
+				445:   {},
+				446:   {},
+				447:   {},
+				3306:  {},
+				5432:  {},
+				5433:  {},
+				5434:  {},
+				5435:  {},
+				11211: {},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc // pin
+		t.Run(fmt.Sprintf("test %s", tc.ports), func(t *testing.T) {
+			ports, err := ParsePorts(tc.ports)
+			if err != nil {
+				t.Fatalf("could not parse ports: %v", err)
+			}
+
+			if !reflect.DeepEqual(ports, tc.result) {
+				t.Fatalf("Expected output: \"%v\", got: \"%v\"", tc.result, ports)
+			}
+		})
+	}
+}
diff --git a/test/integration/install_test.go b/test/integration/install_test.go
index 180e0cc2a..16e49e76f 100644
--- a/test/integration/install_test.go
+++ b/test/integration/install_test.go
@@ -466,7 +466,6 @@ func helmOverridesEdge(root *tls.CA) []string {
 	return []string{
 		"--set", "controllerLogLevel=debug",
 		"--set", "linkerdVersion=" + TestHelper.GetVersion(),
-		"--set", "proxy.image.version=" + TestHelper.GetVersion(),
 		// these ports will get verified in test/integration/inject
 		"--set", "proxyInit.ignoreInboundPorts=" + skippedInboundPortsEscaped,
 		"--set", "identityTrustDomain=cluster.local",