Repository: linkerd/linkerd2
Pull request #6875 (2021-09-14 00:13:43)

Add linkerd viz authz command
Similarly to the `linkerd authz` command which lists all authorizations for a given resource and `linkerd viz stat` which can show metrics for policy resources, we introduce a `linkerd viz authz` command which shows metrics for server authorizations broken down by server for a given resource.  It also shows the rate of unauthorized requests to each server.  This is helpful for seeing a breakdown of which authorizations are being used and what proportion of traffic is being rejected.  For example:


```console
> linkerd viz authz -n emojivoto deploy
SERVER       AUTHZ            SUCCESS     RPS  LATENCY_P50  LATENCY_P95  LATENCY_P99  
emoji-grpc   emoji-grpc       100.00%  1.8rps          1ms          1ms          1ms  
prom         prom-prometheus        -       -            -            -            -  
voting-grpc  [UNAUTHORIZED]         -  0.9rps            -            -            -  
web-http     web-public        50.00%  1.8rps          4ms        190ms        198ms
```

This shows us a few things right away:

* all traffic to the emoji-grpc server is authorized by the emoji-grpc server authorization
* the prom server defines a prom-prometheus server authorization, but it is not receiving any traffic
* the voting-grpc server has no server authorizations, and thus all 0.9rps is getting rejected

TODO:
* this command requires the CLI to make many API calls.  it could be sped up by making some of these calls in parallel or by moving more logic into the metrics-api controller to take better advantage of the metrcs-api client-go caches
* add support for json output
* improve CLI help output

adleong: I am planning to rebase once https://github.com/linkerd/linkerd2/pull/6785 has been merged, which should clean up the diff.

Patch:
diff --git a/.proxy-version b/.proxy-version
index fe67ec870..19ecb4e10 100644
--- a/.proxy-version
+++ b/.proxy-version
@@ -1,1 +1,1 @@
-v2.158.0
+v2.159.0
diff --git a/CHANGES.md b/CHANGES.md
index 3b168b34e..69eda5c62 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,40 @@
 # Changes
 
+## edge-21.9.3
+
+This edge is a release candidate for `stable-2.11.0`! It features a new `linkerd
+authz` CLI command to list servers and authorizations for a workload, as well as
+policy resources support for `linkerd viz stat`. Furthermore, this edge release
+adds support for JSON log formatting, enables TLS detection on port 443
+(previously marked as opaque), and further improves policy features.
+
+* Removed port 443 from the default list of opaque ports, this will allow the
+  proxy to report metadata (such as the connection's SNI value) on TLS
+  connections to port 443
+* Added default policies for core Linkerd extensions
+* Added support for JSON log formatting to the policy controller
+* Added support for new policy resources to `viz stat` command
+* Added default policy annotation to `linkerd-identity`
+* Added a new `linkerd authz` command to the CLI to list all server and
+  authorization resources that apply to a specific resource
+* Added TLS labels (including client identity) to authorization metrics in the
+  proxy
+* Changed the opaque ports CLI check to consider service and pod ports when
+  checking annotation values; previously, the check would naively issue warnings
+  when the service annotation values were different from the pod it selected
+* Changed how the proxy forwards inbound connections to a pod locally; the proxy
+  now targets the original address instead of a port bound on localhost to
+  protect services that are only bound on loopback from being exposed to other
+  pods
+* Improved memory utilization in the proxy, especially for TCP forwarding, where
+  the memory allocated was reduced from 128KB to 16KB
+* Updated the inbound policy system for the proxies to always allow connections
+  from localhost
+* Fixed an issue where the policy controller would not detect changes to the
+  `proxyProtocol` field of `Server` resources
+* Fixed an issue where the policy admission controller would log a `WARN`
+  message when deserializing `Server` structs
+
 ## edge-21.9.2
 
 This edge release gets us closer to 2.11 by further polishing the policy
diff --git a/Cargo.lock b/Cargo.lock
index 76cfca647..57c485e20 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -550,9 +550,9 @@ checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
 
 [[package]]
 name = "hyper"
-version = "0.14.12"
+version = "0.14.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd"
+checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1478,9 +1478,9 @@ dependencies = [
 
 [[package]]
 name = "schemars"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc6ab463ae35acccb5cba66c0084c985257b797d288b6050cc2f6ac1b266cb78"
+checksum = "b82485a532ef0af18878ad4281f73e58161cdba1db7918176e9294f0ca5498a5"
 dependencies = [
  "dyn-clone",
  "schemars_derive",
@@ -1490,9 +1490,9 @@ dependencies = [
 
 [[package]]
 name = "schemars_derive"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "902fdfbcf871ae8f653bddf4b2c05905ddaabc08f69d32a915787e3be0d31356"
+checksum = "791c2c848cff1abaeae34fef7e70da5f93171d9eea81ce0fe969a1df627a61a8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1997,9 +1997,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
 
 [[package]]
 name = "tracing"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2ba9ab62b7d6497a8638dfda5e5c4fb3b2d5a7fca4118f2b96151c8ef1a437e"
+checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8"
 dependencies = [
  "cfg-if",
  "log",
@@ -2061,9 +2061,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.2.22"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62af966210b88ad5776ee3ba12d5f35b8d6a2b2a12168f3080cf02b814d7376b"
+checksum = "fdd0568dbfe3baf7048b7908d2b32bca0d81cd56bec6d2a8f894b01d74f86be3"
 dependencies = [
  "lazy_static",
  "matchers",
diff --git a/bin/helm-build b/bin/helm-build
index bfeb90dc8..7ab8976ac 100755
--- a/bin/helm-build
+++ b/bin/helm-build
@@ -30,6 +30,7 @@ rm -f viz/charts/linkerd-viz/charts/*
 
 "$bindir"/helm dep up "$rootdir"/multicluster/charts/linkerd-multicluster
 "$bindir"/helm lint "$rootdir"/multicluster/charts/linkerd-multicluster
+"$bindir"/helm dep up "$rootdir"/multicluster/charts/linkerd-multicluster-link
 "$bindir"/helm lint "$rootdir"/multicluster/charts/linkerd-multicluster-link
 "$bindir"/helm lint "$rootdir"/charts/partials
 "$bindir"/helm dep up "$rootdir"/charts/linkerd2-cni
diff --git a/charts/linkerd2/README.md b/charts/linkerd2/README.md
index fef9de282..9484cbf03 100644
--- a/charts/linkerd2/README.md
+++ b/charts/linkerd2/README.md
@@ -191,7 +191,7 @@ Kubernetes: `>=1.16.0-0`
 | proxy.inboundConnectTimeout | string | `"100ms"` | Maximum time allowed for the proxy to establish an inbound TCP connection |
 | proxy.logFormat | string | `"plain"` | Log format (`plain` or `json`) for the proxy |
 | proxy.logLevel | string | `"warn,linkerd=info"` | Log level for the proxy |
-| proxy.opaquePorts | string | `"25,443,587,3306,4444,5432,6379,9300,11211"` | Default set of opaque ports - SMTP (25,587) server-first - HTTPS (443) opaque TLS - MYSQL (3306) server-first - Galera (4444) server-first - PostgreSQL (5432) server-first - Redis (6379) server-first - ElasticSearch (9300) server-first - Memcached (11211) clients do not issue any preamble, which breaks detection |
+| proxy.opaquePorts | string | `"25,587,3306,4444,5432,6379,9300,11211"` | Default set of opaque ports - SMTP (25,587) server-first - MYSQL (3306) server-first - Galera (4444) server-first - PostgreSQL (5432) server-first - Redis (6379) server-first - ElasticSearch (9300) server-first - Memcached (11211) clients do not issue any preamble, which breaks detection |
 | proxy.outboundConnectTimeout | string | `"1000ms"` | Maximum time allowed for the proxy to establish an outbound TCP connection |
 | proxy.ports.admin | int | `4191` | Admin port for the proxy container |
 | proxy.ports.control | int | `4190` | Control port for the proxy container |
diff --git a/charts/linkerd2/templates/destination.yaml b/charts/linkerd2/templates/destination.yaml
index dd38c2d9d..bbea55d92 100644
--- a/charts/linkerd2/templates/destination.yaml
+++ b/charts/linkerd2/templates/destination.yaml
@@ -50,7 +50,6 @@ metadata:
     linkerd.io/control-plane-ns: {{.Values.namespace}}
   annotations:
     {{ include "partials.annotations.created-by" . }}
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -151,7 +150,6 @@ spec:
         {{ include "partials.annotations.created-by" . }}
         {{- include "partials.proxy.annotations" . | nindent 8}}
         {{- with .Values.podAnnotations }}{{ toYaml . | trim | nindent 8 }}{{- end }}
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -289,9 +287,11 @@ spec:
           readOnly: true
       {{ if not .Values.cniEnabled -}}
       initContainers:
-      {{- if not (contains "443" ( .Values.proxyInit.ignoreOutboundPorts | toString ))}}
-      {{- $_ := set $tree.Values.proxyInit "ignoreOutboundPorts" ( ternary "443" (printf "%s,443" (.Values.proxyInit.ignoreOutboundPorts | toString )) (empty .Values.proxyInit.ignoreOutboundPorts)) -}}
-      {{- end}}
+      {{- /*
+        The destination controller needs to connect to the Kubernetes API before the proxy is able
+        to proxy requests, so we always skip these connections.
+      */}}
+      {{- $_ := set $tree.Values.proxyInit "ignoreOutboundPorts" "443" }}
       - {{- include "partials.proxy-init" $tree | indent 8 | trimPrefix (repeat 7 " ") }}
       {{ end -}}
       serviceAccountName: linkerd-destination
diff --git a/charts/linkerd2/templates/identity.yaml b/charts/linkerd2/templates/identity.yaml
index 0043a1818..fa1c75dbc 100644
--- a/charts/linkerd2/templates/identity.yaml
+++ b/charts/linkerd2/templates/identity.yaml
@@ -201,9 +201,12 @@ spec:
       - {{- include "partials.proxy" $tree | indent 8 | trimPrefix (repeat 7 " ") }}
       {{ if not .Values.cniEnabled -}}
       initContainers:
-      {{- if not (contains "443" ( .Values.proxyInit.ignoreOutboundPorts | toString ))}}
-      {{- $_ := set $tree.Values.proxyInit "ignoreOutboundPorts" ( ternary "443" (printf "%s,443" (.Values.proxyInit.ignoreOutboundPorts | toString )) (empty .Values.proxyInit.ignoreOutboundPorts)) -}}
-      {{- end}}
+      {{- /*
+        The identity controller needs to connect to the Kubernetes API before the proxy is able to
+        proxy requests, so we always skip these connections. The identity controller makes no other
+        outbound connections (so it's not important to persist any other skip ports here)
+      */}}
+      {{- $_ := set $tree.Values.proxyInit "ignoreOutboundPorts" "443" }}
       - {{- include "partials.proxy-init" $tree | indent 8 | trimPrefix (repeat 7 " ") }}
       {{ end -}}
       serviceAccountName: linkerd-identity
diff --git a/charts/linkerd2/templates/proxy-injector.yaml b/charts/linkerd2/templates/proxy-injector.yaml
index 95f5ca1a5..cb9adaac3 100644
--- a/charts/linkerd2/templates/proxy-injector.yaml
+++ b/charts/linkerd2/templates/proxy-injector.yaml
@@ -106,9 +106,6 @@ spec:
           readOnly: true
       {{ if not .Values.cniEnabled -}}
       initContainers:
-      {{- if not (contains "443" ( .Values.proxyInit.ignoreOutboundPorts | toString ))}}
-      {{- $_ := set $tree.Values.proxyInit "ignoreOutboundPorts" ( ternary "443" (printf "%s,443" (.Values.proxyInit.ignoreOutboundPorts | toString )) (empty .Values.proxyInit.ignoreOutboundPorts)) -}}
-      {{- end}}
       - {{- include "partials.proxy-init" $tree | indent 8 | trimPrefix (repeat 7 " ") }}
       {{ end -}}
       serviceAccountName: linkerd-proxy-injector
diff --git a/charts/linkerd2/values.yaml b/charts/linkerd2/values.yaml
index eb2deeed3..08b88e833 100644
--- a/charts/linkerd2/values.yaml
+++ b/charts/linkerd2/values.yaml
@@ -139,14 +139,13 @@ proxy:
   requireIdentityOnInboundPorts: ""
   # -- Default set of opaque ports
   # - SMTP (25,587) server-first
-  # - HTTPS (443) opaque TLS
   # - MYSQL (3306) server-first
   # - Galera (4444) server-first
   # - PostgreSQL (5432) server-first
   # - Redis (6379) server-first
   # - ElasticSearch (9300) server-first
   # - Memcached (11211) clients do not issue any preamble, which breaks detection
-  opaquePorts: "25,443,587,3306,4444,5432,6379,9300,11211"
+  opaquePorts: "25,587,3306,4444,5432,6379,9300,11211"
 
 # proxy-init configuration
 proxyInit:
diff --git a/cli/cmd/authz.go b/cli/cmd/authz.go
index 81b02088c..560818cfe 100644
--- a/cli/cmd/authz.go
+++ b/cli/cmd/authz.go
@@ -1,36 +1,15 @@
 package cmd
 
 import (
-	"context"
 	"fmt"
 	"os"
-	"strings"
 
 	"github.com/linkerd/linkerd2/cli/table"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/spf13/cobra"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/client-go/kubernetes"
 )
 
-var sazGVR = schema.GroupVersionResource{
-	Group:    "policy.linkerd.io",
-	Version:  "v1alpha1",
-	Resource: "serverauthorizations",
-}
-
-var serverGVR = schema.GroupVersionResource{
-	Group:    "policy.linkerd.io",
-	Version:  "v1alpha1",
-	Resource: "servers",
-}
-
-type id struct{ name, namespace string }
-
 func newCmdAuthz() *cobra.Command {
 
 	var namespace string
@@ -78,58 +57,16 @@ func newCmdAuthz() *cobra.Command {
 				resource = args[0] + "/" + args[1]
 			}
 
-			pods, err := getPodsForResourceOrKind(cmd.Context(), k8sAPI, namespace, resource)
-			if err != nil {
-				return err
-			}
-			podSet := make(map[id]struct{})
-			for _, pod := range pods {
-				podSet[id{pod.Name, pod.Namespace}] = struct{}{}
-			}
-
 			rows := make([]table.Row, 0)
 
-			sazs, err := k8sAPI.DynamicClient.Resource(sazGVR).Namespace(namespace).List(cmd.Context(), metav1.ListOptions{})
+			authzs, err := k8s.ServerAuthorizationsForResource(cmd.Context(), k8sAPI, namespace, resource)
 			if err != nil {
 				fmt.Fprintf(os.Stderr, "Failed to get serverauthorization resources: %s\n", err)
 				os.Exit(1)
 			}
 
-			for _, saz := range sazs.Items {
-				var servers []unstructured.Unstructured
-
-				if name, found, _ := unstructured.NestedString(saz.UnstructuredContent(), "spec", "server", "name"); found {
-					server, err := k8sAPI.DynamicClient.Resource(serverGVR).Namespace(saz.GetNamespace()).Get(cmd.Context(), name, metav1.GetOptions{})
-					if err != nil {
-						fmt.Fprintf(os.Stderr, "Failed to get server %s: %s\n", name, err)
-						os.Exit(1)
-					}
-					servers = []unstructured.Unstructured{*server}
-				} else if sel, found, _ := unstructured.NestedMap(saz.UnstructuredContent(), "spec", "server", "selector"); found {
-					selector := selector(sel)
-					serverList, err := k8sAPI.DynamicClient.Resource(serverGVR).Namespace(saz.GetNamespace()).List(cmd.Context(), metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
-					if err != nil {
-						fmt.Fprintf(os.Stderr, "Failed to get servers: %s\n", err)
-						os.Exit(1)
-					}
-					servers = serverList.Items
-				}
-
-				for _, server := range servers {
-					if sel, found, _ := unstructured.NestedMap(server.UnstructuredContent(), "spec", "podSelector"); found {
-						selector := selector(sel)
-						selectedPods, err := k8sAPI.CoreV1().Pods(server.GetNamespace()).List(cmd.Context(), metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
-						if err != nil {
-							fmt.Fprintf(os.Stderr, "Failed to get pods: %s\n", err)
-							os.Exit(1)
-						}
-						if serverIncludesPod(server, selectedPods.Items, podSet) {
-							rows = append(rows, table.Row{server.GetName(), saz.GetName()})
-						}
-					}
-
-				}
-
+			for _, authz := range authzs {
+				rows = append(rows, table.Row{authz.Server, authz.ServerAuthorization})
 			}
 
 			cols := []table.Column{
@@ -150,202 +87,3 @@ func newCmdAuthz() *cobra.Command {
 		kubeconfigPath, impersonate, impersonateGroup, kubeContext)
 	return cmd
 }
-
-func selector(selector map[string]interface{}) metav1.LabelSelector {
-	if labels, found, err := unstructured.NestedStringMap(selector, "matchLabels"); found && err == nil {
-		return metav1.LabelSelector{MatchLabels: labels}
-	}
-	if expressions, found, err := unstructured.NestedSlice(selector, "matchExpressions"); found && err == nil {
-		exprs := make([]metav1.LabelSelectorRequirement, len(expressions))
-		for i, expr := range expressions {
-			exprs[i] = matchExpression(expr)
-		}
-		return metav1.LabelSelector{MatchExpressions: exprs}
-	}
-	return metav1.LabelSelector{}
-}
-
-func matchExpression(expr interface{}) metav1.LabelSelectorRequirement {
-	if exprMap, ok := expr.(map[string]interface{}); ok {
-		if key, found, err := unstructured.NestedString(exprMap, "key"); found && err == nil {
-			if op, found, err := unstructured.NestedString(exprMap, "operator"); found && err == nil {
-				if values, found, err := unstructured.NestedStringSlice(exprMap, "values"); found && err == nil {
-					return metav1.LabelSelectorRequirement{
-						Key:      key,
-						Operator: metav1.LabelSelectorOperator(op),
-						Values:   values,
-					}
-				}
-			}
-		}
-	}
-	return metav1.LabelSelectorRequirement{}
-}
-
-func serverIncludesPod(server unstructured.Unstructured, serverPods []corev1.Pod, podSet map[id]struct{}) bool {
-	for _, pod := range serverPods {
-		if _, ok := podSet[id{pod.Name, pod.Namespace}]; ok {
-			if port, found, err := unstructured.NestedInt64(server.UnstructuredContent(), "spec", "port"); found && err == nil {
-				for _, container := range pod.Spec.Containers {
-					for _, p := range container.Ports {
-						if int32(port) == p.ContainerPort {
-							return true
-						}
-					}
-				}
-			}
-			if port, found, err := unstructured.NestedString(server.UnstructuredContent(), "spec", "port"); found && err == nil {
-				for _, container := range pod.Spec.Containers {
-					for _, p := range container.Ports {
-						if port == p.Name {
-							return true
-						}
-					}
-				}
-			}
-		}
-	}
-	return false
-}
-
-// getPodsForResourceOrKind is similar to getPodsForResource, but also supports
-// querying for all resources of a given kind (i.e. when resource name is unspecified).
-func getPodsForResourceOrKind(ctx context.Context, k8sAPI kubernetes.Interface, namespace string, resource string) ([]corev1.Pod, error) {
-
-	elems := strings.Split(resource, "/")
-	if len(elems) > 2 {
-		return nil, fmt.Errorf("invalid resource: %s", resource)
-	}
-	if len(elems) == 2 {
-		pods, err := getPodsFor(ctx, k8sAPI, namespace, resource)
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-			os.Exit(1)
-		}
-		return pods, nil
-	}
-	pods := []corev1.Pod{}
-
-	typ, err := k8s.CanonicalResourceNameFromFriendlyName(elems[0])
-	if err != nil {
-		return nil, fmt.Errorf("invalid resource: %s", resource)
-	}
-	switch typ {
-	case k8s.Pod:
-		ps, err := k8sAPI.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-			os.Exit(1)
-		}
-		pods = append(pods, ps.Items...)
-
-	case k8s.CronJob:
-		jobs, err := k8sAPI.BatchV1().CronJobs(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get cronjobs: %s", err)
-			os.Exit(1)
-		}
-		for _, job := range jobs.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.CronJob, job.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.DaemonSet:
-		dss, err := k8sAPI.AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get demonsets: %s", err)
-			os.Exit(1)
-		}
-		for _, ds := range dss.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.DaemonSet, ds.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.Deployment:
-		deploys, err := k8sAPI.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get deployments: %s", err)
-			os.Exit(1)
-		}
-		for _, deploy := range deploys.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.Deployment, deploy.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.Job:
-		jobs, err := k8sAPI.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get jobs: %s", err)
-			os.Exit(1)
-		}
-		for _, job := range jobs.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.Job, job.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.ReplicaSet:
-		rss, err := k8sAPI.AppsV1().ReplicaSets(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get replicasets: %s", err)
-			os.Exit(1)
-		}
-		for _, rs := range rss.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.ReplicaSet, rs.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.ReplicationController:
-		rcs, err := k8sAPI.CoreV1().ReplicationControllers(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get replicationcontrollers: %s", err)
-			os.Exit(1)
-		}
-		for _, rc := range rcs.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.ReplicationController, rc.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	case k8s.StatefulSet:
-		sss, err := k8sAPI.AppsV1().StatefulSets(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "failed to get statefulsets: %s", err)
-			os.Exit(1)
-		}
-		for _, ss := range sss.Items {
-			ps, err := getPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", k8s.StatefulSet, ss.Name))
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
-				os.Exit(1)
-			}
-			pods = append(pods, ps...)
-		}
-
-	default:
-		return nil, fmt.Errorf("unsupported resource type: %s", typ)
-	}
-	return pods, nil
-}
diff --git a/cli/cmd/metrics.go b/cli/cmd/metrics.go
index 91b8ce3ca..a5c265ae7 100644
--- a/cli/cmd/metrics.go
+++ b/cli/cmd/metrics.go
@@ -2,20 +2,12 @@ package cmd
 
 import (
 	"bytes"
-	"context"
-	"errors"
 	"fmt"
-	"strings"
 	"time"
 
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/spf13/cobra"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/kubernetes"
 )
 
 type metricsOptions struct {
@@ -83,7 +75,7 @@ func newCmdMetrics() *cobra.Command {
 				return err
 			}
 
-			pods, err := getPodsFor(cmd.Context(), k8sAPI, options.namespace, args[0])
+			pods, err := k8s.GetPodsFor(cmd.Context(), k8sAPI, options.namespace, args[0])
 			if err != nil {
 				return err
 			}
@@ -113,163 +105,3 @@ func newCmdMetrics() *cobra.Command {
 
 	return cmd
 }
-
-// getPodsFor takes a resource string, queries the Kubernetes API, and returns a
-// list of pods belonging to that resource.
-// This could move into `pkg/k8s` if becomes more generally useful.
-func getPodsFor(ctx context.Context, clientset kubernetes.Interface, namespace string, resource string) ([]corev1.Pod, error) {
-	elems := strings.Split(resource, "/")
-
-	if len(elems) == 1 {
-		return nil, errors.New("no resource name provided")
-	}
-
-	if len(elems) != 2 {
-		return nil, fmt.Errorf("invalid resource string: %s", resource)
-	}
-
-	typ, err := k8s.CanonicalResourceNameFromFriendlyName(elems[0])
-	if err != nil {
-		return nil, err
-	}
-	name := elems[1]
-
-	// special case if a single pod was specified
-	if typ == k8s.Pod {
-		pod, err := clientset.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		return []corev1.Pod{*pod}, nil
-	}
-
-	var matchLabels map[string]string
-	var ownerUID types.UID
-	switch typ {
-	case k8s.CronJob:
-		jobs, err := clientset.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
-		if err != nil {
-			return nil, err
-		}
-
-		var pods []corev1.Pod
-		for _, job := range jobs.Items {
-			if isOwner(job.GetUID(), job.GetOwnerReferences()) {
-				jobPods, err := getPodsFor(ctx, clientset, namespace, fmt.Sprintf("%s/%s", k8s.Job, job.GetName()))
-				if err != nil {
-					return nil, err
-				}
-				pods = append(pods, jobPods...)
-			}
-		}
-		return pods, nil
-
-	case k8s.DaemonSet:
-		ds, err := clientset.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = ds.Spec.Selector.MatchLabels
-		ownerUID = ds.GetUID()
-
-	case k8s.Deployment:
-		deployment, err := clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = deployment.Spec.Selector.MatchLabels
-		ownerUID = deployment.GetUID()
-
-		replicaSets, err := clientset.AppsV1().ReplicaSets(namespace).List(
-			ctx,
-			metav1.ListOptions{
-				LabelSelector: labels.Set(matchLabels).AsSelector().String(),
-			},
-		)
-		if err != nil {
-			return nil, err
-		}
-
-		var pods []corev1.Pod
-		for _, rs := range replicaSets.Items {
-			if isOwner(ownerUID, rs.GetOwnerReferences()) {
-				podsRS, err := getPodsFor(ctx, clientset, namespace, fmt.Sprintf("%s/%s", k8s.ReplicaSet, rs.GetName()))
-				if err != nil {
-					return nil, err
-				}
-				pods = append(pods, podsRS...)
-			}
-		}
-		return pods, nil
-
-	case k8s.Job:
-		job, err := clientset.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = job.Spec.Selector.MatchLabels
-		ownerUID = job.GetUID()
-
-	case k8s.ReplicaSet:
-		rs, err := clientset.AppsV1().ReplicaSets(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = rs.Spec.Selector.MatchLabels
-		ownerUID = rs.GetUID()
-
-	case k8s.ReplicationController:
-		rc, err := clientset.CoreV1().ReplicationControllers(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = rc.Spec.Selector
-		ownerUID = rc.GetUID()
-
-	case k8s.StatefulSet:
-		ss, err := clientset.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{})
-		if err != nil {
-			return nil, err
-		}
-		matchLabels = ss.Spec.Selector.MatchLabels
-		ownerUID = ss.GetUID()
-
-	default:
-		return nil, fmt.Errorf("unsupported resource type: %s", name)
-	}
-
-	podList, err := clientset.
-		CoreV1().
-		Pods(namespace).
-		List(
-			ctx,
-			metav1.ListOptions{
-				LabelSelector: labels.Set(matchLabels).AsSelector().String(),
-			},
-		)
-	if err != nil {
-		return nil, err
-	}
-
-	if ownerUID == "" {
-		return podList.Items, nil
-	}
-
-	pods := []corev1.Pod{}
-	for _, pod := range podList.Items {
-		if isOwner(ownerUID, pod.GetOwnerReferences()) {
-			pods = append(pods, pod)
-		}
-	}
-
-	return pods, nil
-}
-
-func isOwner(u types.UID, ownerRefs []metav1.OwnerReference) bool {
-	for _, or := range ownerRefs {
-		if u == or.UID {
-			return true
-		}
-	}
-	return false
-}
diff --git a/cli/table/table.go b/cli/table/table.go
index d405c2d68..ba585f721 100644
--- a/cli/table/table.go
+++ b/cli/table/table.go
@@ -43,6 +43,21 @@ func NewTable(cols []Column, data []Row) Table {
 	}
 }
 
+// NewColumn creates a new flexible column with the given name.
+func NewColumn(header string) Column {
+	return Column{
+		Header:   header,
+		Flexible: true,
+		Width:    len(header),
+	}
+}
+
+// WithLeftAlign turns on the left align of this column and returns it.
+func (c Column) WithLeftAlign() Column {
+	c.LeftAlign = true
+	return c
+}
+
 // Render writes the full table to the given Writer.
 func (t *Table) Render(w io.Writer) {
 	columnWidths := t.columnWidths()
diff --git a/controller/api/destination/watcher/endpoints_watcher.go b/controller/api/destination/watcher/endpoints_watcher.go
index e32449fd1..6877622eb 100644
--- a/controller/api/destination/watcher/endpoints_watcher.go
+++ b/controller/api/destination/watcher/endpoints_watcher.go
@@ -183,9 +183,9 @@ func (ew *EndpointsWatcher) Subscribe(id ServiceID, port Port, hostname string,
 	}
 
 	if hostname == "" {
-		ew.log.Infof("Establishing watch on endpoint [%s:%d]", id, port)
+		ew.log.Debugf("Establishing watch on endpoint [%s:%d]", id, port)
 	} else {
-		ew.log.Infof("Establishing watch on endpoint [%s.%s:%d]", hostname, id, port)
+		ew.log.Debugf("Establishing watch on endpoint [%s.%s:%d]", hostname, id, port)
 	}
 
 	sp := ew.getOrNewServicePublisher(id)
@@ -197,9 +197,9 @@ func (ew *EndpointsWatcher) Subscribe(id ServiceID, port Port, hostname string,
 // Unsubscribe removes a listener from the subscribers list for this authority.
 func (ew *EndpointsWatcher) Unsubscribe(id ServiceID, port Port, hostname string, listener EndpointUpdateListener) {
 	if hostname == "" {
-		ew.log.Infof("Stopping watch on endpoint [%s:%d]", id, port)
+		ew.log.Debugf("Stopping watch on endpoint [%s:%d]", id, port)
 	} else {
-		ew.log.Infof("Stopping watch on endpoint [%s.%s:%d]", hostname, id, port)
+		ew.log.Debugf("Stopping watch on endpoint [%s.%s:%d]", hostname, id, port)
 	}
 
 	sp, ok := ew.getServicePublisher(id)
diff --git a/controller/api/destination/watcher/opaque_ports_watcher.go b/controller/api/destination/watcher/opaque_ports_watcher.go
index 47b85ade0..809bd62ca 100644
--- a/controller/api/destination/watcher/opaque_ports_watcher.go
+++ b/controller/api/destination/watcher/opaque_ports_watcher.go
@@ -64,7 +64,7 @@ func (opw *OpaquePortsWatcher) Subscribe(id ServiceID, listener OpaquePortsUpdat
 	if svc != nil && svc.Spec.Type == corev1.ServiceTypeExternalName {
 		return invalidService(id.String())
 	}
-	opw.log.Infof("Starting watch on service %s", id)
+	opw.log.Debugf("Starting watch on service %s", id)
 	ss, ok := opw.subscriptions[id]
 	// If there is no watched service, create a subscription for the service
 	// and no opaque ports
@@ -87,7 +87,7 @@ func (opw *OpaquePortsWatcher) Subscribe(id ServiceID, listener OpaquePortsUpdat
 func (opw *OpaquePortsWatcher) Unsubscribe(id ServiceID, listener OpaquePortsUpdateListener) {
 	opw.Lock()
 	defer opw.Unlock()
-	opw.log.Infof("Stopping watch on service %s", id)
+	opw.log.Debugf("Stopping watch on service %s", id)
 	ss, ok := opw.subscriptions[id]
 	if !ok {
 		opw.log.Errorf("Cannot unsubscribe from unknown service %s", id)
diff --git a/controller/api/destination/watcher/profile_watcher.go b/controller/api/destination/watcher/profile_watcher.go
index 4b4c33a9d..66bff1e6c 100644
--- a/controller/api/destination/watcher/profile_watcher.go
+++ b/controller/api/destination/watcher/profile_watcher.go
@@ -71,7 +71,7 @@ func NewProfileWatcher(k8sAPI *k8s.API, log *logging.Entry) *ProfileWatcher {
 // The provided listener will be updated each time the service profile for the
 // given authority is changed.
 func (pw *ProfileWatcher) Subscribe(id ProfileID, listener ProfileUpdateListener) error {
-	pw.log.Infof("Establishing watch on profile %s", id)
+	pw.log.Debugf("Establishing watch on profile %s", id)
 
 	publisher := pw.getOrNewProfilePublisher(id, nil)
 
@@ -81,7 +81,7 @@ func (pw *ProfileWatcher) Subscribe(id ProfileID, listener ProfileUpdateListener
 
 // Unsubscribe removes a listener from the subscribers list for this authority.
 func (pw *ProfileWatcher) Unsubscribe(id ProfileID, listener ProfileUpdateListener) error {
-	pw.log.Infof("Stopping watch on profile %s", id)
+	pw.log.Debugf("Stopping watch on profile %s", id)
 
 	publisher, ok := pw.getProfilePublisher(id)
 	if !ok {
diff --git a/controller/api/destination/watcher/traffic_split_watcher.go b/controller/api/destination/watcher/traffic_split_watcher.go
index 6880711b5..f705b018e 100644
--- a/controller/api/destination/watcher/traffic_split_watcher.go
+++ b/controller/api/destination/watcher/traffic_split_watcher.go
@@ -71,7 +71,7 @@ func NewTrafficSplitWatcher(k8sAPI *k8s.API, log *logging.Entry) *TrafficSplitWa
 // Each time a traffic split is updated with the given apex service, the
 // listener will be updated.
 func (tsw *TrafficSplitWatcher) Subscribe(id ServiceID, listener TrafficSplitUpdateListener) error {
-	tsw.log.Infof("Establishing watch on service %s", id)
+	tsw.log.Debugf("Establishing watch on service %s", id)
 
 	publisher := tsw.getOrNewTrafficSplitPublisher(id, nil)
 
@@ -81,7 +81,7 @@ func (tsw *TrafficSplitWatcher) Subscribe(id ServiceID, listener TrafficSplitUpd
 
 // Unsubscribe removes a listener from the subscribers list for this service.
 func (tsw *TrafficSplitWatcher) Unsubscribe(id ServiceID, listener TrafficSplitUpdateListener) error {
-	tsw.log.Infof("Stopping watch on profile %s", id)
+	tsw.log.Debugf("Stopping watch on profile %s", id)
 
 	publisher, ok := tsw.getTrafficSplitPublisher(id)
 	if !ok {
diff --git a/controller/proxy-injector/fake/data/pod-with-debug.patch.json b/controller/proxy-injector/fake/data/pod-with-debug.patch.json
index c27fb261b..64eeb4fca 100644
--- a/controller/proxy-injector/fake/data/pod-with-debug.patch.json
+++ b/controller/proxy-injector/fake/data/pod-with-debug.patch.json
@@ -214,7 +214,7 @@
         },
         {
           "name": "LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION",
-          "value": "25,443,587,3306,4444,5432,6379,9300,11211"
+          "value": "25,587,3306,4444,5432,6379,9300,11211"
         },
         {
           "name": "LINKERD2_PROXY_DESTINATION_CONTEXT",
diff --git a/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json b/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
index 1a02394a7..2ac69fb06 100644
--- a/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
+++ b/controller/proxy-injector/fake/data/pod-with-ns-annotations.patch.json
@@ -214,7 +214,7 @@
         },
         {
           "name": "LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION",
-          "value": "25,443,587,3306,4444,5432,6379,9300,11211"
+          "value": "25,587,3306,4444,5432,6379,9300,11211"
         },
         {
           "name": "LINKERD2_PROXY_DESTINATION_CONTEXT",
diff --git a/controller/proxy-injector/fake/data/pod.patch.json b/controller/proxy-injector/fake/data/pod.patch.json
index 7023de026..3e20cbe97 100644
--- a/controller/proxy-injector/fake/data/pod.patch.json
+++ b/controller/proxy-injector/fake/data/pod.patch.json
@@ -204,7 +204,7 @@
         },
         {
           "name": "LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION",
-          "value": "25,443,587,3306,4444,5432,6379,9300,11211"
+          "value": "25,587,3306,4444,5432,6379,9300,11211"
         },
         {
           "name": "LINKERD2_PROXY_DESTINATION_CONTEXT",
diff --git a/jaeger/charts/linkerd-jaeger/templates/jaeger-injector-policy.yaml b/jaeger/charts/linkerd-jaeger/templates/jaeger-injector-policy.yaml
new file mode 100644
index 000000000..301fd67f2
--- /dev/null
+++ b/jaeger/charts/linkerd-jaeger/templates/jaeger-injector-policy.yaml
@@ -0,0 +1,56 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-injector-webhook
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: jaeger-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-injector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: jaeger-injector
+  client:
+    # traffic coming from the kubelet and from kube-api
+    unauthenticated: true
diff --git a/jaeger/charts/linkerd-jaeger/templates/proxy-admin-policy.yaml b/jaeger/charts/linkerd-jaeger/templates/proxy-admin-policy.yaml
new file mode 100644
index 000000000..9f936b1cc
--- /dev/null
+++ b/jaeger/charts/linkerd-jaeger/templates/proxy-admin-policy.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
diff --git a/jaeger/charts/linkerd-jaeger/templates/tracing-policy.yaml b/jaeger/charts/linkerd-jaeger/templates/tracing-policy.yaml
new file mode 100644
index 000000000..007a73e51
--- /dev/null
+++ b/jaeger/charts/linkerd-jaeger/templates/tracing-policy.yaml
@@ -0,0 +1,232 @@
+{{ if .Values.collector.enabled -}}
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-otlp
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 4317
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-opencensus
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 55678
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-zipkin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 9411
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-jaeger-thrift
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14268
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14250
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 13133
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: collector
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: collector
+  client:
+    # allow connections from any pod (meshed or not) sending trace data
+    unauthenticated: true
+{{ end -}}
+{{ if .Values.jaeger.enabled -}}
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: grpc
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: jaeger-grpc
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: collector
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: jaeger-admin
+  client:
+    meshTLS:
+      serviceAccounts:
+      # if not using linkerd-viz' prometheus, replace its SA here
+      - name: prometheus
+        namespace: linkerd-viz
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: ui
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: jaeger-ui
+  client:
+    meshTLS:
+      serviceAccounts:
+      # for the optional dashboard integration
+      - name: web
+        namespace: linkerd-viz
+{{ end -}}
diff --git a/jaeger/charts/linkerd-jaeger/templates/tracing.yaml b/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
index 4b479fd60..285fc4e03 100644
--- a/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
+++ b/jaeger/charts/linkerd-jaeger/templates/tracing.yaml
@@ -9,6 +9,7 @@ metadata:
   name: collector-config
   namespace: {{.Values.namespace}}
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 data:
   collector-config: |
@@ -20,6 +21,7 @@ metadata:
   name: collector
   namespace: {{.Values.namespace}}
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 spec:
   type: ClusterIP
@@ -51,6 +53,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: collector
     app.kubernetes.io/part-of: Linkerd
     component: collector
@@ -70,6 +73,7 @@ spec:
         prometheus.io/port: "8888"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: collector
     spec:
       {{- if .Values.collector.tolerations -}}
@@ -96,6 +100,7 @@ spec:
             port: 13133
         name: ot-collector
         ports:
+        - containerPort: 13133
         - containerPort: 4317
         - containerPort: 55678
         - containerPort: 9411
@@ -132,6 +137,7 @@ metadata:
   name: jaeger
   namespace: {{.Values.namespace}}
   labels:
+    linkerd.io/extension: jaeger
     component: jaeger
 spec:
   type: ClusterIP
@@ -149,6 +155,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: jaeger
     app.kubernetes.io/part-of: Linkerd
     component: jaeger
@@ -167,6 +174,7 @@ spec:
         prometheus.io/port: "14269"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: jaeger
     spec:
       {{- if .Values.jaeger.tolerations -}}
diff --git a/jaeger/cmd/install.go b/jaeger/cmd/install.go
index 6fd228fe5..2a86464bd 100644
--- a/jaeger/cmd/install.go
+++ b/jaeger/cmd/install.go
@@ -25,10 +25,13 @@ import (
 var (
 	templatesJaeger = []string{
 		"templates/namespace.yaml",
+		"templates/proxy-admin-policy.yaml",
 		"templates/jaeger-injector.yaml",
+		"templates/jaeger-injector-policy.yaml",
 		"templates/rbac.yaml",
 		"templates/psp.yaml",
 		"templates/tracing.yaml",
+		"templates/tracing-policy.yaml",
 	}
 )
 
diff --git a/multicluster/charts/linkerd-multicluster-link/templates/service-mirror-policy.yaml b/multicluster/charts/linkerd-multicluster-link/templates/service-mirror-policy.yaml
new file mode 100644
index 000000000..6bdb1ccfe
--- /dev/null
+++ b/multicluster/charts/linkerd-multicluster-link/templates/service-mirror-policy.yaml
@@ -0,0 +1,34 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: service-mirror
+  labels:
+    linkerd.io/control-plane-component: linkerd-service-mirror
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/control-plane-component: linkerd-service-mirror
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: service-mirror
+  labels:
+    linkerd.io/control-plane-component: linkerd-service-mirror
+spec:
+  server:
+    name: service-mirror
+  client:
+    # In order to use `linkerd mc gateways` you need viz' Prometheus instance
+    # to be able to reach the service-mirror. In order to also have a separate
+    # Prometheus scrape the service-mirror an additional ServerAuthorization
+    # resource should be created.
+    meshTLS:
+      serviceAccounts:
+      - name: prometheus
+        namespace: linkerd-viz
diff --git a/multicluster/charts/linkerd-multicluster-link/templates/service-mirror.yaml b/multicluster/charts/linkerd-multicluster-link/templates/service-mirror.yaml
index 31a2ad9e8..375d8763c 100644
--- a/multicluster/charts/linkerd-multicluster-link/templates/service-mirror.yaml
+++ b/multicluster/charts/linkerd-multicluster-link/templates/service-mirror.yaml
@@ -4,6 +4,7 @@ apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}}
   labels:
+    linkerd.io/extension: multicluster
     linkerd.io/control-plane-component: service-mirror
     mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
 rules:
@@ -19,6 +20,7 @@ apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: linkerd-service-mirror-access-local-resources-{{.Values.targetClusterName}}
   labels:
+    linkerd.io/extension: multicluster
     linkerd.io/control-plane-component: service-mirror
     mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
 roleRef:
@@ -36,6 +38,7 @@ metadata:
   name: linkerd-service-mirror-read-remote-creds-{{.Values.targetClusterName}}
   namespace: {{.Values.namespace}}
   labels:
+      linkerd.io/extension: multicluster
       linkerd.io/control-plane-component: service-mirror
       mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
 rules:
@@ -53,6 +56,7 @@ metadata:
   name: linkerd-service-mirror-read-remote-creds-{{.Values.targetClusterName}}
   namespace: {{.Values.namespace}}
   labels:
+      linkerd.io/extension: multicluster
       linkerd.io/control-plane-component: service-mirror
       mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
 roleRef:
@@ -70,6 +74,7 @@ metadata:
   name: linkerd-service-mirror-{{.Values.targetClusterName}}
   namespace: {{.Values.namespace}}
   labels:
+    linkerd.io/extension: multicluster
     linkerd.io/control-plane-component: service-mirror
     mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
 ---
@@ -77,6 +82,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: multicluster
     linkerd.io/control-plane-component: service-mirror
     mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
   name: linkerd-service-mirror-{{.Values.targetClusterName}}
@@ -85,6 +91,7 @@ spec:
   replicas: 1
   selector:
     matchLabels:
+      linkerd.io/extension: multicluster
       linkerd.io/control-plane-component: linkerd-service-mirror
       mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
   template:
@@ -92,6 +99,7 @@ spec:
       annotations:
         linkerd.io/inject: enabled
       labels:
+        linkerd.io/extension: multicluster
         linkerd.io/control-plane-component: linkerd-service-mirror
         mirror.linkerd.io/cluster-name: {{.Values.targetClusterName}}
     spec:
diff --git a/multicluster/charts/linkerd-multicluster/templates/gateway-policy.yaml b/multicluster/charts/linkerd-multicluster/templates/gateway-policy.yaml
new file mode 100644
index 000000000..e8e53b4d7
--- /dev/null
+++ b/multicluster/charts/linkerd-multicluster/templates/gateway-policy.yaml
@@ -0,0 +1,66 @@
+{{if .Values.gateway.enabled -}}
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: linkerd-gateway
+  labels:
+    linkerd.io/extension: multicluster
+    app: {{.Values.gateway.name}}
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      app: {{.Values.gateway.name}}
+  port: linkerd-proxy
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: linkerd-gateway
+  labels:
+    linkerd.io/extension: multicluster
+    app: {{.Values.gateway.name}}
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: linkerd-gateway
+  client:
+    meshTLS:
+      identities:
+      - '*'
+    networks:
+    # Change this to the source cluster cidrs pointing to this gateway.
+    # Note that the source IP in some providers (e.g. GKE) will be the local
+    # node's IP and not the source cluster's
+    - cidr: 0.0.0.0/0
+    - cidr: ::/0
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: linkerd-gateway-probe
+  labels:
+    linkerd.io/extension: multicluster
+    app: {{.Values.gateway.name}}
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # allows probes from outside the cluster, as long as they have an identity
+    meshTLS:
+      identities:
+      - '*'
+    networks:
+    # cf note for linkerd-gateway ServerAuthorization
+    - cidr: 0.0.0.0/0
+    - cidr: ::/0
+{{end -}}
diff --git a/multicluster/charts/linkerd-multicluster/templates/gateway.yaml b/multicluster/charts/linkerd-multicluster/templates/gateway.yaml
index 6b3bcc6e2..e4e5d93e9 100644
--- a/multicluster/charts/linkerd-multicluster/templates/gateway.yaml
+++ b/multicluster/charts/linkerd-multicluster/templates/gateway.yaml
@@ -18,6 +18,7 @@ spec:
   replicas: 1
   selector:
     matchLabels:
+      linkerd.io/extension: multicluster
       app: {{.Values.gateway.name}}
   template:
     metadata:
@@ -27,6 +28,7 @@ spec:
         config.linkerd.io/proxy-require-identity-inbound-ports: "{{.Values.gateway.port}}"
         config.linkerd.io/enable-gateway: "true"
       labels:
+        linkerd.io/extension: multicluster
         app: {{.Values.gateway.name}}
     spec:
       containers:
diff --git a/multicluster/charts/linkerd-multicluster/templates/proxy-admin-policy.yaml b/multicluster/charts/linkerd-multicluster/templates/proxy-admin-policy.yaml
new file mode 100644
index 000000000..889349c0e
--- /dev/null
+++ b/multicluster/charts/linkerd-multicluster/templates/proxy-admin-policy.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: multicluster
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: multicluster
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: multicluster
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
diff --git a/multicluster/cmd/install.go b/multicluster/cmd/install.go
index 2c6520391..e2fe1ffc6 100644
--- a/multicluster/cmd/install.go
+++ b/multicluster/cmd/install.go
@@ -85,6 +85,8 @@ A full list of configurable values can be found at https://github.com/linkerd/li
 				{Name: chartutil.ChartfileName},
 				{Name: "templates/namespace.yaml"},
 				{Name: "templates/gateway.yaml"},
+				{Name: "templates/proxy-admin-policy.yaml"},
+				{Name: "templates/gateway-policy.yaml"},
 				{Name: "templates/psp.yaml"},
 				{Name: "templates/remote-access-service-mirror-rbac.yaml"},
 				{Name: "templates/link-crd.yaml"},
diff --git a/multicluster/cmd/link.go b/multicluster/cmd/link.go
index 6c472e39e..6dcd5009b 100644
--- a/multicluster/cmd/link.go
+++ b/multicluster/cmd/link.go
@@ -259,6 +259,7 @@ A full list of configurable values can be found at https://github.com/linkerd/li
 			files := []*chartloader.BufferedFile{
 				{Name: chartutil.ChartfileName},
 				{Name: "templates/service-mirror.yaml"},
+				{Name: "templates/service-mirror-policy.yaml"},
 				{Name: "templates/psp.yaml"},
 				{Name: "templates/gateway-mirror.yaml"},
 			}
diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go
index d6ffaa5ee..fb81d9d67 100644
--- a/pkg/healthcheck/healthcheck.go
+++ b/pkg/healthcheck/healthcheck.go
@@ -2355,7 +2355,7 @@ func checkPodPorts(service *corev1.Service, pod *corev1.Pod, podPorts []string,
 						if util.ContainsString(strPort, podPorts) {
 							return nil
 						}
-						return fmt.Errorf("service %s expects %d to be opaque; add it to pod %s's %s annotation", service.Name, port, pod.Name, k8s.ProxyOpaquePortsAnnotation)
+						return fmt.Errorf("service %s expects target port %s to be opaque; add it to pod %s %s annotation", service.Name, strPort, pod.Name, k8s.ProxyOpaquePortsAnnotation)
 					}
 				}
 			}
diff --git a/pkg/k8s/api.go b/pkg/k8s/api.go
index 967ca55b7..0ae270d9c 100644
--- a/pkg/k8s/api.go
+++ b/pkg/k8s/api.go
@@ -2,6 +2,7 @@ package k8s
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net/http"
 	"strings"
@@ -12,8 +13,10 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
-	"k8s.io/apimachinery/pkg/api/errors"
+	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/version"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
@@ -137,7 +140,7 @@ func (kubeAPI *KubernetesAPI) CheckVersion(versionInfo *version.Info) error {
 // NamespaceExists validates whether a given namespace exists.
 func (kubeAPI *KubernetesAPI) NamespaceExists(ctx context.Context, namespace string) (bool, error) {
 	ns, err := kubeAPI.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
-	if errors.IsNotFound(err) {
+	if kerrors.IsNotFound(err) {
 		return false, nil
 	}
 	if err != nil {
@@ -197,7 +200,7 @@ func (kubeAPI *KubernetesAPI) GetNamespaceWithExtensionLabel(ctx context.Context
 			return &ns, err
 		}
 	}
-	return nil, errors.NewNotFound(corev1.Resource("namespace"), value)
+	return nil, kerrors.NewNotFound(corev1.Resource("namespace"), value)
 }
 
 // GetPodStatus receives a pod and returns the pod status, based on `kubectl` logic.
@@ -285,3 +288,162 @@ func GetProxyVersion(pod corev1.Pod) string {
 	}
 	return ""
 }
+
+// GetPodsFor takes a resource string, queries the Kubernetes API, and returns a
+// list of pods belonging to that resource.
+func GetPodsFor(ctx context.Context, clientset kubernetes.Interface, namespace string, resource string) ([]corev1.Pod, error) {
+	elems := strings.Split(resource, "/")
+
+	if len(elems) == 1 {
+		return nil, errors.New("no resource name provided")
+	}
+
+	if len(elems) != 2 {
+		return nil, fmt.Errorf("invalid resource string: %s", resource)
+	}
+
+	typ, err := CanonicalResourceNameFromFriendlyName(elems[0])
+	if err != nil {
+		return nil, err
+	}
+	name := elems[1]
+
+	// special case if a single pod was specified
+	if typ == Pod {
+		pod, err := clientset.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		return []corev1.Pod{*pod}, nil
+	}
+
+	var matchLabels map[string]string
+	var ownerUID types.UID
+	switch typ {
+	case CronJob:
+		jobs, err := clientset.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
+		if err != nil {
+			return nil, err
+		}
+
+		var pods []corev1.Pod
+		for _, job := range jobs.Items {
+			if isOwner(job.GetUID(), job.GetOwnerReferences()) {
+				jobPods, err := GetPodsFor(ctx, clientset, namespace, fmt.Sprintf("%s/%s", Job, job.GetName()))
+				if err != nil {
+					return nil, err
+				}
+				pods = append(pods, jobPods...)
+			}
+		}
+		return pods, nil
+
+	case DaemonSet:
+		ds, err := clientset.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = ds.Spec.Selector.MatchLabels
+		ownerUID = ds.GetUID()
+
+	case Deployment:
+		deployment, err := clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = deployment.Spec.Selector.MatchLabels
+		ownerUID = deployment.GetUID()
+
+		replicaSets, err := clientset.AppsV1().ReplicaSets(namespace).List(
+			ctx,
+			metav1.ListOptions{
+				LabelSelector: labels.Set(matchLabels).AsSelector().String(),
+			},
+		)
+		if err != nil {
+			return nil, err
+		}
+
+		var pods []corev1.Pod
+		for _, rs := range replicaSets.Items {
+			if isOwner(ownerUID, rs.GetOwnerReferences()) {
+				podsRS, err := GetPodsFor(ctx, clientset, namespace, fmt.Sprintf("%s/%s", ReplicaSet, rs.GetName()))
+				if err != nil {
+					return nil, err
+				}
+				pods = append(pods, podsRS...)
+			}
+		}
+		return pods, nil
+
+	case Job:
+		job, err := clientset.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = job.Spec.Selector.MatchLabels
+		ownerUID = job.GetUID()
+
+	case ReplicaSet:
+		rs, err := clientset.AppsV1().ReplicaSets(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = rs.Spec.Selector.MatchLabels
+		ownerUID = rs.GetUID()
+
+	case ReplicationController:
+		rc, err := clientset.CoreV1().ReplicationControllers(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = rc.Spec.Selector
+		ownerUID = rc.GetUID()
+
+	case StatefulSet:
+		ss, err := clientset.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{})
+		if err != nil {
+			return nil, err
+		}
+		matchLabels = ss.Spec.Selector.MatchLabels
+		ownerUID = ss.GetUID()
+
+	default:
+		return nil, fmt.Errorf("unsupported resource type: %s", name)
+	}
+
+	podList, err := clientset.
+		CoreV1().
+		Pods(namespace).
+		List(
+			ctx,
+			metav1.ListOptions{
+				LabelSelector: labels.Set(matchLabels).AsSelector().String(),
+			},
+		)
+	if err != nil {
+		return nil, err
+	}
+
+	if ownerUID == "" {
+		return podList.Items, nil
+	}
+
+	pods := []corev1.Pod{}
+	for _, pod := range podList.Items {
+		if isOwner(ownerUID, pod.GetOwnerReferences()) {
+			pods = append(pods, pod)
+		}
+	}
+
+	return pods, nil
+}
+
+func isOwner(u types.UID, ownerRefs []metav1.OwnerReference) bool {
+	for _, or := range ownerRefs {
+		if u == or.UID {
+			return true
+		}
+	}
+	return false
+}
diff --git a/pkg/k8s/policy.go b/pkg/k8s/policy.go
new file mode 100644
index 000000000..d1f8f152c
--- /dev/null
+++ b/pkg/k8s/policy.go
@@ -0,0 +1,374 @@
+package k8s
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"strings"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/kubernetes"
+)
+
+// ServerAndAuthorization holds a server name and serverauthorization name.
+type ServerAndAuthorization struct {
+	Server              string
+	ServerAuthorization string
+}
+
+type id struct{ name, namespace string }
+
+// SazGVR is the GroupVersionResource for the ServerAuthorization resource.
+var SazGVR = schema.GroupVersionResource{
+	Group:    "policy.linkerd.io",
+	Version:  "v1alpha1",
+	Resource: "serverauthorizations",
+}
+
+// ServerGVR is the GroupVersionResource for the Server resource.
+var ServerGVR = schema.GroupVersionResource{
+	Group:    "policy.linkerd.io",
+	Version:  "v1alpha1",
+	Resource: "servers",
+}
+
+// ServerAuthorizationsForResource returns a list of Server-ServerAuthorization
+// pairs which select pods belonging to the given resource.
+func ServerAuthorizationsForResource(ctx context.Context, k8sAPI *KubernetesAPI, namespace string, resource string) ([]ServerAndAuthorization, error) {
+	pods, err := getPodsForResourceOrKind(ctx, k8sAPI, namespace, resource, "")
+	if err != nil {
+		return nil, err
+	}
+	podSet := make(map[id]struct{})
+	for _, pod := range pods {
+		podSet[id{pod.Name, pod.Namespace}] = struct{}{}
+	}
+
+	results := make([]ServerAndAuthorization, 0)
+
+	sazs, err := k8sAPI.DynamicClient.Resource(SazGVR).Namespace(namespace).List(ctx, metav1.ListOptions{})
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to get serverauthorization resources: %s\n", err)
+		os.Exit(1)
+	}
+
+	for _, saz := range sazs.Items {
+		var servers []unstructured.Unstructured
+
+		if name, found, _ := unstructured.NestedString(saz.UnstructuredContent(), "spec", "server", "name"); found {
+			server, err := k8sAPI.DynamicClient.Resource(ServerGVR).Namespace(saz.GetNamespace()).Get(ctx, name, metav1.GetOptions{})
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Failed to get server %s: %s\n", name, err)
+				os.Exit(1)
+			}
+			servers = []unstructured.Unstructured{*server}
+		} else if sel, found, _ := unstructured.NestedMap(saz.UnstructuredContent(), "spec", "server", "selector"); found {
+			selector := selector(sel)
+			serverList, err := k8sAPI.DynamicClient.Resource(ServerGVR).Namespace(saz.GetNamespace()).List(ctx, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Failed to get servers: %s\n", err)
+				os.Exit(1)
+			}
+			servers = serverList.Items
+		}
+
+		for _, server := range servers {
+			if sel, found, _ := unstructured.NestedMap(server.UnstructuredContent(), "spec", "podSelector"); found {
+				selector := selector(sel)
+				selectedPods, err := k8sAPI.CoreV1().Pods(server.GetNamespace()).List(ctx, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
+				if err != nil {
+					fmt.Fprintf(os.Stderr, "Failed to get pods: %s\n", err)
+					os.Exit(1)
+				}
+				if serverIncludesPod(server, selectedPods.Items, podSet) {
+					results = append(results, ServerAndAuthorization{server.GetName(), saz.GetName()})
+				}
+			}
+
+		}
+	}
+	return results, nil
+}
+
+// ServersForResource returns a list of Server names of Servers which select pods
+// belonging to the given resource.
+func ServersForResource(ctx context.Context, k8sAPI *KubernetesAPI, namespace string, resource string, labelSelector string) ([]string, error) {
+	pods, err := getPodsForResourceOrKind(ctx, k8sAPI, namespace, resource, labelSelector)
+	if err != nil {
+		return nil, err
+	}
+	podSet := make(map[id]struct{})
+	for _, pod := range pods {
+		podSet[id{pod.Name, pod.Namespace}] = struct{}{}
+	}
+
+	results := make([]string, 0)
+
+	servers, err := k8sAPI.DynamicClient.Resource(ServerGVR).Namespace(namespace).List(ctx, metav1.ListOptions{})
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to get serverauthorization resources: %s\n", err)
+		os.Exit(1)
+	}
+
+	for _, server := range servers.Items {
+		if sel, found, _ := unstructured.NestedMap(server.UnstructuredContent(), "spec", "podSelector"); found {
+			selector := selector(sel)
+			selectedPods, err := k8sAPI.CoreV1().Pods(server.GetNamespace()).List(ctx, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Failed to get pods: %s\n", err)
+				os.Exit(1)
+			}
+			if serverIncludesPod(server, selectedPods.Items, podSet) {
+				results = append(results, server.GetName())
+			}
+		}
+
+	}
+	return results, nil
+}
+
+// ServerAuthorizationsForServer returns a list of ServerAuthorization names of
+// ServerAuthorizations which select the given Server.
+func ServerAuthorizationsForServer(ctx context.Context, k8sAPI *KubernetesAPI, namespace string, server string) ([]string, error) {
+	results := make([]string, 0)
+
+	sazs, err := k8sAPI.DynamicClient.Resource(SazGVR).Namespace(namespace).List(ctx, metav1.ListOptions{})
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to get serverauthorization resources: %s\n", err)
+		os.Exit(1)
+	}
+
+	for _, saz := range sazs.Items {
+		if name, found, _ := unstructured.NestedString(saz.UnstructuredContent(), "spec", "server", "name"); found {
+			s, err := k8sAPI.DynamicClient.Resource(ServerGVR).Namespace(saz.GetNamespace()).Get(ctx, name, metav1.GetOptions{})
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Failed to get server %s: %s\n", name, err)
+				os.Exit(1)
+			}
+			if s.GetName() == server {
+				results = append(results, saz.GetName())
+			}
+		} else if sel, found, _ := unstructured.NestedMap(saz.UnstructuredContent(), "spec", "server", "selector"); found {
+			selector := selector(sel)
+			serverList, err := k8sAPI.DynamicClient.Resource(ServerGVR).Namespace(saz.GetNamespace()).List(ctx, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&selector)})
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Failed to get servers: %s\n", err)
+				os.Exit(1)
+			}
+			for _, s := range serverList.Items {
+				if s.GetName() == server {
+					results = append(results, saz.GetName())
+					break
+				}
+			}
+		}
+	}
+	return results, nil
+}
+
+func selector(selector map[string]interface{}) metav1.LabelSelector {
+	if labels, found, err := unstructured.NestedStringMap(selector, "matchLabels"); found && err == nil {
+		return metav1.LabelSelector{MatchLabels: labels}
+	}
+	if expressions, found, err := unstructured.NestedSlice(selector, "matchExpressions"); found && err == nil {
+		exprs := make([]metav1.LabelSelectorRequirement, len(expressions))
+		for i, expr := range expressions {
+			exprs[i] = matchExpression(expr)
+		}
+		return metav1.LabelSelector{MatchExpressions: exprs}
+	}
+	return metav1.LabelSelector{}
+}
+
+func matchExpression(expr interface{}) metav1.LabelSelectorRequirement {
+	if exprMap, ok := expr.(map[string]interface{}); ok {
+		if key, found, err := unstructured.NestedString(exprMap, "key"); found && err == nil {
+			if op, found, err := unstructured.NestedString(exprMap, "operator"); found && err == nil {
+				if values, found, err := unstructured.NestedStringSlice(exprMap, "values"); found && err == nil {
+					return metav1.LabelSelectorRequirement{
+						Key:      key,
+						Operator: metav1.LabelSelectorOperator(op),
+						Values:   values,
+					}
+				}
+			}
+		}
+	}
+	return metav1.LabelSelectorRequirement{}
+}
+
+func serverIncludesPod(server unstructured.Unstructured, serverPods []corev1.Pod, podSet map[id]struct{}) bool {
+	for _, pod := range serverPods {
+		if _, ok := podSet[id{pod.Name, pod.Namespace}]; ok {
+			if port, found, err := unstructured.NestedInt64(server.UnstructuredContent(), "spec", "port"); found && err == nil {
+				for _, container := range pod.Spec.Containers {
+					for _, p := range container.Ports {
+						if int32(port) == p.ContainerPort {
+							return true
+						}
+					}
+				}
+			}
+			if port, found, err := unstructured.NestedString(server.UnstructuredContent(), "spec", "port"); found && err == nil {
+				for _, container := range pod.Spec.Containers {
+					for _, p := range container.Ports {
+						if port == p.Name {
+							return true
+						}
+					}
+				}
+			}
+		}
+	}
+	return false
+}
+
+// getPodsForResourceOrKind is similar to getPodsForResource, but also supports
+// querying for all resources of a given kind (i.e. when resource name is unspecified).
+func getPodsForResourceOrKind(ctx context.Context, k8sAPI kubernetes.Interface, namespace string, resource string, labelSelector string) ([]corev1.Pod, error) {
+
+	elems := strings.Split(resource, "/")
+	if len(elems) > 2 {
+		return nil, fmt.Errorf("invalid resource: %s", resource)
+	}
+	if len(elems) == 2 {
+		pods, err := GetPodsFor(ctx, k8sAPI, namespace, resource)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+			os.Exit(1)
+		}
+		return pods, nil
+	}
+	pods := []corev1.Pod{}
+
+	typ, err := CanonicalResourceNameFromFriendlyName(elems[0])
+	if err != nil {
+		return nil, fmt.Errorf("invalid resource: %s", resource)
+	}
+
+	selector := metav1.ListOptions{
+		LabelSelector: labelSelector,
+	}
+
+	switch typ {
+	case Pod:
+		ps, err := k8sAPI.CoreV1().Pods(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+			os.Exit(1)
+		}
+		pods = append(pods, ps.Items...)
+
+	case CronJob:
+		jobs, err := k8sAPI.BatchV1().CronJobs(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get cronjobs: %s", err)
+			os.Exit(1)
+		}
+		for _, job := range jobs.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", CronJob, job.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case DaemonSet:
+		dss, err := k8sAPI.AppsV1().DaemonSets(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get demonsets: %s", err)
+			os.Exit(1)
+		}
+		for _, ds := range dss.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", DaemonSet, ds.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case Deployment:
+		deploys, err := k8sAPI.AppsV1().Deployments(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get deployments: %s", err)
+			os.Exit(1)
+		}
+		for _, deploy := range deploys.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", Deployment, deploy.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case Job:
+		jobs, err := k8sAPI.BatchV1().Jobs(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get jobs: %s", err)
+			os.Exit(1)
+		}
+		for _, job := range jobs.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", Job, job.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case ReplicaSet:
+		rss, err := k8sAPI.AppsV1().ReplicaSets(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get replicasets: %s", err)
+			os.Exit(1)
+		}
+		for _, rs := range rss.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", ReplicaSet, rs.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case ReplicationController:
+		rcs, err := k8sAPI.CoreV1().ReplicationControllers(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get replicationcontrollers: %s", err)
+			os.Exit(1)
+		}
+		for _, rc := range rcs.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", ReplicationController, rc.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	case StatefulSet:
+		sss, err := k8sAPI.AppsV1().StatefulSets(namespace).List(ctx, selector)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to get statefulsets: %s", err)
+			os.Exit(1)
+		}
+		for _, ss := range sss.Items {
+			ps, err := GetPodsFor(ctx, k8sAPI, namespace, fmt.Sprintf("%s/%s", StatefulSet, ss.Name))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "failed to get pods: %s", err)
+				os.Exit(1)
+			}
+			pods = append(pods, ps...)
+		}
+
+	default:
+		return nil, fmt.Errorf("unsupported resource type: %s", typ)
+	}
+	return pods, nil
+}
diff --git a/policy-controller/src/admission.rs b/policy-controller/src/admission.rs
index a35296267..2731eca8a 100644
--- a/policy-controller/src/admission.rs
+++ b/policy-controller/src/admission.rs
@@ -1,5 +1,6 @@
 use crate::api;
 use anyhow::{anyhow, bail, Result};
+use api::policy::ServerSpec;
 use kube::{api::Api, core::DynamicObject, ResourceExt};
 use std::convert::{Infallible, TryInto};
 use tracing::{debug, info, warn};
@@ -26,7 +27,7 @@ pub fn routes(client: kube::Client) -> BoxedFilter<(impl warp::Reply,)> {
 
             // Parse the server instance under review before doing anything with the API--i.e., if
             // this fails we don't have to waste the API calls.
-            let (ns, review_server) = match parse_server(req) {
+            let (ns, name, review_spec) = match parse_server(req) {
                 Ok(s) => s,
                 Err(error) => {
                     warn!(%error, "Failed to deserialize server from admission request");
@@ -48,10 +49,10 @@ pub fn routes(client: kube::Client) -> BoxedFilter<(impl warp::Reply,)> {
             };
 
             // If validation fails, deny admission.
-            let rsp = match validate(&review_server, &*servers.items) {
+            let rsp = match validate(&name, &review_spec, &*servers.items) {
                 Ok(()) => rsp,
                 Err(error) => {
-                    info!(%error, %ns, name = %review_server.name(), "Denying server");
+                    info!(%error, %ns, %name, "Denying server");
                     rsp.deny(error)
                 }
             };
@@ -72,27 +73,37 @@ fn ok(reply: impl warp::Reply + 'static) -> Result<Box<dyn warp::Reply>, Infalli
 }
 
 /// Parses a `Server` instance and it's namespace from the admission request.
-fn parse_server(req: Request) -> Result<(String, api::policy::Server)> {
+fn parse_server(req: Request) -> Result<(String, String, api::policy::ServerSpec)> {
     let obj = req.object.ok_or_else(|| anyhow!("missing server"))?;
-    let server = serde_json::from_value::<api::policy::Server>(obj.data)?;
-    let ns = server
+    let ns = obj
         .namespace()
         .ok_or_else(|| anyhow!("no 'namespace' field set on server"))?;
-    Ok((ns, server))
+    let name = obj.name();
+    let data = obj
+        .data
+        .get("spec")
+        .cloned()
+        .ok_or_else(|| anyhow!("no 'spec' field set on server"))?;
+    let spec = serde_json::from_value::<ServerSpec>(data)?;
+    Ok((ns, name, spec))
 }
 
 /// Validates a new server (`review`) against existing `servers`.
-fn validate(review: &api::policy::Server, servers: &[api::policy::Server]) -> Result<()> {
+fn validate(
+    review_name: &str,
+    review_spec: &api::policy::ServerSpec,
+    servers: &[api::policy::Server],
+) -> Result<()> {
     for s in servers {
         // If the port and pod selectors select the same resources, fail the admission of the
         // server. Ignore existing instances of this Server (e.g., if the server's metadata is
         // changing).
-        if s.name() != review.name()
+        if s.name() != review_name
             // TODO(ver) this isn't rigorous about detecting servers that select the same port if one port
             // specifies a numeric port and the other specifies the port's name.
-            && s.spec.port == review.spec.port
+            && s.spec.port == review_spec.port
             // TODO(ver) We can probably detect overlapping selectors more effectively.
-            && s.spec.pod_selector == review.spec.pod_selector
+            && s.spec.pod_selector == review_spec.pod_selector
         {
             bail!("identical server spec already exists");
         }
diff --git a/viz/charts/linkerd-viz/templates/admin-policy.yaml b/viz/charts/linkerd-viz/templates/admin-policy.yaml
new file mode 100644
index 000000000..d361224d0
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/admin-policy.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
diff --git a/viz/charts/linkerd-viz/templates/grafana-policy.yaml b/viz/charts/linkerd-viz/templates/grafana-policy.yaml
new file mode 100644
index 000000000..2282f2514
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/grafana-policy.yaml
@@ -0,0 +1,37 @@
+{{ if .Values.grafana.enabled -}}
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+{{ end -}}
diff --git a/viz/charts/linkerd-viz/templates/metrics-api-policy.yaml b/viz/charts/linkerd-viz/templates/metrics-api-policy.yaml
new file mode 100644
index 000000000..ebbf4f949
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/metrics-api-policy.yaml
@@ -0,0 +1,37 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
diff --git a/viz/charts/linkerd-viz/templates/proxy-admin-policy.yaml b/viz/charts/linkerd-viz/templates/proxy-admin-policy.yaml
new file mode 100644
index 000000000..54831784f
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/proxy-admin-policy.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
diff --git a/viz/charts/linkerd-viz/templates/tap-injector-policy.yaml b/viz/charts/linkerd-viz/templates/tap-injector-policy.yaml
new file mode 100644
index 000000000..4f7d8c0e5
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/tap-injector-policy.yaml
@@ -0,0 +1,35 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
diff --git a/viz/charts/linkerd-viz/templates/tap-policy.yaml b/viz/charts/linkerd-viz/templates/tap-policy.yaml
new file mode 100644
index 000000000..f897c8fa2
--- /dev/null
+++ b/viz/charts/linkerd-viz/templates/tap-policy.yaml
@@ -0,0 +1,35 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: {{.Values.namespace}}
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: {{.Values.namespace}}
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    {{ include "partials.annotations.created-by" . }}
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
diff --git a/viz/cmd/authz.go b/viz/cmd/authz.go
new file mode 100644
index 000000000..3093111da
--- /dev/null
+++ b/viz/cmd/authz.go
@@ -0,0 +1,196 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/linkerd/linkerd2/cli/table"
+	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
+	"github.com/linkerd/linkerd2/pkg/healthcheck"
+	"github.com/linkerd/linkerd2/pkg/k8s"
+	"github.com/linkerd/linkerd2/viz/metrics-api/util"
+	"github.com/linkerd/linkerd2/viz/pkg/api"
+	"github.com/spf13/cobra"
+)
+
+// NewCmdAuthz creates a new cobra command `authz`
+func NewCmdAuthz() *cobra.Command {
+	options := newStatOptions()
+
+	cmd := &cobra.Command{
+		Use:   "authz [flags] resource",
+		Short: "Display stats for server authorizations for a resource",
+		Long:  "Display stats for server authorizations for a resource.",
+		Args:  cobra.MinimumNArgs(1),
+		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+
+			k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
+			if err != nil {
+				return nil, cobra.ShellCompDirectiveError
+			}
+
+			if options.namespace == "" {
+				options.namespace = pkgcmd.GetDefaultNamespace(kubeconfigPath, kubeContext)
+			}
+
+			cc := k8s.NewCommandCompletion(k8sAPI, options.namespace)
+
+			results, err := cc.Complete(args, toComplete)
+			if err != nil {
+				return nil, cobra.ShellCompDirectiveError
+			}
+
+			return results, cobra.ShellCompDirectiveDefault
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if options.namespace == "" {
+				options.namespace = pkgcmd.GetDefaultNamespace(kubeconfigPath, kubeContext)
+			}
+
+			k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
+			if err != nil {
+				return err
+			}
+			// The gRPC client is concurrency-safe, so we can reuse it in all the following goroutines
+			// https://github.com/grpc/grpc-go/issues/682
+			client := api.CheckClientOrExit(healthcheck.Options{
+				ControlPlaneNamespace: controlPlaneNamespace,
+				KubeConfig:            kubeconfigPath,
+				Impersonate:           impersonate,
+				ImpersonateGroup:      impersonateGroup,
+				KubeContext:           kubeContext,
+				APIAddr:               apiAddr,
+			})
+
+			var resource string
+			if len(args) == 1 {
+				resource = args[0]
+			} else if len(args) == 2 {
+				resource = args[0] + "/" + args[1]
+			}
+
+			cols := []table.Column{
+				table.NewColumn("SERVER").WithLeftAlign(),
+				table.NewColumn("AUTHZ").WithLeftAlign(),
+				table.NewColumn("SUCCESS"),
+				table.NewColumn("RPS"),
+				table.NewColumn("LATENCY_P50"),
+				table.NewColumn("LATENCY_P95"),
+				table.NewColumn("LATENCY_P99"),
+			}
+			rows := []table.Row{}
+
+			servers, err := k8s.ServersForResource(cmd.Context(), k8sAPI, options.namespace, resource, options.labelSelector)
+			if err != nil {
+				fmt.Fprint(os.Stderr, err.Error())
+				os.Exit(1)
+			}
+			for _, server := range servers {
+				sazs, err := k8s.ServerAuthorizationsForServer(cmd.Context(), k8sAPI, options.namespace, server)
+				if err != nil {
+					fmt.Fprint(os.Stderr, err.Error())
+					os.Exit(1)
+				}
+				for _, saz := range sazs {
+					requestParams := util.StatsSummaryRequestParams{
+						StatsBaseRequestParams: util.StatsBaseRequestParams{
+							TimeWindow:    options.timeWindow,
+							ResourceName:  saz,
+							ResourceType:  k8s.ServerAuthorization,
+							Namespace:     options.namespace,
+							AllNamespaces: false,
+						},
+						ToNamespace: options.namespace,
+					}
+					requestParams.ToName = server
+					requestParams.ToType = k8s.Server
+
+					req, err := util.BuildStatSummaryRequest(requestParams)
+					if err != nil {
+						return err
+					}
+					resp, err := requestStatsFromAPI(client, req)
+					if err != nil {
+						fmt.Fprint(os.Stderr, err.Error())
+						os.Exit(1)
+					}
+
+					for _, row := range respToRows(resp) {
+						if row.Stats == nil {
+							rows = append(rows, table.Row{
+								server,
+								saz,
+								"-",
+								"-",
+								"-",
+								"-",
+								"-",
+							})
+						} else {
+							rows = append(rows, table.Row{
+								server,
+								saz,
+								fmt.Sprintf("%.2f%%", getSuccessRate(row.Stats.GetSuccessCount(), row.Stats.GetFailureCount())*100),
+								fmt.Sprintf("%.1frps", getRequestRate(row.Stats.GetSuccessCount(), row.Stats.GetFailureCount(), row.TimeWindow)),
+								fmt.Sprintf("%dms", row.Stats.LatencyMsP50),
+								fmt.Sprintf("%dms", row.Stats.LatencyMsP95),
+								fmt.Sprintf("%dms", row.Stats.LatencyMsP99),
+							})
+						}
+					}
+				}
+
+				// Unauthorized
+				requestParams := util.StatsSummaryRequestParams{
+					StatsBaseRequestParams: util.StatsBaseRequestParams{
+						TimeWindow:    options.timeWindow,
+						ResourceName:  server,
+						ResourceType:  k8s.Server,
+						Namespace:     options.namespace,
+						AllNamespaces: false,
+					},
+					ToNamespace:   options.namespace,
+					LabelSelector: options.labelSelector,
+				}
+
+				req, err := util.BuildStatSummaryRequest(requestParams)
+				if err != nil {
+					return err
+				}
+				resp, err := requestStatsFromAPI(client, req)
+				if err != nil {
+					fmt.Fprint(os.Stderr, err.Error())
+					os.Exit(1)
+				}
+				for _, row := range respToRows(resp) {
+					if row.SrvStats != nil && row.SrvStats.DeniedCount > 0 {
+						rows = append(rows, table.Row{
+							server,
+							"[UNAUTHORIZED]",
+							"-",
+							fmt.Sprintf("%.1frps", getRequestRate(row.SrvStats.DeniedCount, 0, row.TimeWindow)),
+							"-",
+							"-",
+							"-",
+						})
+					}
+				}
+			}
+
+			data := table.NewTable(cols, rows)
+			data.Render(os.Stdout)
+
+			return nil
+		},
+	}
+
+	cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace of the specified resource")
+	cmd.PersistentFlags().StringVarP(&options.timeWindow, "time-window", "t", options.timeWindow, "Stat window (for example: \"15s\", \"1m\", \"10m\", \"1h\"). Needs to be at least 15s.")
+	cmd.PersistentFlags().StringVarP(&options.outputFormat, "output", "o", options.outputFormat, "Output format; one of: \"table\" or \"json\" or \"wide\"")
+	cmd.PersistentFlags().StringVarP(&options.labelSelector, "selector", "l", options.labelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='")
+
+	pkgcmd.ConfigureNamespaceFlagCompletion(
+		cmd, []string{"namespace"},
+		kubeconfigPath, impersonate, impersonateGroup, kubeContext)
+	return cmd
+}
diff --git a/viz/cmd/install.go b/viz/cmd/install.go
index ea67f9f0f..a1f62cb03 100644
--- a/viz/cmd/install.go
+++ b/viz/cmd/install.go
@@ -29,12 +29,18 @@ var (
 		"templates/tap-rbac.yaml",
 		"templates/web-rbac.yaml",
 		"templates/psp.yaml",
+		"templates/admin-policy.yaml",
+		"templates/proxy-admin-policy.yaml",
 		"templates/metrics-api.yaml",
+		"templates/metrics-api-policy.yaml",
 		"templates/grafana.yaml",
+		"templates/grafana-policy.yaml",
 		"templates/prometheus.yaml",
 		"templates/tap.yaml",
+		"templates/tap-policy.yaml",
 		"templates/tap-injector-rbac.yaml",
 		"templates/tap-injector.yaml",
+		"templates/tap-injector-policy.yaml",
 		"templates/web.yaml",
 		"templates/service-profiles.yaml",
 	}
diff --git a/viz/cmd/root.go b/viz/cmd/root.go
index e832da7ae..9578c0c8f 100644
--- a/viz/cmd/root.go
+++ b/viz/cmd/root.go
@@ -76,6 +76,7 @@ func NewCmdViz() *cobra.Command {
 	vizCmd.PersistentFlags().StringArrayVar(&impersonateGroup, "as-group", []string{}, "Group to impersonate for Kubernetes operations")
 	vizCmd.PersistentFlags().StringVar(&apiAddr, "api-addr", "", "Override kubeconfig and communicate directly with the control plane at host:port (mostly for testing)")
 	vizCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Turn on debug logging")
+	vizCmd.AddCommand(NewCmdAuthz())
 	vizCmd.AddCommand(NewCmdCheck())
 	vizCmd.AddCommand(NewCmdDashboard())
 	vizCmd.AddCommand(NewCmdEdges())
diff --git a/viz/metrics-api/prometheus.go b/viz/metrics-api/prometheus.go
index a901e5e3c..0f05b7a09 100644
--- a/viz/metrics-api/prometheus.go
+++ b/viz/metrics-api/prometheus.go
@@ -118,8 +118,14 @@ func promDstGroupByLabelNames(resource *pb.Resource) model.LabelNames {
 func promQueryLabels(resource *pb.Resource) model.LabelSet {
 	set := model.LabelSet{}
 	if resource != nil {
-		if resource.Name != "" && resource.GetType() != k8s.Service {
-			set[promResourceType(resource)] = model.LabelValue(resource.Name)
+		if resource.Name != "" {
+			if resource.GetType() == k8s.Server {
+				set[serverLabel] = model.LabelValue(resource.GetName())
+			} else if resource.GetType() == k8s.ServerAuthorization {
+				set[serverAuthorizationLabel] = model.LabelValue(resource.GetName())
+			} else if resource.GetType() != k8s.Service {
+				set[promResourceType(resource)] = model.LabelValue(resource.Name)
+			}
 		}
 		if shouldAddNamespaceLabel(resource) {
 			set[namespaceLabel] = model.LabelValue(resource.Namespace)
diff --git a/viz/metrics-api/stat_summary.go b/viz/metrics-api/stat_summary.go
index a26348716..eba146cb0 100644
--- a/viz/metrics-api/stat_summary.go
+++ b/viz/metrics-api/stat_summary.go
@@ -24,20 +24,6 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
 )
 
-var (
-	serverGroupVersionResource = schema.GroupVersionResource{
-		Group:    "policy.linkerd.io",
-		Version:  "v1alpha1",
-		Resource: "servers",
-	}
-
-	serverAuthorizationGroupVersionResource = schema.GroupVersionResource{
-		Group:    "policy.linkerd.io",
-		Version:  "v1alpha1",
-		Resource: "serverauthorizations",
-	}
-)
-
 type resourceResult struct {
 	res *pb.StatTable
 	err error
@@ -406,9 +392,9 @@ func (s *grpcServer) getPolicyResourceKeys(req *pb.StatSummaryRequest) ([]rKey,
 
 	var gvr schema.GroupVersionResource
 	if req.GetSelector().Resource.GetType() == k8s.Server {
-		gvr = serverGroupVersionResource
+		gvr = k8s.ServerGVR
 	} else if req.GetSelector().Resource.GetType() == k8s.ServerAuthorization {
-		gvr = serverAuthorizationGroupVersionResource
+		gvr = k8s.SazGVR
 	}
 
 	res := req.GetSelector().GetResource()
diff --git a/web/app/package.json b/web/app/package.json
index 537bb519c..11fd4a668 100644
--- a/web/app/package.json
+++ b/web/app/package.json
@@ -22,7 +22,7 @@
     "d3-force": "3.0.0",
     "d3-format": "3.0.1",
     "d3-selection": "3.0.0",
-    "date-fns": "2.23.0",
+    "date-fns": "2.24.0",
     "jest-progress-bar-reporter": "^1.0.21",
     "locales-detector": "3.0.2",
     "lodash": "4.17.21",
@@ -64,7 +64,7 @@
     "eslint-plugin-import": "^2.24.2",
     "eslint-plugin-jsx-a11y": "^6.4.1",
     "eslint-plugin-promise": "^5.1.0",
-    "eslint-plugin-react": "^7.25.1",
+    "eslint-plugin-react": "^7.25.2",
     "eslint-plugin-react-hooks": "^4.2.0",
     "eslint-webpack-plugin": "^3.0.1",
     "file-loader": "^6.2.0",
@@ -78,7 +78,7 @@
     "sinon-stub-promise": "4.0.0",
     "style-loader": "^3.2.1",
     "url-loader": "^4.1.1",
-    "webpack": "^5.52.1",
+    "webpack": "^5.53.0",
     "webpack-bundle-analyzer": "4.4.2",
     "webpack-cli": "4.8.0",
     "webpack-dev-server": "4.2.1"
diff --git a/web/app/yarn.lock b/web/app/yarn.lock
index de7717b63..efd8d5fbc 100644
--- a/web/app/yarn.lock
+++ b/web/app/yarn.lock
@@ -3403,10 +3403,10 @@ data-urls@^2.0.0:
     whatwg-mimetype "^2.3.0"
     whatwg-url "^8.0.0"
 
-date-fns@2.23.0, date-fns@^2.16.1:
-  version "2.23.0"
-  resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9"
-  integrity sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==
+date-fns@2.24.0, date-fns@^2.16.1:
+  version "2.24.0"
+  resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.24.0.tgz#7d86dc0d93c87b76b63d213b4413337cfd1c105d"
+  integrity sha512-6ujwvwgPID6zbI0o7UbURi2vlLDR9uP26+tW6Lg+Ji3w7dd0i3DOcjcClLjLPranT60SSEFBwdSyYwn/ZkPIuw==
 
 debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
   version "2.6.9"
@@ -4047,10 +4047,10 @@ eslint-plugin-react-hooks@^4.2.0:
   resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556"
   integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==
 
-eslint-plugin-react@^7.25.1:
-  version "7.25.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.25.1.tgz#9286b7cd9bf917d40309760f403e53016eda8331"
-  integrity sha512-P4j9K1dHoFXxDNP05AtixcJEvIT6ht8FhYKsrkY0MPCPaUMYijhpWwNiRDZVtA8KFuZOkGSeft6QwH8KuVpJug==
+eslint-plugin-react@^7.25.2:
+  version "7.25.2"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.25.2.tgz#d567a217d306b76dd110561f28074e2328ae38f8"
+  integrity sha512-elx4585wgmryanJK4C5IoSKQyVZ+e7H0t2JOOtJNBql0cuercvSShvRReuLBbfx8687yW5yv+UL7pXwMsd6adQ==
   dependencies:
     array-includes "^3.1.3"
     array.prototype.flatmap "^1.2.4"
@@ -9565,10 +9565,10 @@ webpack-sources@^3.2.0:
   resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.0.tgz#b16973bcf844ebcdb3afde32eda1c04d0b90f89d"
   integrity sha512-fahN08Et7P9trej8xz/Z7eRu8ltyiygEo/hnRi9KqBUs80KeDcnf96ZJo++ewWd84fEf3xSX9bp4ZS9hbw0OBw==
 
-webpack@^5.52.1:
-  version "5.52.1"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.52.1.tgz#2dc1d9029ecb7acfb80da7bf67baab67baa517a7"
-  integrity sha512-wkGb0hLfrS7ML3n2xIKfUIwHbjB6gxwQHyLmVHoAqEQBw+nWo+G6LoHL098FEXqahqximsntjBLuewStrnJk0g==
+webpack@^5.53.0:
+  version "5.53.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.53.0.tgz#f463cd9c6fc1356ae4b9b7ac911fd1f5b2df86af"
+  integrity sha512-RZ1Z3z3ni44snoWjfWeHFyzvd9HMVYDYC5VXmlYUT6NWgEOWdCNpad5Fve2CzzHoRED7WtsKe+FCyP5Vk4pWiQ==
   dependencies:
     "@types/eslint-scope" "^3.7.0"
     "@types/estree" "^0.0.50"


Test patch:
diff --git a/cli/cmd/metrics_test.go b/cli/cmd/metrics_test.go
deleted file mode 100644
index d28cda687..000000000
--- a/cli/cmd/metrics_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package cmd
-
-import (
-	"context"
-	"testing"
-
-	"github.com/linkerd/linkerd2/pkg/k8s"
-)
-
-func TestGetPodsFor(t *testing.T) {
-
-	configs := []string{
-		// pod-1
-		`apiVersion: v1
-kind: Pod
-metadata:
-  name: pod-1
-  namespace: ns
-  uid: pod-1
-  labels:
-    app: foo
-  ownerReferences:
-  - apiVersion: apps/v1
-    controller: true
-    kind: ReplicaSet
-    name: rs-1
-    uid: rs-1
-`,
-		// rs-1
-		`apiVersion: apps/v1
-kind: ReplicaSet
-metadata:
-  name: rs-1
-  namespace: ns
-  uid: rs-1
-  labels:
-    app: foo
-  ownerReferences:
-  - apiVersion: apps/v1
-    controller: true
-    kind: Deployment
-    name: deploy-1
-    uid: deploy-1
-spec:
-  selector:
-    matchLabels:
-      app: foo
-`,
-		// deploy-1
-		`apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: deploy-1
-  namespace: ns
-  uid: deploy-1
-spec:
-  selector:
-    matchLabels:
-      app: foo
-`,
-		// pod-2
-		`apiVersion: v1
-kind: Pod
-metadata:
-  name: pod-2
-  namespace: ns
-  uid: pod-2
-  labels:
-    app: foo
-  ownerReferences:
-  - apiVersion: apps/v1
-    controller: true
-    kind: ReplicaSet
-    name: rs-2
-    uid: rs-2
-`,
-		// rs-2
-		`apiVersion: apps/v1
-kind: ReplicaSet
-metadata:
-  name: rs-2
-  namespace: ns
-  uid: rs-2
-  labels:
-    app: foo
-  ownerReferences:
-  - apiVersion: apps/v1
-    controller: true
-    kind: Deployment
-    name: deploy-2
-    uid: deploy-2
-spec:
-  selector:
-    matchLabels:
-     app: foo
-`,
-		// deploy-2
-		`apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: deploy-2
-  namespace: ns
-  uid: deploy-2
-spec:
-  selector:
-    matchLabels:
-      app: foo
-`}
-
-	k8sClient, err := k8s.NewFakeAPI(configs...)
-	if err != nil {
-		t.Fatalf("Unexpected error %s", err)
-	}
-
-	// Both pod-1 and pod-2 have labels which match deploy-1's selector.
-	// However, only pod-1 is owned by deploy-1 according to the owner references.
-	// Owner references should be considered authoritative to resolve ambiguity
-	// when deployments have overlapping seletors.
-	pods, err := getPodsFor(context.Background(), k8sClient, "ns", "deploy/deploy-1")
-	if err != nil {
-		t.Fatalf("Unexpected error %s", err)
-	}
-
-	if len(pods) != 1 {
-		for _, p := range pods {
-			t.Logf("%s/%s", p.Namespace, p.Name)
-		}
-		t.Fatalf("Expected 1 pod, got %d", len(pods))
-	}
-}
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
index bd7da9991..e7ed798de 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
@@ -73,7 +73,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
index f09ce5203..eb826eab0 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
@@ -73,7 +73,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -267,7 +267,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
index 0119f128e..06011253a 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
@@ -73,7 +73,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_contour.golden.yml b/cli/cmd/testdata/inject_contour.golden.yml
index 533d67477..0d6973e17 100644
--- a/cli/cmd/testdata/inject_contour.golden.yml
+++ b/cli/cmd/testdata/inject_contour.golden.yml
@@ -81,7 +81,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
index 3ff6b5c00..175029d29 100644
--- a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -280,7 +280,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -485,7 +485,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -690,7 +690,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
index ff0b1ac79..6a83e5088 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
index 98a21eb1e..7f6567a0d 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
index d0564c8ea..b35120a45 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
@@ -85,7 +85,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
index 3f0a282df..744f0e9b4 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -280,7 +280,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
index 31c80cce7..dfe50805d 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
@@ -76,7 +76,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
index 345859410..01fc1c22b 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
index 23f9d725a..e3c2f3715 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_no_init_container.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_no_init_container.golden.yml
index b67d20e39..5782c8471 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_no_init_container.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_no_init_container.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
index 0c716e05e..c976adadc 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
@@ -76,7 +76,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
index 90025916b..60d8899c0 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
@@ -77,7 +77,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
index ad3f40036..23342dca4 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
@@ -75,7 +75,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_list.golden.yml b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
index 2a7ccd9c9..7320a08c7 100644
--- a/cli/cmd/testdata/inject_emojivoto_list.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
@@ -77,7 +77,7 @@ items:
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
             value: 10000ms
           - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-            value: 25,443,587,3306,4444,5432,6379,9300,11211
+            value: 25,587,3306,4444,5432,6379,9300,11211
           - name: LINKERD2_PROXY_DESTINATION_CONTEXT
             value: |
               {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -281,7 +281,7 @@ items:
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
             value: 10000ms
           - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-            value: 25,443,587,3306,4444,5432,6379,9300,11211
+            value: 25,587,3306,4444,5432,6379,9300,11211
           - name: LINKERD2_PROXY_DESTINATION_CONTEXT
             value: |
               {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml b/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
index 02e091a8c..ca507a67d 100644
--- a/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
@@ -77,7 +77,7 @@ items:
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
             value: 10000ms
           - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-            value: 25,443,587,3306,4444,5432,6379,9300,11211
+            value: 25,587,3306,4444,5432,6379,9300,11211
           - name: LINKERD2_PROXY_DESTINATION_CONTEXT
             value: |
               {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -281,7 +281,7 @@ items:
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
             value: 10000ms
           - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-            value: 25,443,587,3306,4444,5432,6379,9300,11211
+            value: 25,587,3306,4444,5432,6379,9300,11211
           - name: LINKERD2_PROXY_DESTINATION_CONTEXT
             value: |
               {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
index 2ab0eef68..a90223d85 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
@@ -65,7 +65,7 @@ spec:
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
       value: 10000ms
     - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-      value: 25,443,587,3306,4444,5432,6379,9300,11211
+      value: 25,587,3306,4444,5432,6379,9300,11211
     - name: LINKERD2_PROXY_DESTINATION_CONTEXT
       value: |
         {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
index 2142ce003..7f8a7524a 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
@@ -68,7 +68,7 @@ spec:
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
       value: 10000ms
     - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-      value: 25,443,587,3306,4444,5432,6379,9300,11211
+      value: 25,587,3306,4444,5432,6379,9300,11211
     - name: LINKERD2_PROXY_DESTINATION_CONTEXT
       value: |
         {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
index 5908d45f5..f1e1a02a5 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
@@ -67,7 +67,7 @@ spec:
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
       value: 10000ms
     - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-      value: 25,443,587,3306,4444,5432,6379,9300,11211
+      value: 25,587,3306,4444,5432,6379,9300,11211
     - name: LINKERD2_PROXY_DESTINATION_CONTEXT
       value: |
         {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
index 24c85e3e0..2bbbe69e1 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
@@ -69,7 +69,7 @@ spec:
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
       value: 10000ms
     - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-      value: 25,443,587,3306,4444,5432,6379,9300,11211
+      value: 25,587,3306,4444,5432,6379,9300,11211
     - name: LINKERD2_PROXY_DESTINATION_CONTEXT
       value: |
         {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
index 40ec6678c..937a7b1e2 100644
--- a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
@@ -76,7 +76,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
index a39c44a65..06b3c5061 100644
--- a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
+++ b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
@@ -71,7 +71,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -278,7 +278,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
index 40fb50f85..ccd4263c2 100644
--- a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
@@ -92,7 +92,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: 25,443,587,3306,4444,5432,6379,9300,11211
+          value: 25,587,3306,4444,5432,6379,9300,11211
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden
index 16eb07999..b0e9e13b6 100644
--- a/cli/cmd/testdata/install_controlplane_tracing_output.golden
+++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1414,7 +1414,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1483,7 +1483,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1573,7 +1573,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1647,7 +1646,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1712,7 +1710,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1785,7 +1783,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         - -trace-collector=collector.linkerd-jaeger.svc.cluster.local:55678
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
@@ -1882,7 +1880,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2064,7 +2062,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2170,7 +2168,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_custom_domain.golden b/cli/cmd/testdata/install_custom_domain.golden
index b7b612178..15e9dc507 100644
--- a/cli/cmd/testdata/install_custom_domain.golden
+++ b/cli/cmd/testdata/install_custom_domain.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1482,7 +1482,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1572,7 +1572,6 @@ metadata:
     linkerd.io/control-plane-ns: l5d
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1646,7 +1645,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1711,7 +1709,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1784,7 +1782,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1880,7 +1878,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2062,7 +2060,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2168,7 +2166,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden
index 64ded8c74..f887cfbc2 100644
--- a/cli/cmd/testdata/install_custom_registry.golden
+++ b/cli/cmd/testdata/install_custom_registry.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1482,7 +1482,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: my.custom.registry/linkerd-io/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1572,7 +1572,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1646,7 +1645,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1711,7 +1709,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1784,7 +1782,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: my.custom.registry/linkerd-io/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1880,7 +1878,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: my.custom.registry/linkerd-io/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2062,7 +2060,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2168,7 +2166,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: my.custom.registry/linkerd-io/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 4704529a0..0bdebdde0 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1482,7 +1482,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1572,7 +1572,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1646,7 +1645,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1711,7 +1709,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1784,7 +1782,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1880,7 +1878,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2062,7 +2060,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2168,7 +2166,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
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 e74c7f53f..b06979d36 100644
--- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden
+++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1482,7 +1482,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1572,7 +1572,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1646,7 +1645,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1711,7 +1709,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1784,7 +1782,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1880,7 +1878,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2062,7 +2060,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2168,7 +2166,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index 8f0abaf09..e32c6c3f1 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -1164,7 +1164,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1482,7 +1482,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1556,7 +1556,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1646,7 +1646,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1739,7 +1738,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1824,7 +1822,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1902,7 +1900,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -2004,7 +2002,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2215,7 +2213,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2332,7 +2330,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index 9629edd18..ed0bb1334 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -1164,7 +1164,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1482,7 +1482,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1556,7 +1556,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1646,7 +1646,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1739,7 +1738,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1824,7 +1822,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1902,7 +1900,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -2004,7 +2002,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2215,7 +2213,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2332,7 +2330,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_heartbeat_disabled_output.golden b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
index 4e892a3c4..a35fe149c 100644
--- a/cli/cmd/testdata/install_heartbeat_disabled_output.golden
+++ b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
@@ -1077,7 +1077,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1344,7 +1344,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1413,7 +1413,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1503,7 +1503,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1577,7 +1576,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1642,7 +1640,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1715,7 +1713,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1811,7 +1809,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1944,7 +1942,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2050,7 +2048,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_helm_output.golden b/cli/cmd/testdata/install_helm_output.golden
index 89dddad3c..043d6d916 100644
--- a/cli/cmd/testdata/install_helm_output.golden
+++ b/cli/cmd/testdata/install_helm_output.golden
@@ -1142,7 +1142,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1404,7 +1404,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1473,7 +1473,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1565,7 +1565,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/helm linkerd-version
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1639,7 +1638,6 @@ spec:
         linkerd.io/created-by: linkerd/helm linkerd-version
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: test-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1704,7 +1702,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1777,7 +1775,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1873,7 +1871,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2059,7 +2057,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2165,7 +2163,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "111"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_helm_output_ha.golden b/cli/cmd/testdata/install_helm_output_ha.golden
index 64b054a9b..710ada695 100644
--- a/cli/cmd/testdata/install_helm_output_ha.golden
+++ b/cli/cmd/testdata/install_helm_output_ha.golden
@@ -1160,7 +1160,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1473,7 +1473,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1547,7 +1547,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1639,7 +1639,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/helm linkerd-version
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1732,7 +1731,6 @@ spec:
         linkerd.io/created-by: linkerd/helm linkerd-version
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: test-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1817,7 +1815,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1895,7 +1893,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1997,7 +1995,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2212,7 +2210,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2329,7 +2327,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "111"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_helm_output_ha_labels.golden b/cli/cmd/testdata/install_helm_output_ha_labels.golden
index 9996c8537..621d92ece 100644
--- a/cli/cmd/testdata/install_helm_output_ha_labels.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_labels.golden
@@ -1164,7 +1164,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1481,7 +1481,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1555,7 +1555,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,444"
         - --outbound-ports-to-ignore
-        - "333,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1647,7 +1647,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/helm linkerd-version
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1742,7 +1741,6 @@ spec:
         linkerd.io/proxy-version: test-proxy-version
         asda: fasda
         bingo: bongo
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1829,7 +1827,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1907,7 +1905,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -2009,7 +2007,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,444"
         - --outbound-ports-to-ignore
-        - "333,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2232,7 +2230,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2349,7 +2347,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,444"
         - --outbound-ports-to-ignore
-        - "333,443"
+        - "333"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
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 e147104cf..7d9648994 100644
--- a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
@@ -1160,7 +1160,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1473,7 +1473,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1547,7 +1547,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1639,7 +1639,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/helm linkerd-version
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1732,7 +1731,6 @@ spec:
         linkerd.io/created-by: linkerd/helm linkerd-version
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: test-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1817,7 +1815,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1895,7 +1893,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=test.trust.domain
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:linkerd-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1997,7 +1995,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2212,7 +2210,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2329,7 +2327,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,222"
         - --outbound-ports-to-ignore
-        - "111,443"
+        - "111"
         image: cr.l5d.io/linkerd/proxy-init:test-proxy-init-version
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index 9a4b023e3..9af4d5a31 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1534,7 +1534,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1608,7 +1607,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1673,7 +1671,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1746,7 +1744,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1986,7 +1984,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index 45cc7ef62..b1d212420 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -1574,7 +1574,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: CliVersion
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1648,7 +1647,6 @@ spec:
         linkerd.io/created-by: CliVersion
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: ProxyVersion
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden
index cb79fcec8..f68db4694 100644
--- a/cli/cmd/testdata/install_proxy_ignores.golden
+++ b/cli/cmd/testdata/install_proxy_ignores.golden
@@ -1146,7 +1146,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1413,7 +1413,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1482,7 +1482,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
-        - "5432,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1572,7 +1572,6 @@ metadata:
     linkerd.io/control-plane-ns: linkerd
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1646,7 +1645,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1711,7 +1709,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1784,7 +1782,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=cluster.local
         - -identity-trust-domain=cluster.local
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1880,7 +1878,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
-        - "5432,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2062,7 +2060,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2168,7 +2166,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,22,8100-8102"
         - --outbound-ports-to-ignore
-        - "5432,443"
+        - "5432"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/cli/cmd/testdata/install_values_file.golden b/cli/cmd/testdata/install_values_file.golden
index 4af482619..74b80aa0c 100644
--- a/cli/cmd/testdata/install_values_file.golden
+++ b/cli/cmd/testdata/install_values_file.golden
@@ -1132,7 +1132,7 @@ data:
       isIngress: false
       logFormat: plain
       logLevel: warn,linkerd=info
-      opaquePorts: 25,443,587,3306,4444,5432,6379,9300,11211
+      opaquePorts: 25,587,3306,4444,5432,6379,9300,11211
       outboundConnectTimeout: 1000ms
       podInboundPorts: ""
       ports:
@@ -1399,7 +1399,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1468,7 +1468,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -1558,7 +1558,6 @@ metadata:
     linkerd.io/control-plane-ns: l5d
   annotations:
     linkerd.io/created-by: linkerd/cli dev-undefined
-    config.linkerd.io/opaque-ports: "443"
 spec:
   type: ClusterIP
   selector:
@@ -1632,7 +1631,6 @@ spec:
         linkerd.io/created-by: linkerd/cli dev-undefined
         linkerd.io/identity-mode: default
         linkerd.io/proxy-version: install-proxy-version
-        config.linkerd.io/opaque-ports: "8443"
         config.linkerd.io/default-inbound-policy: "all-unauthenticated"
       labels:
         linkerd.io/control-plane-component: destination
@@ -1697,7 +1695,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -1770,7 +1768,7 @@ spec:
         - -enable-endpoint-slices=false
         - -cluster-domain=example.com
         - -identity-trust-domain=example.com
-        - -default-opaque-ports=25,443,587,3306,4444,5432,6379,9300,11211
+        - -default-opaque-ports=25,587,3306,4444,5432,6379,9300,11211
         image: cr.l5d.io/linkerd/controller:install-control-plane-version
         imagePullPolicy: IfNotPresent
         livenessProbe:
@@ -1866,7 +1864,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "443"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
@@ -2048,7 +2046,7 @@ spec:
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE
           value: 10000ms
         - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION
-          value: "25,443,587,3306,4444,5432,6379,9300,11211"
+          value: "25,587,3306,4444,5432,6379,9300,11211"
         - name: LINKERD2_PROXY_DESTINATION_CONTEXT
           value: |
             {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)"}
@@ -2154,7 +2152,7 @@ spec:
         - --inbound-ports-to-ignore
         - "4190,4191,4567,4568"
         - --outbound-ports-to-ignore
-        - "4567,4568,443"
+        - "4567,4568"
         image: cr.l5d.io/linkerd/proxy-init:v1.4.0
         imagePullPolicy: IfNotPresent
         name: linkerd-init
diff --git a/jaeger/cmd/testdata/install_collector_disabled.golden b/jaeger/cmd/testdata/install_collector_disabled.golden
index 8ee21f00c..6f0d37e57 100644
--- a/jaeger/cmd/testdata/install_collector_disabled.golden
+++ b/jaeger/cmd/testdata/install_collector_disabled.golden
@@ -9,6 +9,39 @@ metadata:
     linkerd.io/inject: enabled
     config.linkerd.io/proxy-await: "enabled"
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Jaeger Injector
 ###
@@ -90,6 +123,62 @@ spec:
     port: 443
     targetPort: jaeger-injector
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-webhook
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: jaeger-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: jaeger-injector
+  client:
+    # traffic coming from the kubelet and from kube-api
+    unauthenticated: true
+---
 ###
 ### Jaeger Injector RBAC
 ###
@@ -178,6 +267,7 @@ metadata:
   name: jaeger
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: jaeger
 spec:
   type: ClusterIP
@@ -195,6 +285,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: jaeger
     app.kubernetes.io/part-of: Linkerd
     component: jaeger
@@ -213,6 +304,7 @@ spec:
         prometheus.io/port: "14269"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: jaeger
     spec:
       nodeSelector:
@@ -234,3 +326,112 @@ spec:
           name: ui
       dnsPolicy: ClusterFirst
       serviceAccountName: jaeger
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: grpc
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-grpc
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: collector
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-admin
+  client:
+    meshTLS:
+      serviceAccounts:
+      # if not using linkerd-viz' prometheus, replace its SA here
+      - name: prometheus
+        namespace: linkerd-viz
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: ui
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-ui
+  client:
+    meshTLS:
+      serviceAccounts:
+      # for the optional dashboard integration
+      - name: web
+        namespace: linkerd-viz
diff --git a/jaeger/cmd/testdata/install_default.golden b/jaeger/cmd/testdata/install_default.golden
index a3c178878..ea28c7e33 100644
--- a/jaeger/cmd/testdata/install_default.golden
+++ b/jaeger/cmd/testdata/install_default.golden
@@ -9,6 +9,39 @@ metadata:
     linkerd.io/inject: enabled
     config.linkerd.io/proxy-await: "enabled"
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Jaeger Injector
 ###
@@ -90,6 +123,62 @@ spec:
     port: 443
     targetPort: jaeger-injector
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-webhook
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: jaeger-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: jaeger-injector
+  client:
+    # traffic coming from the kubelet and from kube-api
+    unauthenticated: true
+---
 ###
 ### collector RBAC
 ###
@@ -187,6 +276,7 @@ metadata:
   name: collector-config
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 data:
   collector-config: |
@@ -225,6 +315,7 @@ metadata:
   name: collector
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 spec:
   type: ClusterIP
@@ -256,6 +347,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: collector
     app.kubernetes.io/part-of: Linkerd
     component: collector
@@ -275,6 +367,7 @@ spec:
         prometheus.io/port: "8888"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: collector
     spec:
       nodeSelector:
@@ -299,6 +392,7 @@ spec:
             port: 13133
         name: ot-collector
         ports:
+        - containerPort: 13133
         - containerPort: 4317
         - containerPort: 55678
         - containerPort: 9411
@@ -330,6 +424,7 @@ metadata:
   name: jaeger
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: jaeger
 spec:
   type: ClusterIP
@@ -347,6 +442,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: jaeger
     app.kubernetes.io/part-of: Linkerd
     component: jaeger
@@ -365,6 +461,7 @@ spec:
         prometheus.io/port: "14269"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: jaeger
     spec:
       nodeSelector:
@@ -386,3 +483,231 @@ spec:
           name: ui
       dnsPolicy: ClusterFirst
       serviceAccountName: jaeger
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-otlp
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 4317
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-opencensus
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 55678
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-zipkin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 9411
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-jaeger-thrift
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14268
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14250
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 13133
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: collector
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: collector
+  client:
+    # allow connections from any pod (meshed or not) sending trace data
+    unauthenticated: true
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: grpc
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-grpc
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: collector
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-admin
+  client:
+    meshTLS:
+      serviceAccounts:
+      # if not using linkerd-viz' prometheus, replace its SA here
+      - name: prometheus
+        namespace: linkerd-viz
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: jaeger
+  port: ui
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-ui
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: jaeger-ui
+  client:
+    meshTLS:
+      serviceAccounts:
+      # for the optional dashboard integration
+      - name: web
+        namespace: linkerd-viz
diff --git a/jaeger/cmd/testdata/install_jaeger_disabled.golden b/jaeger/cmd/testdata/install_jaeger_disabled.golden
index 922ef38ea..29df97d17 100644
--- a/jaeger/cmd/testdata/install_jaeger_disabled.golden
+++ b/jaeger/cmd/testdata/install_jaeger_disabled.golden
@@ -9,6 +9,39 @@ metadata:
     linkerd.io/inject: enabled
     config.linkerd.io/proxy-await: "enabled"
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: jaeger
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Jaeger Injector
 ###
@@ -90,6 +123,62 @@ spec:
     port: 443
     targetPort: jaeger-injector
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-webhook
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: jaeger-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: jaeger
+      component: jaeger-injector
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: jaeger-injector
+  labels:
+    linkerd.io/extension: jaeger
+    component: jaeger-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: jaeger-injector
+  client:
+    # traffic coming from the kubelet and from kube-api
+    unauthenticated: true
+---
 ###
 ### collector RBAC
 ###
@@ -178,6 +267,7 @@ metadata:
   name: collector-config
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 data:
   collector-config: |
@@ -216,6 +306,7 @@ metadata:
   name: collector
   namespace: linkerd-jaeger
   labels:
+    linkerd.io/extension: jaeger
     component: collector
 spec:
   type: ClusterIP
@@ -247,6 +338,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
+    linkerd.io/extension: jaeger
     app.kubernetes.io/name: collector
     app.kubernetes.io/part-of: Linkerd
     component: collector
@@ -266,6 +358,7 @@ spec:
         prometheus.io/port: "8888"
         prometheus.io/scrape: "true"
       labels:
+        linkerd.io/extension: jaeger
         component: collector
     spec:
       nodeSelector:
@@ -290,6 +383,7 @@ spec:
             port: 13133
         name: ot-collector
         ports:
+        - containerPort: 13133
         - containerPort: 4317
         - containerPort: 55678
         - containerPort: 9411
@@ -311,3 +405,122 @@ spec:
             path: collector-config.yaml
           name: collector-config
         name: collector-config-val
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-otlp
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 4317
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-opencensus
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 55678
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-zipkin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 9411
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-jaeger-thrift
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14268
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-jaeger-grpc
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 14250
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-jaeger
+  name: collector-admin
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      component: collector
+  port: 13133
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-jaeger
+  name: collector
+  labels:
+    linkerd.io/extension: jaeger
+    component: collector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    selector:
+      matchLabels:
+        linkerd.io/extension: jaeger
+        component: collector
+  client:
+    # allow connections from any pod (meshed or not) sending trace data
+    unauthenticated: true
diff --git a/pkg/charts/linkerd2/values_test.go b/pkg/charts/linkerd2/values_test.go
index 237104557..230118f5a 100644
--- a/pkg/charts/linkerd2/values_test.go
+++ b/pkg/charts/linkerd2/values_test.go
@@ -99,7 +99,7 @@ func TestNewValues(t *testing.T) {
 			WaitBeforeExitSeconds:  0,
 			OutboundConnectTimeout: "1000ms",
 			InboundConnectTimeout:  "100ms",
-			OpaquePorts:            "25,443,587,3306,4444,5432,6379,9300,11211",
+			OpaquePorts:            "25,587,3306,4444,5432,6379,9300,11211",
 			Await:                  true,
 		},
 		ProxyInit: &ProxyInit{
diff --git a/pkg/healthcheck/healthcheck_test.go b/pkg/healthcheck/healthcheck_test.go
index 936df5139..f63acd032 100644
--- a/pkg/healthcheck/healthcheck_test.go
+++ b/pkg/healthcheck/healthcheck_test.go
@@ -3418,7 +3418,7 @@ subsets:
     protocol: TCP
 `,
 			},
-			expected: fmt.Errorf("\t* service svc expects 9200 to be opaque; add it to pod pod's config.linkerd.io/opaque-ports annotation"),
+			expected: fmt.Errorf("\t* service svc expects target port 9200 to be opaque; add it to pod pod config.linkerd.io/opaque-ports annotation"),
 		},
 		{
 			resources: []string{`
diff --git a/pkg/k8s/api_test.go b/pkg/k8s/api_test.go
index 8f04a88a9..b0d78f24e 100644
--- a/pkg/k8s/api_test.go
+++ b/pkg/k8s/api_test.go
@@ -1,6 +1,7 @@
 package k8s
 
 import (
+	"context"
 	"testing"
 
 	corev1 "k8s.io/api/core/v1"
@@ -303,3 +304,125 @@ status:
 		}
 	}
 }
+
+func TestGetPodsFor(t *testing.T) {
+
+	configs := []string{
+		// pod-1
+		`apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-1
+  namespace: ns
+  uid: pod-1
+  labels:
+    app: foo
+  ownerReferences:
+  - apiVersion: apps/v1
+    controller: true
+    kind: ReplicaSet
+    name: rs-1
+    uid: rs-1
+`,
+		// rs-1
+		`apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+  name: rs-1
+  namespace: ns
+  uid: rs-1
+  labels:
+    app: foo
+  ownerReferences:
+  - apiVersion: apps/v1
+    controller: true
+    kind: Deployment
+    name: deploy-1
+    uid: deploy-1
+spec:
+  selector:
+    matchLabels:
+      app: foo
+`,
+		// deploy-1
+		`apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deploy-1
+  namespace: ns
+  uid: deploy-1
+spec:
+  selector:
+    matchLabels:
+      app: foo
+`,
+		// pod-2
+		`apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-2
+  namespace: ns
+  uid: pod-2
+  labels:
+    app: foo
+  ownerReferences:
+  - apiVersion: apps/v1
+    controller: true
+    kind: ReplicaSet
+    name: rs-2
+    uid: rs-2
+`,
+		// rs-2
+		`apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+  name: rs-2
+  namespace: ns
+  uid: rs-2
+  labels:
+    app: foo
+  ownerReferences:
+  - apiVersion: apps/v1
+    controller: true
+    kind: Deployment
+    name: deploy-2
+    uid: deploy-2
+spec:
+  selector:
+    matchLabels:
+     app: foo
+`,
+		// deploy-2
+		`apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deploy-2
+  namespace: ns
+  uid: deploy-2
+spec:
+  selector:
+    matchLabels:
+      app: foo
+`}
+
+	k8sClient, err := NewFakeAPI(configs...)
+	if err != nil {
+		t.Fatalf("Unexpected error %s", err)
+	}
+
+	// Both pod-1 and pod-2 have labels which match deploy-1's selector.
+	// However, only pod-1 is owned by deploy-1 according to the owner references.
+	// Owner references should be considered authoritative to resolve ambiguity
+	// when deployments have overlapping seletors.
+	pods, err := GetPodsFor(context.Background(), k8sClient, "ns", "deploy/deploy-1")
+	if err != nil {
+		t.Fatalf("Unexpected error %s", err)
+	}
+
+	if len(pods) != 1 {
+		for _, p := range pods {
+			t.Logf("%s/%s", p.Namespace, p.Name)
+		}
+		t.Fatalf("Expected 1 pod, got %d", len(pods))
+	}
+}
diff --git a/test/integration/localhost/localhost_test.go b/test/integration/localhost/localhost_test.go
index 780729dc8..e870805e6 100644
--- a/test/integration/localhost/localhost_test.go
+++ b/test/integration/localhost/localhost_test.go
@@ -86,14 +86,13 @@ func TestLocalhostServer(t *testing.T) {
 				return fmt.Errorf("expected non-zero RPS from slowcooker to nginx: %s", out)
 			}
 
-			// TODO: Update this test to expect these requests to fail once
-			// https://github.com/linkerd/linkerd2/issues/6495 is fixed.  Requests
-			// sent to a port which is only bound to localhost should fail.
-			if *stats[0].Success != 1.0 {
-				return fmt.Errorf("expected perfect success-rate from slowcooker to nginx: %s", out)
+			// Requests sent to a port which is only bound to localhost should
+			// fail.
+			if *stats[0].Success >= 1.0 {
+				return fmt.Errorf("expected zero success-rate from slowcooker to nginx: %s", out)
 			}
-			if *stats[0].TCPOpenConnections == 0 {
-				return fmt.Errorf("expected tcp connection from slowcooker to nginx: %s", out)
+			if *stats[0].TCPOpenConnections > 0 {
+				return fmt.Errorf("expected no tcp connection from slowcooker to nginx: %s", out)
 			}
 
 			return nil
diff --git a/test/integration/policy/policy_test.go b/test/integration/policy/policy_test.go
new file mode 100644
index 000000000..72d3e0b85
--- /dev/null
+++ b/test/integration/policy/policy_test.go
@@ -0,0 +1,244 @@
+package policy
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/linkerd/linkerd2/testutil"
+)
+
+var TestHelper *testutil.TestHelper
+
+func TestMain(m *testing.M) {
+	TestHelper = testutil.NewTestHelper()
+	os.Exit(m.Run())
+}
+
+//////////////////////
+/// TEST EXECUTION ///
+//////////////////////
+
+func TestPolicy(t *testing.T) {
+	ctx := context.Background()
+
+	// Test authorization stats
+	TestHelper.WithDataPlaneNamespace(ctx, "stat-authz-test", map[string]string{}, t, func(t *testing.T, prefixedNs string) {
+		emojivotoYaml, err := testutil.ReadFile("testdata/emojivoto.yaml")
+		if err != nil {
+			testutil.AnnotatedFatalf(t, "failed to read emojivoto yaml",
+				"failed to read emojivoto yaml\n%s\n", err)
+		}
+		emojivotoYaml = strings.ReplaceAll(emojivotoYaml, "___NS___", prefixedNs)
+		out, stderr, err := TestHelper.PipeToLinkerdRun(emojivotoYaml, "inject", "-")
+		if err != nil {
+			testutil.AnnotatedFatalf(t, "'linkerd inject' command failed",
+				"'linkerd inject' command failed\n%s\n%s", out, stderr)
+		}
+
+		out, err = TestHelper.KubectlApply(out, prefixedNs)
+		if err != nil {
+			testutil.AnnotatedFatalf(t, "failed to apply emojivoto resources",
+				"failed to apply emojivoto resources: %s\n %s", err, out)
+		}
+
+		emojivotoPolicy, err := testutil.ReadFile("testdata/emoji-policy.yaml")
+		if err != nil {
+			testutil.AnnotatedFatalf(t, "failed to read emoji-policy yaml",
+				"failed to read emoji-policy yaml\n%s\n", err)
+		}
+
+		out, err = TestHelper.KubectlApply(emojivotoPolicy, prefixedNs)
+		if err != nil {
+			testutil.AnnotatedFatalf(t, "failed to apply emojivoto policy resources",
+				"failed to apply emojivoto policy resources: %s\n %s", err, out)
+		}
+
+		// wait for deployments to start
+		for _, deploy := range []string{"web", "emoji", "vote-bot", "voting"} {
+			if err := TestHelper.CheckPods(ctx, prefixedNs, deploy, 1); err != nil {
+				if rce, ok := err.(*testutil.RestartCountError); ok {
+					testutil.AnnotatedWarn(t, "CheckPods timed-out", rce)
+				} else {
+					testutil.AnnotatedError(t, "CheckPods timed-out", err)
+				}
+			}
+		}
+
+		testCases := []struct {
+			args         []string
+			expectedRows []string
+			isServer     bool
+		}{
+			{
+				args: []string{"viz", "stat", "srv", "-n", prefixedNs},
+				expectedRows: []string{
+					"emoji-grpc",
+					"voting-grpc",
+					"web-http",
+				},
+				isServer: true,
+			},
+			{
+				args: []string{"viz", "stat", "srv/emoji-grpc", "-n", prefixedNs},
+				expectedRows: []string{
+					"emoji-grpc",
+				},
+				isServer: true,
+			},
+			{
+				args: []string{"viz", "stat", "saz", "-n", prefixedNs},
+				expectedRows: []string{
+					"emoji-grpc",
+					"voting-grpc",
+					"web-public",
+				},
+				isServer: false,
+			},
+			{
+				args: []string{"viz", "stat", "saz/emoji-grpc", "-n", prefixedNs},
+				expectedRows: []string{
+					"emoji-grpc",
+				},
+				isServer: false,
+			},
+		}
+
+		for _, tt := range testCases {
+			tt := tt // pin
+			timeout := 3 * time.Minute
+			t.Run("linkerd "+strings.Join(tt.args, " "), func(t *testing.T) {
+				err := TestHelper.RetryFor(timeout, func() error {
+					// Use a short time window so that transient errors at startup
+					// fall out of the window.
+					tt.args = append(tt.args, "-t", "30s")
+					out, err := TestHelper.LinkerdRun(tt.args...)
+					if err != nil {
+						testutil.AnnotatedFatalf(t, "unexpected stat error",
+							"unexpected stat error: %s\n%s", err, out)
+					}
+
+					var expectedColumnCount int
+					if tt.isServer {
+						expectedColumnCount = 8
+					} else {
+						expectedColumnCount = 6
+					}
+
+					rowStats, err := ParseAuthzRows(out, len(tt.expectedRows), expectedColumnCount, tt.isServer)
+					if err != nil {
+						return err
+					}
+
+					for _, name := range tt.expectedRows {
+						if err := validateAuthzRows(name, rowStats, tt.isServer); err != nil {
+							return err
+						}
+					}
+
+					return nil
+				})
+				if err != nil {
+					testutil.AnnotatedFatal(t, fmt.Sprintf("timed-out checking stats (%s)", timeout), err)
+				}
+			})
+		}
+	})
+}
+
+func validateAuthzRows(name string, rowStats map[string]*testutil.RowStat, isServer bool) error {
+	stat, ok := rowStats[name]
+	if !ok {
+		return fmt.Errorf("No stats found for [%s]", name)
+	}
+
+	// Check for suffix only, as the value will not be 100% always with
+	// the normal emojivoto sample
+	if !strings.HasSuffix(stat.Success, "%") {
+		return fmt.Errorf("Unexpected success rate for [%s], got [%s]",
+			name, stat.Success)
+	}
+
+	if isServer {
+		if !strings.HasSuffix(stat.UnauthorizedRPS, "rps") {
+			return fmt.Errorf("Unexpected Unauthorized RPS for [%s], got [%s]",
+				name, stat.UnauthorizedRPS)
+		}
+	}
+
+	if !strings.HasSuffix(stat.Rps, "rps") {
+		return fmt.Errorf("Unexpected rps for [%s], got [%s]",
+			name, stat.Rps)
+	}
+
+	if !strings.HasSuffix(stat.P50Latency, "ms") {
+		return fmt.Errorf("Unexpected p50 latency for [%s], got [%s]",
+			name, stat.P50Latency)
+	}
+
+	if !strings.HasSuffix(stat.P95Latency, "ms") {
+		return fmt.Errorf("Unexpected p95 latency for [%s], got [%s]",
+			name, stat.P95Latency)
+	}
+
+	if !strings.HasSuffix(stat.P99Latency, "ms") {
+		return fmt.Errorf("Unexpected p99 latency for [%s], got [%s]",
+			name, stat.P99Latency)
+	}
+
+	if isServer {
+		_, err := strconv.Atoi(stat.TCPOpenConnections)
+		if err != nil {
+			return fmt.Errorf("Error parsing number of TCP connections [%s]: %s", stat.TCPOpenConnections, err.Error())
+		}
+	}
+
+	return nil
+}
+
+// ParseRows parses the output of linkerd stat on a policy resource
+func ParseAuthzRows(out string, expectedRowCount, expectedColumnCount int, isServer bool) (map[string]*testutil.RowStat, error) {
+	rows, err := testutil.CheckRowCount(out, expectedRowCount)
+	if err != nil {
+		return nil, err
+	}
+
+	rowStats := make(map[string]*testutil.RowStat)
+	for _, row := range rows {
+		fields := strings.Fields(row)
+
+		if len(fields) != expectedColumnCount {
+			return nil, fmt.Errorf(
+				"Expected [%d] columns in stat output, got [%d]; full output:\n%s",
+				expectedColumnCount, len(fields), row)
+		}
+
+		i := 0
+		rowStats[fields[0]] = &testutil.RowStat{
+			Name: fields[0],
+		}
+
+		if isServer {
+			rowStats[fields[0]].UnauthorizedRPS = fields[1+i]
+			rowStats[fields[0]].Success = fields[2+i]
+			rowStats[fields[0]].Rps = fields[3+i]
+			rowStats[fields[0]].P50Latency = fields[4+i]
+			rowStats[fields[0]].P95Latency = fields[5+i]
+			rowStats[fields[0]].P99Latency = fields[6+i]
+			rowStats[fields[0]].TCPOpenConnections = fields[7+i]
+		} else {
+			rowStats[fields[0]].Success = fields[1+i]
+			rowStats[fields[0]].Rps = fields[2+i]
+			rowStats[fields[0]].P50Latency = fields[3+i]
+			rowStats[fields[0]].P95Latency = fields[4+i]
+			rowStats[fields[0]].P99Latency = fields[5+i]
+		}
+
+	}
+
+	return rowStats, nil
+}
diff --git a/test/integration/policy/testdata/emoji-policy.yaml b/test/integration/policy/testdata/emoji-policy.yaml
new file mode 100644
index 000000000..a7ef577f1
--- /dev/null
+++ b/test/integration/policy/testdata/emoji-policy.yaml
@@ -0,0 +1,97 @@
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  name: emoji-grpc
+  labels:
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/name: emoji
+    app.kubernetes.io/version: v11
+spec:
+  podSelector:
+    matchLabels:
+      app: emoji-svc
+  port: grpc
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  name: emoji-grpc
+  labels:
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/name: emoji
+    app.kubernetes.io/version: v11
+spec:
+  # Allow all authenticated clients to access the (read-only) emoji service.
+  server:
+    name: emoji-grpc
+  client:
+    meshTLS:
+      identities:
+        - "*.linkerd-stat-authz-test.serviceaccount.identity.linkerd.cluster.local"
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  name: voting-grpc
+  labels:
+    app: voting-svc
+spec:
+  podSelector:
+    matchLabels:
+      app: voting-svc
+  port: grpc
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  name: voting-grpc
+  labels:
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/name: voting
+    app.kubernetes.io/version: v11
+spec:
+  server:
+    name: voting-grpc
+  # The voting service only allows requests from the web service.
+  client:
+    meshTLS:
+      serviceAccounts:
+        - name: web
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  name: web-http
+  labels:
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/name: web
+    app.kubernetes.io/version: v11
+spec:
+  podSelector:
+    matchLabels:
+      app: web-svc
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  name: web-public
+  labels:
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/name: web
+    app.kubernetes.io/version: v11
+spec:
+  server:
+    name: web-http
+  # Allow all clients to access the web HTTP port without regard for
+  # authentication. If unauthenticated connections are permitted, there is no
+  # need to describe authenticated clients.
+  client:
+    unauthenticated: true
+    networks:
+      - cidr: 0.0.0.0/0
+      - cidr: ::/0
diff --git a/test/integration/policy/testdata/emojivoto.yaml b/test/integration/policy/testdata/emojivoto.yaml
new file mode 100644
index 000000000..2a05e0132
--- /dev/null
+++ b/test/integration/policy/testdata/emojivoto.yaml
@@ -0,0 +1,205 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: emoji
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: voting
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: web
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: emoji-svc
+spec:
+  ports:
+  - name: grpc
+    port: 8080
+    targetPort: 8080
+  - name: prom
+    port: 8801
+    targetPort: 8801
+  selector:
+    app: emoji-svc
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: voting-svc
+spec:
+  ports:
+  - name: grpc
+    port: 8080
+    targetPort: 8080
+  - name: prom
+    port: 8801
+    targetPort: 8801
+  selector:
+    app: voting-svc
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: web-svc
+spec:
+  ports:
+  - name: http
+    port: 80
+    targetPort: 8080
+  selector:
+    app: web-svc
+  type: ClusterIP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: emoji
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/version: v11
+  name: emoji
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: emoji-svc
+      version: v11
+  template:
+    metadata:
+      labels:
+        app: emoji-svc
+        version: v11
+    spec:
+      containers:
+      - env:
+        - name: GRPC_PORT
+          value: "8080"
+        - name: PROM_PORT
+          value: "8801"
+        image: docker.l5d.io/buoyantio/emojivoto-emoji-svc:v11
+        name: emoji-svc
+        ports:
+        - containerPort: 8080
+          name: grpc
+        - containerPort: 8801
+          name: prom
+        resources:
+          requests:
+            cpu: 100m
+      serviceAccountName: emoji
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: vote-bot
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/version: v11
+  name: vote-bot
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: vote-bot
+      version: v11
+  template:
+    metadata:
+      labels:
+        app: vote-bot
+        version: v11
+    spec:
+      containers:
+      - command:
+        - emojivoto-vote-bot
+        env:
+        - name: WEB_HOST
+          value: web-svc.___NS___:80
+        image: docker.l5d.io/buoyantio/emojivoto-web:v11
+        name: vote-bot
+        resources:
+          requests:
+            cpu: 10m
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: voting
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/version: v11
+  name: voting
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: voting-svc
+      version: v11
+  template:
+    metadata:
+      labels:
+        app: voting-svc
+        version: v11
+    spec:
+      containers:
+      - env:
+        - name: GRPC_PORT
+          value: "8080"
+        - name: PROM_PORT
+          value: "8801"
+        image: docker.l5d.io/buoyantio/emojivoto-voting-svc:v11
+        name: voting-svc
+        ports:
+        - containerPort: 8080
+          name: grpc
+        - containerPort: 8801
+          name: prom
+        resources:
+          requests:
+            cpu: 100m
+      serviceAccountName: voting
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: web
+    app.kubernetes.io/part-of: emojivoto
+    app.kubernetes.io/version: v11
+  name: web
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: web-svc
+      version: v11
+  template:
+    metadata:
+      labels:
+        app: web-svc
+        version: v11
+    spec:
+      containers:
+      - env:
+        - name: WEB_PORT
+          value: "8080"
+        - name: EMOJISVC_HOST
+          value: emoji-svc.___NS___:8080
+        - name: VOTINGSVC_HOST
+          value: voting-svc.___NS___:8080
+        - name: INDEX_BUNDLE
+          value: dist/index_bundle.js
+        image: docker.l5d.io/buoyantio/emojivoto-web:v11
+        name: web-svc
+        ports:
+        - containerPort: 8080
+          name: http
+        resources:
+          requests:
+            cpu: 100m
+      serviceAccountName: web
diff --git a/test/integration/testdata/inject.report.golden b/test/integration/testdata/inject.report.golden
index c7c5928fd..d1b4570b5 100644
--- a/test/integration/testdata/inject.report.golden
+++ b/test/integration/testdata/inject.report.golden
@@ -1,6 +1,10 @@
 
 deployment "smoke-test-terminus" injected
 service "smoke-test-terminus-svc" skipped
+server "smoke-test-terminus" skipped
+serverauthorization "smoke-test-terminus" skipped
 deployment "smoke-test-gateway" injected
 service "smoke-test-gateway-svc" skipped
+server "smoke-test-proxy-admin" skipped
+serverauthorization "smoke-test-proxy-admin" skipped
 
diff --git a/test/integration/testdata/smoke_test.yaml b/test/integration/testdata/smoke_test.yaml
index fd9e1d9ea..14bce1adc 100644
--- a/test/integration/testdata/smoke_test.yaml
+++ b/test/integration/testdata/smoke_test.yaml
@@ -32,6 +32,34 @@ spec:
     port: 9090
     targetPort: 9090
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  name: smoke-test-terminus
+spec:
+  podSelector:
+    matchLabels:
+      app: smoke-test-terminus
+  port: 9090
+  proxyProtocol: gRPC
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  name: smoke-test-terminus
+spec:
+  server:
+    name: smoke-test-terminus
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: default
+        namespace: linkerd-smoke-test
+      - name: default
+        namespace: linkerd-smoke-test-manual
+      - name: default
+        namespace: linkerd-smoke-test-ann
+---
 apiVersion: apps/v1
 kind: Deployment
 metadata:
@@ -64,3 +92,29 @@ spec:
   - name: http
     port: 8080
     targetPort: 8080
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  name: smoke-test-proxy-admin
+spec:
+  podSelector:
+    matchExpressions:
+    - key: app
+      operator: In
+      values:
+      - smoke-test-terminus
+      - smoke-test-gateway
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  name: smoke-test-proxy-admin
+spec:
+  server:
+    name: smoke-test-proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
diff --git a/testutil/test_helper.go b/testutil/test_helper.go
index dea3c19c4..771ba536b 100644
--- a/testutil/test_helper.go
+++ b/testutil/test_helper.go
@@ -672,6 +672,7 @@ type RowStat struct {
 	P95Latency         string
 	P99Latency         string
 	TCPOpenConnections string
+	UnauthorizedRPS    string
 }
 
 // CheckRowCount checks that expectedRowCount rows have been returned
diff --git a/viz/cmd/testdata/install_default.golden b/viz/cmd/testdata/install_default.golden
index 3c83fe4ad..c07ee6a2b 100644
--- a/viz/cmd/testdata/install_default.golden
+++ b/viz/cmd/testdata/install_default.golden
@@ -392,6 +392,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -474,6 +540,43 @@ spec:
           runAsUser: 2103
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Grafana
 ###
@@ -631,6 +734,41 @@ spec:
           name: grafana-config
         name: grafana-config
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+---
 ###
 ### Prometheus
 ###
@@ -977,6 +1115,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -1137,6 +1310,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###
diff --git a/viz/cmd/testdata/install_default_overrides.golden b/viz/cmd/testdata/install_default_overrides.golden
index 82abf79ab..cf73caa2c 100644
--- a/viz/cmd/testdata/install_default_overrides.golden
+++ b/viz/cmd/testdata/install_default_overrides.golden
@@ -392,6 +392,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -474,6 +540,43 @@ spec:
           runAsUser: 1234
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Grafana
 ###
@@ -631,6 +734,41 @@ spec:
           name: grafana-config
         name: grafana-config
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+---
 ###
 ### Prometheus
 ###
@@ -977,6 +1115,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -1137,6 +1310,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###
diff --git a/viz/cmd/testdata/install_grafana_disabled.golden b/viz/cmd/testdata/install_grafana_disabled.golden
index da80d2534..102b91a5b 100644
--- a/viz/cmd/testdata/install_grafana_disabled.golden
+++ b/viz/cmd/testdata/install_grafana_disabled.golden
@@ -379,6 +379,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -461,6 +527,43 @@ spec:
           runAsUser: 2103
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Prometheus
 ###
@@ -798,6 +901,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -958,6 +1096,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###
diff --git a/viz/cmd/testdata/install_prometheus_disabled.golden b/viz/cmd/testdata/install_prometheus_disabled.golden
index 14d1242b4..094f3bff4 100644
--- a/viz/cmd/testdata/install_prometheus_disabled.golden
+++ b/viz/cmd/testdata/install_prometheus_disabled.golden
@@ -352,6 +352,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -434,6 +500,43 @@ spec:
           runAsUser: 2103
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Grafana
 ###
@@ -591,6 +694,41 @@ spec:
           name: grafana-config
         name: grafana-config
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+---
 ###
 ### Tap
 ###
@@ -690,6 +828,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -850,6 +1023,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###
diff --git a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
index 63b9c4ed8..f5f693ce5 100644
--- a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
+++ b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
@@ -392,6 +392,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -474,6 +540,43 @@ spec:
           runAsUser: 2103
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Grafana
 ###
@@ -631,6 +734,41 @@ spec:
           name: grafana-config
         name: grafana-config
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+---
 ###
 ### Prometheus
 ###
@@ -977,6 +1115,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -1137,6 +1310,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###
diff --git a/viz/cmd/testdata/install_proxy_resources.golden b/viz/cmd/testdata/install_proxy_resources.golden
index 2270cf83e..d6de02232 100644
--- a/viz/cmd/testdata/install_proxy_resources.golden
+++ b/viz/cmd/testdata/install_proxy_resources.golden
@@ -392,6 +392,72 @@ metadata:
     component: web
     namespace: linkerd-viz
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: admin-http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: admin
+  client:
+    # for kubelet probes and prometheus scraping
+    unauthenticated: true
+
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+  port: linkerd-admin
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: proxy-admin
+  labels:
+    linkerd.io/extension: viz
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: proxy-admin
+  client:
+    # for kubelet probes
+    unauthenticated: true
+
+---
 ###
 ### Metrics API
 ###
@@ -474,6 +540,43 @@ spec:
           runAsUser: 2103
       serviceAccountName: metrics-api
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: metrics-api
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: metrics-api
+  labels:
+    linkerd.io/extension: viz
+    component: metrics-api
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: metrics-api
+  client:
+    meshTLS:
+      serviceAccounts:
+      - name: web
+      - name: prometheus
+---
 ###
 ### Grafana
 ###
@@ -635,6 +738,41 @@ spec:
           name: grafana-config
         name: grafana-config
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: grafana
+  port: http
+  proxyProtocol: HTTP/1
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: grafana
+  labels:
+    linkerd.io/extension: viz
+    component: grafana
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: grafana
+  client:
+    # web, prometheus and the kubelet probes
+    unauthenticated: true
+---
 ###
 ### Prometheus
 ###
@@ -989,6 +1127,41 @@ spec:
         secret:
           secretName: tap-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-api
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap
+  port: apiserver
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap
+  labels:
+    linkerd.io/extension: viz
+    component: tap
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-api
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Tap Injector RBAC
 ###
@@ -1149,6 +1322,41 @@ spec:
         secret:
           secretName: tap-injector-k8s-tls
 ---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: Server
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector-webhook
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  podSelector:
+    matchLabels:
+      linkerd.io/extension: viz
+      component: tap-injector
+  port: tap-injector
+  proxyProtocol: TLS
+---
+apiVersion: policy.linkerd.io/v1alpha1
+kind: ServerAuthorization
+metadata:
+  namespace: linkerd-viz
+  name: tap-injector
+  labels:
+    linkerd.io/extension: viz
+    component: tap-injector
+  annotations:
+    linkerd.io/created-by: linkerd/helm dev-undefined
+spec:
+  server:
+    name: tap-injector-webhook
+  client:
+    # traffic coming from kube-api
+    unauthenticated: true
+---
 ###
 ### Web
 ###