Repository: linkerd/linkerd2
Pull request #11816 (2023-12-22 02:04:33)

Remove shortnames from Tap API resources
The Tap API resource shortnames were colliding with existing Kubernetes resources (e.g. `po`, `deploy`, etc), causing warnings from kubectl v1.29.0+.

Remove the shortnames from the Tap APIService handlers.

To validate:
```bash
bin/k3d cluster create

# install latest edge
curl https://run.linkerd.io/install-edge | sh
linkerd install --crds | kubectl apply -f -
linkerd install        | kubectl apply -f -
linkerd check
linkerd viz install    | kubectl apply -f -
linkerd check

# observe shortnames
kubectl api-resources --api-group=tap.linkerd.io

# with kubectl v1.29.0+, observe "Warning: short name..."
kubectl get po

# replace tap image
TAP_IMAGE=$(bin/docker-build-tap)
bin/k3d image load $TAP_IMAGE
kubectl -n linkerd-viz set image deploy/tap tap=$TAP_IMAGE

# verify shortnames are no longer present
kubectl api-resources --api-group=tap.linkerd.io

# with kubectl v1.29.0+, observe no warning
kubectl get po
```

Fixes linkerd/linkerd2#11784

<!--  Thanks for sending a pull request!

If you already have a well-structured git commit message, chances are GitHub
set the title and description of this PR to the git commit message subject and
body, respectively. If so, you may delete these instructions and submit your PR.

If this is your first time, please read our contributor guide:
https://github.com/linkerd/linkerd2/blob/main/CONTRIBUTING.md

The title and description of your Pull Request should match the git commit
subject and body, respectively. Git commit messages are structured as follows:

```
Subject

Problem

Solution

Validation

Fixes #[GitHub issue ID]

DCO Sign off
```

Example git commit message:

```
Introduce Pull Request Template

GitHub's community guidelines recommend a pull request template, the repo was
lacking one.

Introduce a `PULL_REQUEST_TEMPLATE.md` file.

Once merged, the
[Community profile checklist](https://github.com/linkerd/linkerd2/community)
should indicate the repo now provides a pull request template.

Fixes #3321

Signed-off-by: Jane Smith <jane.smith@example.com>
```

Note the git commit message subject becomes the pull request title.

For more details around git commits, see the section on Committing in our
contributor guide:
https://github.com/linkerd/linkerd2/blob/main/CONTRIBUTING.md#committing
-->



Patch:
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 487eea0f4..41bf3aa42 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -148,7 +148,7 @@ jobs:
     timeout-minutes: 5
     steps:
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
-      - uses: tj-actions/changed-files@56284d80811fb5963a972b438f2870f175e5b7c8
+      - uses: tj-actions/changed-files@716b1e13042866565e00e85fd4ec490e186c4a2f
         id: changed
         with:
           files: |
@@ -287,7 +287,7 @@ jobs:
     timeout-minutes: 5
     steps:
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
-      - uses: tj-actions/changed-files@56284d80811fb5963a972b438f2870f175e5b7c8
+      - uses: tj-actions/changed-files@716b1e13042866565e00e85fd4ec490e186c4a2f
         id: changed
         with:
           files: |
@@ -330,7 +330,7 @@ jobs:
     timeout-minutes: 5
     steps:
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
-      - uses: tj-actions/changed-files@56284d80811fb5963a972b438f2870f175e5b7c8
+      - uses: tj-actions/changed-files@716b1e13042866565e00e85fd4ec490e186c4a2f
         id: changed
         with:
           files: |
diff --git a/.proxy-version b/.proxy-version
index 8549fdd43..92433673c 100644
--- a/.proxy-version
+++ b/.proxy-version
@@ -1,1 +1,1 @@
-v2.216.0
+v2.219.0
diff --git a/CHANGES.md b/CHANGES.md
index 550512f1e..2dbe08062 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,22 @@
 # Changes
 
+## edge-23.12.4
+
+This edge release includes fixes and improvements to the destination
+controller's endpoint resolution API.
+
+* Fixed an issue in the control plane where discovery for pod IP addresses could
+  hang indefinitely ([#11815])
+* Updated the proxy to enforce time limits on control plane response streams so
+  that proxies more naturally distribute load over control plane replicas
+  ([#11837])
+* Fixed the policy's controller service metadata responses so that proxy logs
+  and metrics have informative values ([#11842])
+
+[#11842]: https://github.com/linkerd/linkerd2/pull/11842
+[#11837]: https://github.com/linkerd/linkerd2/pull/11837
+[#11815]: https://github.com/linkerd/linkerd2/pull/11815
+
 ## edge-23.12.3
 
 This edge release contains improvements to the logging and diagnostics of the
diff --git a/Cargo.lock b/Cargo.lock
index 80cb1e236..d3a442f4a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -91,7 +91,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -102,7 +102,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -113,9 +113,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "axum"
-version = "0.6.11"
+version = "0.6.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13d8068b6ccb8b34db9de397c7043f91db8b4c66414952c6db944f238c4d3db3"
+checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
 dependencies = [
  "async-trait",
  "axum-core",
@@ -141,9 +141,9 @@ dependencies = [
 
 [[package]]
 name = "axum-core"
-version = "0.3.3"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e"
+checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
 dependencies = [
  "async-trait",
  "bytes",
@@ -193,35 +193,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
 [[package]]
 name = "base64"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
-
-[[package]]
-name = "base64"
-version = "0.21.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
-
-[[package]]
-name = "bindgen"
-version = "0.64.0"
+version = "0.21.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
-dependencies = [
- "bitflags 1.3.2",
- "cexpr",
- "clang-sys",
- "lazy_static",
- "lazycell",
- "peeking_take_while",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn 1.0.109",
-]
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
 
 [[package]]
 name = "bitflags"
@@ -252,15 +226,15 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 
 [[package]]
 name = "cc"
@@ -268,15 +242,6 @@ version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
 
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -296,17 +261,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "clang-sys"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
 [[package]]
 name = "clap"
 version = "4.4.11"
@@ -336,7 +290,7 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -363,9 +317,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
 dependencies = [
  "libc",
 ]
@@ -379,28 +333,6 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
-dependencies = [
- "autocfg",
- "cfg-if",
- "crossbeam-utils",
- "memoffset",
- "scopeguard",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
-dependencies = [
- "cfg-if",
-]
-
 [[package]]
 name = "crypto-common"
 version = "0.1.6"
@@ -413,9 +345,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.14.4"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -423,27 +355,27 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.14.4"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
  "strsim",
- "syn 1.0.109",
+ "syn 2.0.43",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.14.4"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
 dependencies = [
  "darling_core",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -475,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "digest"
-version = "0.10.6"
+version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer",
  "crypto-common",
@@ -492,6 +424,12 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "dtoa"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
+
 [[package]]
 name = "dyn-clone"
 version = "1.0.11"
@@ -512,33 +450,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno"
-version = "0.3.5"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
  "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -564,9 +481,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -604,9 +521,9 @@ checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83"
+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -627,7 +544,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -687,12 +604,6 @@ version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
-[[package]]
-name = "glob"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
-
 [[package]]
 name = "gzip-header"
 version = "1.0.0"
@@ -727,15 +638,6 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
-[[package]]
-name = "hashbrown"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
-dependencies = [
- "ahash",
-]
-
 [[package]]
 name = "hashbrown"
 version = "0.14.0"
@@ -830,7 +732,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2",
+ "socket2 0.4.10",
  "tokio",
  "tower-service",
  "tracing",
@@ -857,9 +759,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-rustls"
-version = "0.24.1"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
  "http",
@@ -951,17 +853,6 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "io-lifetimes"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.45.0",
-]
-
 [[package]]
 name = "ipnet"
 version = "2.9.0"
@@ -999,9 +890,9 @@ dependencies = [
 
 [[package]]
 name = "jemallocator"
-version = "0.5.0"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16c2514137880c52b0b4822b563fadd38257c1f380858addb74a400889696ea6"
+checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc"
 dependencies = [
  "jemalloc-sys",
  "libc",
@@ -1018,9 +909,9 @@ dependencies = [
 
 [[package]]
 name = "json-patch"
-version = "1.0.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658"
+checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6"
 dependencies = [
  "serde",
  "serde_json",
@@ -1029,21 +920,23 @@ dependencies = [
 ]
 
 [[package]]
-name = "jsonpath_lib"
-version = "0.3.0"
+name = "jsonpath-rust"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f"
+checksum = "06cc127b7c3d270be504572364f9569761a180b981919dd0d87693a7f5fb7829"
 dependencies = [
- "log",
- "serde",
+ "pest",
+ "pest_derive",
+ "regex",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
 name = "k8s-gateway-api"
-version = "0.13.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3778745a32b7e8c7ce09d3bf5a2038ee8170e2d983f69c4b910b9e537712e8e1"
+checksum = "9ae4cd917edb1eba13a1413b46b98d292fd10919d86a573311a564ee4f208f44"
 dependencies = [
  "k8s-openapi",
  "kube",
@@ -1054,27 +947,24 @@ dependencies = [
 
 [[package]]
 name = "k8s-openapi"
-version = "0.19.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95578de7d6eac4fba42114bc751e38c59a739968769df1be56feba6f17fd148e"
+checksum = "edc3606fd16aca7989db2f84bb25684d0270c6d6fa1dbcd0025af7b4130523a6"
 dependencies = [
- "base64 0.21.2",
+ "base64 0.21.5",
  "bytes",
  "chrono",
- "http",
- "percent-encoding",
  "schemars",
  "serde",
  "serde-value",
  "serde_json",
- "url",
 ]
 
 [[package]]
 name = "kube"
-version = "0.85.0"
+version = "0.87.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a189cb8721a47de68d883040713bbb9c956763d784fcf066828018d32c180b96"
+checksum = "3499c8d60c763246c7a213f51caac1e9033f46026904cb89bc8951ae8601f26e"
 dependencies = [
  "k8s-openapi",
  "kube-client",
@@ -1085,11 +975,11 @@ dependencies = [
 
 [[package]]
 name = "kube-client"
-version = "0.85.0"
+version = "0.87.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98989b6e1f27695afe22aa29c94136fa06be5e8d28b91222e6dfbe5a460c803f"
+checksum = "033450dfa0762130565890dadf2f8835faedf749376ca13345bcd8ecd6b5f29f"
 dependencies = [
- "base64 0.20.0",
+ "base64 0.21.5",
  "bytes",
  "chrono",
  "either",
@@ -1101,7 +991,7 @@ dependencies = [
  "hyper-openssl",
  "hyper-rustls",
  "hyper-timeout",
- "jsonpath_lib",
+ "jsonpath-rust",
  "k8s-openapi",
  "kube-core",
  "openssl",
@@ -1125,9 +1015,9 @@ dependencies = [
 
 [[package]]
 name = "kube-core"
-version = "0.85.0"
+version = "0.87.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c24d23bf764ec9a5652f943442ff062b91fd52318ea6d2fc11115f19d8c84d13"
+checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae"
 dependencies = [
  "chrono",
  "form_urlencoded",
@@ -1143,22 +1033,22 @@ dependencies = [
 
 [[package]]
 name = "kube-derive"
-version = "0.85.0"
+version = "0.87.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bbec4da219dcb02bb32afd762a7ac4dffd47ed92b7e35ac9a7b961d21327117"
+checksum = "91e98dd5e5767c7b894c1f0e41fd628b145f808e981feb8b08ed66455d47f1a4"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
  "serde_json",
- "syn 1.0.109",
+ "syn 2.0.43",
 ]
 
 [[package]]
 name = "kube-runtime"
-version = "0.85.0"
+version = "0.87.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "381224caa8a6fc16f8251cf1fd6d8678cdf5366f33000a923e4c54192e4b25b5"
+checksum = "2d8893eb18fbf6bb6c80ef6ee7dd11ec32b1dc3c034c988ac1b3a84d46a230ae"
 dependencies = [
  "ahash",
  "async-trait",
@@ -1182,9 +1072,9 @@ dependencies = [
 
 [[package]]
 name = "kubert"
-version = "0.19.0"
+version = "0.21.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "357e2b50e5a455abe6199b26ee7d7137e3b72df7f821c0b801756335d13bc140"
+checksum = "a4c7e2b9edcf6c5848ce9819712d927a5c8fbd63d548f817ca64022444e7cdd1"
 dependencies = [
  "ahash",
  "backoff",
@@ -1200,10 +1090,11 @@ dependencies = [
  "kube-client",
  "kube-core",
  "kube-runtime",
- "metrics-exporter-prometheus",
- "metrics-process",
+ "kubert-prometheus-process",
+ "kubert-prometheus-tokio",
  "parking_lot",
  "pin-project-lite",
+ "prometheus-client",
  "rustls-pemfile",
  "serde",
  "serde_json",
@@ -1217,43 +1108,40 @@ dependencies = [
 ]
 
 [[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "lazycell"
-version = "1.3.0"
+name = "kubert-prometheus-process"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+checksum = "40d2f45f0fb66a3681630fe2efd018c63eb7336697c44d909e53a99847113b97"
+dependencies = [
+ "libc",
+ "procfs",
+ "prometheus-client",
+ "tracing",
+]
 
 [[package]]
-name = "libc"
-version = "0.2.151"
+name = "kubert-prometheus-tokio"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "a101fa3df488c89130664aaf4652986da49e204fb1725d089122f75b22ff6cbb"
+dependencies = [
+ "prometheus-client",
+ "tokio",
+ "tokio-metrics",
+ "tracing",
+]
 
 [[package]]
-name = "libloading"
-version = "0.7.4"
+name = "lazy_static"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
-dependencies = [
- "cfg-if",
- "winapi",
-]
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
-name = "libproc"
-version = "0.13.0"
+name = "libc"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b18cbf29f8ff3542ba22bdce9ac610fcb75d74bb4e2b306b2a2762242025b4f"
-dependencies = [
- "bindgen",
- "errno 0.2.8",
- "libc",
-]
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
 
 [[package]]
 name = "linked-hash-map"
@@ -1436,9 +1324,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.1.4"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
 
 [[package]]
 name = "lock_api"
@@ -1459,15 +1347,6 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "mach2"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
-dependencies = [
- "libc",
-]
-
 [[package]]
 name = "maplit"
 version = "1.0.2"
@@ -1495,93 +1374,12 @@ version = "2.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
-[[package]]
-name = "memoffset"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "metrics"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5"
-dependencies = [
- "ahash",
- "metrics-macros",
- "portable-atomic",
-]
-
-[[package]]
-name = "metrics-exporter-prometheus"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5"
-dependencies = [
- "base64 0.21.2",
- "indexmap 1.9.2",
- "metrics",
- "metrics-util",
- "quanta",
- "thiserror",
-]
-
-[[package]]
-name = "metrics-macros"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "metrics-process"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c93f6ad342d3f7bc14724147e2dbc6eb6fdbe5a832ace16ea23b73618e8cc17"
-dependencies = [
- "libproc",
- "mach2",
- "metrics",
- "once_cell",
- "procfs",
- "rlimit",
- "windows",
-]
-
-[[package]]
-name = "metrics-util"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e"
-dependencies = [
- "crossbeam-epoch",
- "crossbeam-utils",
- "hashbrown 0.13.1",
- "metrics",
- "num_cpus",
- "quanta",
- "sketches-ddsketch",
-]
-
 [[package]]
 name = "mime"
 version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
 [[package]]
 name = "miniz_oxide"
 version = "0.7.1"
@@ -1602,16 +1400,6 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
 [[package]]
 name = "nu-ansi-term"
 version = "0.46.0"
@@ -1634,9 +1422,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
 ]
@@ -1653,9 +1441,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.32.1"
+version = "0.32.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
 dependencies = [
  "memchr",
 ]
@@ -1689,7 +1477,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -1759,25 +1547,65 @@ dependencies = [
 ]
 
 [[package]]
-name = "peeking_take_while"
-version = "0.1.2"
+name = "pem"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310"
+dependencies = [
+ "base64 0.21.5",
+ "serde",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
-name = "pem"
-version = "1.1.1"
+name = "pest"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
+checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5"
 dependencies = [
- "base64 0.13.1",
+ "memchr",
+ "thiserror",
+ "ucd-trie",
 ]
 
 [[package]]
-name = "percent-encoding"
-version = "2.2.0"
+name = "pest_derive"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.43",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
 
 [[package]]
 name = "pin-project"
@@ -1796,14 +1624,14 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.9"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
 [[package]]
 name = "pin-utils"
@@ -1813,15 +1641,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
-
-[[package]]
-name = "portable-atomic"
-version = "1.4.2"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e"
+checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
 
 [[package]]
 name = "ppv-lite86"
@@ -1831,26 +1653,59 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "procfs"
-version = "0.15.1"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943ca7f9f29bab5844ecd8fdb3992c5969b6622bb9609b9502fef9b4310e3f1f"
+checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
 dependencies = [
- "bitflags 1.3.2",
- "byteorder",
+ "bitflags 2.4.0",
  "hex",
  "lazy_static",
+ "procfs-core",
  "rustix",
 ]
 
+[[package]]
+name = "procfs-core"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
+dependencies = [
+ "bitflags 2.4.0",
+ "hex",
+]
+
+[[package]]
+name = "prometheus-client"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "510c4f1c9d81d556458f94c98f857748130ea9737bbd6053da497503b26ea63c"
+dependencies = [
+ "dtoa",
+ "itoa",
+ "parking_lot",
+ "prometheus-client-derive-encode",
+]
+
+[[package]]
+name = "prometheus-client-derive-encode"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.43",
+]
+
 [[package]]
 name = "prost"
 version = "0.11.9"
@@ -1883,22 +1738,6 @@ dependencies = [
  "prost",
 ]
 
-[[package]]
-name = "quanta"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
-dependencies = [
- "crossbeam-utils",
- "libc",
- "mach2",
- "once_cell",
- "raw-cpuid",
- "wasi",
- "web-sys",
- "winapi",
-]
-
 [[package]]
 name = "quote"
 version = "1.0.33"
@@ -1938,15 +1777,6 @@ dependencies = [
  "getrandom",
 ]
 
-[[package]]
-name = "raw-cpuid"
-version = "10.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
-dependencies = [
- "bitflags 1.3.2",
-]
-
 [[package]]
 name = "redox_syscall"
 version = "0.4.1"
@@ -2014,39 +1844,23 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "rlimit"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8"
-dependencies = [
- "libc",
-]
-
 [[package]]
 name = "rustc-demangle"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
 [[package]]
 name = "rustix"
-version = "0.36.16"
+version = "0.38.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab"
+checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
 dependencies = [
- "bitflags 1.3.2",
- "errno 0.3.5",
- "io-lifetimes",
+ "bitflags 2.4.0",
+ "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.45.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2178,9 +1992,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.8.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -2213,7 +2027,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2229,11 +2043,10 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.104"
+version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
+checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
 dependencies = [
- "indexmap 2.0.0",
  "itoa",
  "ryu",
  "serde",
@@ -2241,9 +2054,9 @@ dependencies = [
 
 [[package]]
 name = "serde_yaml"
-version = "0.9.27"
+version = "0.9.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
+checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129"
 dependencies = [
  "indexmap 2.0.0",
  "itoa",
@@ -2263,6 +2076,17 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
 [[package]]
 name = "sharded-slab"
 version = "0.1.7"
@@ -2272,12 +2096,6 @@ dependencies = [
  "lazy_static",
 ]
 
-[[package]]
-name = "shlex"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
-
 [[package]]
 name = "signal-hook-registry"
 version = "1.4.1"
@@ -2287,12 +2105,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "sketches-ddsketch"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceb945e54128e09c43d8e4f1277851bd5044c6fc540bbaa2ad888f60b3da9ae7"
-
 [[package]]
 name = "slab"
 version = "0.4.8"
@@ -2310,14 +2122,24 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
 
 [[package]]
 name = "socket2"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
 dependencies = [
  "libc",
  "winapi",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "spin"
 version = "0.9.8"
@@ -2343,9 +2165,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.32"
+version = "2.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
+checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2375,7 +2197,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2405,11 +2227,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.29.1"
+version = "1.35.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
+checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
 dependencies = [
- "autocfg",
  "backtrace",
  "bytes",
  "libc",
@@ -2418,7 +2239,7 @@ dependencies = [
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2",
+ "socket2 0.5.5",
  "tokio-macros",
  "windows-sys 0.48.0",
 ]
@@ -2435,13 +2256,25 @@ dependencies = [
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
+]
+
+[[package]]
+name = "tokio-metrics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eace09241d62c98b7eeb1107d4c5c64ca3bd7da92e8c218c153ab3a78f9be112"
+dependencies = [
+ "futures-util",
+ "pin-project-lite",
+ "tokio",
+ "tokio-stream",
 ]
 
 [[package]]
@@ -2493,9 +2326,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-tungstenite"
-version = "0.20.0"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2"
+checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
 dependencies = [
  "futures-util",
  "log",
@@ -2572,11 +2405,11 @@ dependencies = [
 
 [[package]]
 name = "tower-http"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82"
+checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
 dependencies = [
- "base64 0.21.2",
+ "base64 0.21.5",
  "bitflags 2.4.0",
  "bytes",
  "futures-core",
@@ -2729,11 +2562,17 @@ version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
 
+[[package]]
+name = "ucd-trie"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+
 [[package]]
 name = "unicode-bidi"
-version = "0.3.13"
+version = "0.3.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
 
 [[package]]
 name = "unicode-ident"
@@ -2866,16 +2705,6 @@ version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
 
-[[package]]
-name = "web-sys"
-version = "0.3.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -2898,16 +2727,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
-[[package]]
-name = "windows"
-version = "0.51.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9763fb813068e9f4ab70a92a0c6ad61ff6b342f693b1ed0e5387c854386e670"
-dependencies = [
- "windows-core",
- "windows-targets 0.48.2",
-]
-
 [[package]]
 name = "windows-core"
 version = "0.51.0"
@@ -2917,15 +2736,6 @@ dependencies = [
  "windows-targets 0.48.2",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -2936,18 +2746,12 @@ dependencies = [
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.42.2"
+name = "windows-sys"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
@@ -2966,10 +2770,19 @@ dependencies = [
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
+name = "windows-targets"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
@@ -2978,10 +2791,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f"
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -2990,10 +2803,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058"
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
+name = "windows_aarch64_msvc"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -3002,10 +2815,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
+name = "windows_i686_gnu"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -3014,10 +2827,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287"
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
+name = "windows_i686_msvc"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -3026,10 +2839,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a"
 
 [[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
+name = "windows_x86_64_gnu"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -3038,10 +2851,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d"
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -3049,24 +2862,30 @@ version = "0.48.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
 [[package]]
 name = "zerocopy"
-version = "0.7.31"
+version = "0.7.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.31"
+version = "0.7.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.32",
+ "syn 2.0.43",
 ]
 
 [[package]]
diff --git a/bin/helm-bump-edge b/bin/helm-bump-edge
new file mode 100755
index 000000000..418ba7758
--- /dev/null
+++ b/bin/helm-bump-edge
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+# This script bumps the patch version of all charts whose versions end in -edge.
+# The BUMP_CRDS and BUMP_CNI variables can be set to also bump those versions.
+
+set -euo pipefail
+shopt -s globstar
+
+bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd )
+
+# Iterate through charts/*/Chart.yaml and bump the patch version of the
+# `version` field. E.g. 1.18.2-edge becomes 1.18.3-edge.
+for chart in **/Chart.yaml; do
+    # Skip the linkerd-crds chart unless BUMP_CRDS is set.
+    if [[ "$chart" =~ "linkerd-crds" ]] && [[ -z "${BUMP_CRDS:-}" ]]; then
+        continue
+    fi
+    if [[ "$chart" =~ "linkerd2-cni" ]] && [[ -z "${BUMP_CNI:-}" ]]; then
+        continue
+    fi
+
+    version=$(yq eval .version <"$chart")
+    if [[ "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)-edge$ ]]; then
+        major="${BASH_REMATCH[1]}"
+        minor="${BASH_REMATCH[2]}"
+        patch="${BASH_REMATCH[3]}"
+        new_version="$major.$minor.$((patch + 1))-edge"
+        echo "Bumping $chart from $version to $new_version"
+        # Replace version line with new version
+        yq -i ".version = \"$new_version\"" "$chart"
+    fi
+done
+
+"$bindir"/helm-docs
diff --git a/charts/linkerd-control-plane/Chart.yaml b/charts/linkerd-control-plane/Chart.yaml
index 3e562e7c7..b74a3d5a4 100644
--- a/charts/linkerd-control-plane/Chart.yaml
+++ b/charts/linkerd-control-plane/Chart.yaml
@@ -7,16 +7,16 @@ description: |
 type: application
 home: https://linkerd.io
 keywords:
-- service-mesh
+  - service-mesh
 kubeVersion: ">=1.22.0-0"
 name: "linkerd-control-plane"
 sources:
-- https://github.com/linkerd/linkerd2/
+  - https://github.com/linkerd/linkerd2/
 dependencies:
-- name: partials
-  version: 0.1.0
-  repository: file://../partials
-version: 1.18.2-edge
+  - name: partials
+    version: 0.1.0
+    repository: file://../partials
+version: 1.18.3-edge
 icon: https://linkerd.io/images/logo-only-200h.png
 maintainers:
   - name: Linkerd authors
diff --git a/charts/linkerd-control-plane/README.md b/charts/linkerd-control-plane/README.md
index 9ed9a3b7e..2fc82dcac 100644
--- a/charts/linkerd-control-plane/README.md
+++ b/charts/linkerd-control-plane/README.md
@@ -3,7 +3,7 @@
 Linkerd gives you observability, reliability, and security
 for your microservices — with no code change required.
 
-![Version: 1.18.2-edge](https://img.shields.io/badge/Version-1.18.2--edge-informational?style=flat-square)
+![Version: 1.18.3-edge](https://img.shields.io/badge/Version-1.18.3--edge-informational?style=flat-square)
 ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
 ![AppVersion: edge-XX.X.X](https://img.shields.io/badge/AppVersion-edge--XX.X.X-informational?style=flat-square)
 
@@ -231,6 +231,9 @@ Kubernetes: `>=1.22.0-0`
 | profileValidator.namespaceSelector | object | `{"matchExpressions":[{"key":"config.linkerd.io/admission-webhooks","operator":"NotIn","values":["disabled"]}]}` | Namespace selector used by admission webhook |
 | prometheusUrl | string | `""` | url of external prometheus instance (used for the heartbeat) |
 | proxy.await | bool | `true` | If set, the application container will not start until the proxy is ready |
+| proxy.control.streams.idleTimeout | string | `"5m"` | The timeout between consecutive updates from the control plane. |
+| proxy.control.streams.initialTimeout | string | `"3s"` | The timeout for the first update from the control plane. |
+| proxy.control.streams.lifetime | string | `"1h"` | The maximum duration for a response stream (i.e. before it will be reinitialized). |
 | proxy.cores | int | `0` | The `cpu.limit` and `cores` should be kept in sync. The value of `cores` must be an integer and should typically be set by rounding up from the limit. E.g. if cpu.limit is '1500m', cores should be 2. |
 | proxy.defaultInboundPolicy | string | "all-unauthenticated" | The default allow policy to use when no `Server` selects a pod.  One of: "all-authenticated", "all-unauthenticated", "cluster-authenticated", "cluster-unauthenticated", "deny" |
 | proxy.disableInboundProtocolDetectTimeout | bool | `false` | When set to true, disables the protocol detection timeout on the inbound side of the proxy by setting it to a very high value |
diff --git a/charts/linkerd-control-plane/templates/destination.yaml b/charts/linkerd-control-plane/templates/destination.yaml
index a4081b691..d48a81a5c 100644
--- a/charts/linkerd-control-plane/templates/destination.yaml
+++ b/charts/linkerd-control-plane/templates/destination.yaml
@@ -205,6 +205,9 @@ spec:
         - -identity-trust-domain={{.Values.identityTrustDomain | default .Values.clusterDomain}}
         - -default-opaque-ports={{.Values.proxy.opaquePorts}}
         - -enable-pprof={{.Values.enablePprof | default false}}
+        {{- range (.Values.destinationController).experimentalArgs }}
+        - {{ . }}
+        {{- end }}
         {{- include "partials.linkerd.trace" . | nindent 8 -}}
         image: {{.Values.controllerImage}}:{{.Values.controllerImageVersion | default .Values.linkerdVersion}}
         imagePullPolicy: {{.Values.imagePullPolicy}}
@@ -294,6 +297,9 @@ spec:
         {{- if .Values.policyController.probeNetworks }}
         - --probe-networks={{.Values.policyController.probeNetworks | join ","}}
         {{- end}}
+        {{- range .Values.policyController.experimentalArgs }}
+        - {{ . }}
+        {{- end }}
         image: {{.Values.policyController.image.name}}:{{.Values.policyController.image.version | default .Values.linkerdVersion}}
         imagePullPolicy: {{.Values.policyController.image.pullPolicy | default .Values.imagePullPolicy}}
         livenessProbe:
diff --git a/charts/linkerd-control-plane/values.yaml b/charts/linkerd-control-plane/values.yaml
index 519585a08..54e7522d6 100644
--- a/charts/linkerd-control-plane/values.yaml
+++ b/charts/linkerd-control-plane/values.yaml
@@ -207,6 +207,17 @@ proxy:
     initialDelaySeconds: 0
     periodSeconds: 1
     failureThreshold: 120
+  # Configures general properties of the proxy's control plane clients.
+  control:
+    # Configures limits on API response streams.
+    streams:
+      # -- The timeout for the first update from the control plane.
+      initialTimeout: "3s"
+      # -- The timeout between consecutive updates from the control plane.
+      idleTimeout: "5m"
+      # -- The maximum duration for a response stream (i.e. before it will be
+      # reinitialized).
+      lifetime: "1h"
 
 # proxy-init configuration
 proxyInit:
diff --git a/charts/partials/templates/_proxy.tpl b/charts/partials/templates/_proxy.tpl
index da0d10b6c..7bb187d5e 100644
--- a/charts/partials/templates/_proxy.tpl
+++ b/charts/partials/templates/_proxy.tpl
@@ -44,6 +44,12 @@ env:
   value: {{.Values.proxy.defaultInboundPolicy}}
 - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
   value: {{.Values.clusterNetworks | quote}}
+- name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+  value: {{((.Values.proxy.control).streams).initialTimeout | default "" | quote}}
+- name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+  value: {{((.Values.proxy.control).streams).idleTimeout | default "" | quote}}
+- name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+  value: {{((.Values.proxy.control).streams).lifetime | default "" | quote}}
 {{ if .Values.proxy.inboundConnectTimeout -}}
 - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
   value: {{.Values.proxy.inboundConnectTimeout | quote}}
@@ -153,6 +159,10 @@ be used in other contexts.
 - name: LINKERD2_PROXY_SHUTDOWN_GRACE_PERIOD
   value: {{.Values.proxy.shutdownGracePeriod | quote}}
 {{ end -}}
+{{ range $k, $v := (.Values.proxy.experimentalEnv) -}}
+- name: {{ $k }}
+  value: {{ $v | quote }}
+{{ end -}}
 image: {{.Values.proxy.image.name}}:{{.Values.proxy.image.version | default .Values.linkerdVersion}}
 imagePullPolicy: {{.Values.proxy.image.pullPolicy | default .Values.imagePullPolicy}}
 livenessProbe:
diff --git a/controller/api/destination/endpoint_profile_translator.go b/controller/api/destination/endpoint_profile_translator.go
index a31083efe..fea388e6f 100644
--- a/controller/api/destination/endpoint_profile_translator.go
+++ b/controller/api/destination/endpoint_profile_translator.go
@@ -5,7 +5,10 @@ import (
 
 	pb "github.com/linkerd/linkerd2-proxy-api/go/destination"
 	"github.com/linkerd/linkerd2/controller/api/destination/watcher"
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promauto"
 	logging "github.com/sirupsen/logrus"
+	"google.golang.org/protobuf/proto"
 )
 
 type endpointProfileTranslator struct {
@@ -13,39 +16,107 @@ type endpointProfileTranslator struct {
 	controllerNS        string
 	identityTrustDomain string
 	defaultOpaquePorts  map[uint32]struct{}
-	stream              pb.Destination_GetProfileServer
-	lastMessage         string
+
+	stream    pb.Destination_GetProfileServer
+	endStream chan struct{}
+
+	updates chan *watcher.Address
+	stop    chan struct{}
+
+	current *pb.DestinationProfile
 
 	log *logging.Entry
 }
 
-// newEndpointProfileTranslator translates pod updates and protocol updates to
+// endpointProfileUpdatesQueueOverflowCounter is a prometheus counter that is incremented
+// whenever the profile updates queue overflows.
+//
+// We omit ip and port labels because they are high cardinality.
+var endpointProfileUpdatesQueueOverflowCounter = promauto.NewCounter(
+	prometheus.CounterOpts{
+		Name: "endpoint_profile_updates_queue_overflow",
+		Help: "A counter incremented whenever the endpoint profile updates queue overflows",
+	},
+)
+
+// newEndpointProfileTranslator translates pod updates and profile updates to
 // DestinationProfiles for endpoints
 func newEndpointProfileTranslator(
 	enableH2Upgrade bool,
 	controllerNS,
 	identityTrustDomain string,
 	defaultOpaquePorts map[uint32]struct{},
-	log *logging.Entry,
 	stream pb.Destination_GetProfileServer,
+	endStream chan struct{},
+	log *logging.Entry,
 ) *endpointProfileTranslator {
 	return &endpointProfileTranslator{
 		enableH2Upgrade:     enableH2Upgrade,
 		controllerNS:        controllerNS,
 		identityTrustDomain: identityTrustDomain,
 		defaultOpaquePorts:  defaultOpaquePorts,
-		stream:              stream,
-		log:                 log.WithField("component", "endpoint-profile-translator"),
+
+		stream:    stream,
+		endStream: endStream,
+		updates:   make(chan *watcher.Address, updateQueueCapacity),
+		stop:      make(chan struct{}),
+
+		log: log.WithField("component", "endpoint-profile-translator"),
 	}
 }
 
-// Update sends a DestinationProfile message into the stream, if the same
-// message hasn't been sent already. If it has, false is returned.
-func (ept *endpointProfileTranslator) Update(address *watcher.Address) (bool, error) {
+// Start initiates a goroutine which processes update events off of the
+// endpointProfileTranslator's internal queue and sends to the grpc stream as
+// appropriate. The goroutine calls non-thread-safe Send, therefore Start must
+// not be called more than once.
+func (ept *endpointProfileTranslator) Start() {
+	go func() {
+		for {
+			select {
+			case update := <-ept.updates:
+				ept.update(update)
+			case <-ept.stop:
+				return
+			}
+		}
+	}()
+}
+
+// Stop terminates the goroutine started by Start.
+func (ept *endpointProfileTranslator) Stop() {
+	close(ept.stop)
+}
+
+// Update enqueues an address update to be translated into a DestinationProfile.
+// An error is returned if the update cannot be enqueued.
+func (ept *endpointProfileTranslator) Update(address *watcher.Address) error {
+	select {
+	case ept.updates <- address:
+		// Update has been successfully enqueued.
+		return nil
+	default:
+		select {
+		case <-ept.endStream:
+			// The endStream channel has already been closed so no action is
+			// necessary.
+			return fmt.Errorf("profile update stream closed")
+		default:
+			// We are unable to enqueue because the channel does not have capacity.
+			// The stream has fallen too far behind and should be closed.
+			endpointProfileUpdatesQueueOverflowCounter.Inc()
+			close(ept.endStream)
+			return fmt.Errorf("profile update queue full; aborting stream")
+		}
+	}
+}
+
+func (ept *endpointProfileTranslator) update(address *watcher.Address) {
 	opaquePorts := watcher.GetAnnotatedOpaquePorts(address.Pod, ept.defaultOpaquePorts)
 	endpoint, err := ept.createEndpoint(*address, opaquePorts)
 	if err != nil {
-		return false, fmt.Errorf("failed to create endpoint: %w", err)
+		ept.log.Errorf("Failed to create endpoint for %s:%d: %s",
+			address.IP, address.Port, err)
+		return
 	}
 
 	profile := &pb.DestinationProfile{
@@ -53,17 +124,18 @@ func (ept *endpointProfileTranslator) Update(address *watcher.Address) (bool, er
 		Endpoint:       endpoint,
 		OpaqueProtocol: address.OpaqueProtocol,
 	}
-	msg := profile.String()
-	if msg == ept.lastMessage {
-		return false, nil
+	if proto.Equal(profile, ept.current) {
+		ept.log.Debugf("Ignoring redundant profile update: %+v", profile)
+		return
 	}
-	ept.lastMessage = msg
-	ept.log.Debugf("sending protocol update: %+v", profile)
+
+	ept.log.Debugf("Sending profile update: %+v", profile)
 	if err := ept.stream.Send(profile); err != nil {
-		return false, fmt.Errorf("failed to send protocol update: %w", err)
+		ept.log.Errorf("failed to send profile update: %s", err)
+		return
 	}
 
-	return true, nil
+	ept.current = profile
 }
 
 func (ept *endpointProfileTranslator) createEndpoint(address watcher.Address, opaquePorts map[uint32]struct{}) (*pb.WeightedAddr, error) {
diff --git a/controller/api/destination/server.go b/controller/api/destination/server.go
index b569bdf0d..84f94d9d0 100644
--- a/controller/api/destination/server.go
+++ b/controller/api/destination/server.go
@@ -492,14 +492,19 @@ func (s *server) subscribeToEndpointProfile(
 	log *logging.Entry,
 	stream pb.Destination_GetProfileServer,
 ) error {
+	canceled := stream.Context().Done()
+	streamEnd := make(chan struct{})
 	translator := newEndpointProfileTranslator(
 		s.config.EnableH2Upgrade,
 		s.config.ControllerNS,
 		s.config.IdentityTrustDomain,
 		s.config.DefaultOpaquePorts,
-		log,
 		stream,
+		streamEnd,
+		log,
 	)
+	translator.Start()
+	defer translator.Stop()
 
 	var err error
 	ip, err = s.pods.Subscribe(service, hostname, ip, port, translator)
@@ -510,8 +515,10 @@ func (s *server) subscribeToEndpointProfile(
 
 	select {
 	case <-s.shutdown:
-	case <-stream.Context().Done():
+	case <-canceled:
 		s.log.Debugf("Cancelled")
+	case <-streamEnd:
+		log.Errorf("GetProfile %s:%d stream aborted", ip, port)
 	}
 	return nil
 }
diff --git a/controller/api/destination/watcher/pod_watcher.go b/controller/api/destination/watcher/pod_watcher.go
index 9c0b8656d..e55f8e46d 100644
--- a/controller/api/destination/watcher/pod_watcher.go
+++ b/controller/api/destination/watcher/pod_watcher.go
@@ -53,7 +53,7 @@ type (
 
 	// PodUpdateListener is the interface subscribers must implement.
 	PodUpdateListener interface {
-		Update(*Address) (bool, error)
+		Update(*Address) error
 	}
 )
 
@@ -115,13 +115,10 @@ func (pw *PodWatcher) Subscribe(service *ServiceID, hostname, ip string, port Po
 		return "", err
 	}
 
-	sent, err := listener.Update(&address)
-	if err != nil {
-		return "", err
-	}
-	if sent {
-		pp.metrics.incUpdates()
+	if err = listener.Update(&address); err != nil {
+		return "", fmt.Errorf("failed to send initial update: %w", err)
 	}
+	pp.metrics.incUpdates()
 
 	return pp.ip, nil
 }
@@ -277,11 +274,11 @@ func (pw *PodWatcher) updateServers(_ any) {
 					pw.log.Errorf("Error creating address for pod: %s", err)
 					continue
 				}
-				sent, err := listener.Update(&addr)
-				if err != nil {
-					pw.log.Errorf("Error calling pod watcher listener for server update: %s", err)
+				if err = listener.Update(&addr); err != nil {
+					pw.log.Warnf("Error sending update to listener: %s", err)
+					continue
 				}
-				updated = updated || sent
+				updated = true
 			}
 			if updated {
 				pp.metrics.incUpdates()
@@ -480,11 +477,11 @@ func (pp *podPublisher) updatePod(pod *corev1.Pod) {
 				pp.log.Errorf("Error creating address for pod: %s", err)
 				continue
 			}
-			sent, err := l.Update(&addr)
-			if err != nil {
-				pp.log.Errorf("Error calling pod watcher listener for pod update: %s", err)
+			if err = l.Update(&addr); err != nil {
+				pp.log.Warnf("Error sending update to listener: %s", err)
+				continue
 			}
-			updated = updated || sent
+			updated = true
 		}
 		if updated {
 			pp.metrics.incUpdates()
@@ -503,11 +500,11 @@ func (pp *podPublisher) updatePod(pod *corev1.Pod) {
 				pp.log.Errorf("Error creating address for pod: %s", err)
 				continue
 			}
-			sent, err := l.Update(&addr)
-			if err != nil {
-				pp.log.Errorf("Error calling pod watcher listener for pod deletion: %s", err)
+			if err = l.Update(&addr); err != nil {
+				pp.log.Warnf("Error sending update to listener: %s", err)
+				continue
 			}
-			updated = updated || sent
+			updated = true
 		}
 		if updated {
 			pp.metrics.incUpdates()
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 6a4f234a6..6e3177912 100644
--- a/controller/proxy-injector/fake/data/pod-with-debug.patch.json
+++ b/controller/proxy-injector/fake/data/pod-with-debug.patch.json
@@ -105,14 +105,18 @@
       "name": "linkerd-debug",
       "terminationMessagePolicy": "FallbackToLogsOnError",
       "livenessProbe": {
-          "exec": {
-              "command": ["true"]
-          }
+        "exec": {
+          "command": [
+            "true"
+          ]
+        }
       },
       "readinessProbe": {
-          "exec": {
-              "command": ["true"]
-          }
+        "exec": {
+          "command": [
+            "true"
+          ]
+        }
       }
     }
   },
@@ -205,6 +209,18 @@
           "name": "LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS",
           "value": "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
         },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT",
+          "value": "3s"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT",
+          "value": "5m"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_LIFETIME",
+          "value": "1h"
+        },
         {
           "name": "LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT",
           "value": "100ms"
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 2716869a4..70e79bf01 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
@@ -195,6 +195,18 @@
           "name": "LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS",
           "value": "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
         },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT",
+          "value": "3s"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT",
+          "value": "5m"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_LIFETIME",
+          "value": "1h"
+        },
         {
           "name": "LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT",
           "value": "100ms"
diff --git a/controller/proxy-injector/fake/data/pod.patch.json b/controller/proxy-injector/fake/data/pod.patch.json
index 9017a44fe..85ab71faf 100644
--- a/controller/proxy-injector/fake/data/pod.patch.json
+++ b/controller/proxy-injector/fake/data/pod.patch.json
@@ -185,6 +185,18 @@
           "name": "LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS",
           "value": "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
         },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT",
+          "value": "3s"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT",
+          "value": "5m"
+        },
+        {
+          "name": "LINKERD2_PROXY_CONTROL_STREAM_LIFETIME",
+          "value": "1h"
+        },
         {
           "name": "LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT",
           "value": "100ms"
diff --git a/deny.toml b/deny.toml
index c5eae35e3..d9c747e12 100644
--- a/deny.toml
+++ b/deny.toml
@@ -67,6 +67,8 @@ skip = [
     # https://github.com/hawkw/matchers/pull/4
     { name = "regex-automata", version = "0.1" },
     { name = "regex-syntax", version = "0.6" },
+    # Pending hyper upgrade to 1.0
+    { name = "socket2" },
 ]
 skip-tree = [
     # `serde_json` and `h2` depend on diverged versions of `indexmap` (2.0.x and
diff --git a/go.mod b/go.mod
index db9d9e435..143b6aeb6 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/evanphx/json-patch v5.7.0+incompatible
 	github.com/fatih/color v1.16.0
 	github.com/fsnotify/fsnotify v1.7.0
-	github.com/go-openapi/spec v0.20.12
+	github.com/go-openapi/spec v0.20.13
 	github.com/go-test/deep v1.1.0
 	github.com/golang/protobuf v1.5.3
 	github.com/gorilla/websocket v1.5.1
@@ -24,7 +24,7 @@ require (
 	github.com/nsf/termbox-go v1.1.1
 	github.com/patrickmn/go-cache v2.1.0+incompatible
 	github.com/pkg/browser v0.0.0-20170505125900-c90ca0c84f15
-	github.com/prometheus/client_golang v1.17.0
+	github.com/prometheus/client_golang v1.18.0
 	github.com/prometheus/common v0.45.0
 	github.com/sergi/go-diff v1.3.1
 	github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
@@ -37,15 +37,15 @@ require (
 	golang.org/x/tools v0.16.1
 	google.golang.org/grpc v1.60.1
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
-	google.golang.org/protobuf v1.31.0
+	google.golang.org/protobuf v1.32.0
 	helm.sh/helm/v3 v3.13.3
-	k8s.io/api v0.28.4
-	k8s.io/apiextensions-apiserver v0.28.4
-	k8s.io/apimachinery v0.28.4
-	k8s.io/client-go v0.28.4
+	k8s.io/api v0.29.0
+	k8s.io/apiextensions-apiserver v0.29.0
+	k8s.io/apimachinery v0.29.0
+	k8s.io/client-go v0.29.0
 	k8s.io/code-generator v0.29.0
 	k8s.io/klog/v2 v2.110.1
-	k8s.io/kube-aggregator v0.28.4
+	k8s.io/kube-aggregator v0.29.0
 	sigs.k8s.io/gateway-api v0.8.1
 	sigs.k8s.io/yaml v1.4.0
 )
@@ -55,7 +55,7 @@ require (
 	github.com/bombsimon/logrusr/v4 v4.1.0
 	github.com/prometheus/client_model v0.5.0
 	gopkg.in/yaml.v2 v2.4.0
-	k8s.io/utils v0.0.0-20230505201702-9f6742963106
+	k8s.io/utils v0.0.0-20230726121419-3b25d923346b
 )
 
 require (
@@ -85,9 +85,9 @@ require (
 	github.com/go-errors/errors v1.4.2 // indirect
 	github.com/go-logr/logr v1.3.0 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/go-openapi/jsonpointer v0.20.1 // indirect
-	github.com/go-openapi/jsonreference v0.20.3 // indirect
-	github.com/go-openapi/swag v0.22.5 // indirect
+	github.com/go-openapi/jsonpointer v0.20.2 // indirect
+	github.com/go-openapi/jsonreference v0.20.4 // indirect
+	github.com/go-openapi/swag v0.22.6 // indirect
 	github.com/gobwas/glob v0.2.3 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -119,6 +119,7 @@ require (
 	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
 	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
@@ -162,3 +163,11 @@ require (
 	sigs.k8s.io/kustomize/kyaml v0.14.3 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
+
+// Required to unblock these bumps:
+// k8s.io/apiextensions-apiserver@v0.29.0
+// k8s.io/apimachinery@v0.29.0
+// k8s.io/kube-aggregator@v0.29.0
+// k8s.io/api@0.29.0
+// Remove when helm v3.13.4 is out
+replace k8s.io/cli-runtime => k8s.io/cli-runtime v0.29.0
diff --git a/go.sum b/go.sum
index add7f638a..d9c9d6217 100644
--- a/go.sum
+++ b/go.sum
@@ -150,14 +150,14 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
 github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-openapi/jsonpointer v0.20.1 h1:MkK4VEIEZMj4wT9PmjaUmGflVBr9nvud4Q4UVFbDoBE=
-github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
-github.com/go-openapi/jsonreference v0.20.3 h1:EjGcjTW8pD1mRis6+w/gmoBdqv5+RbE9B85D1NgDOVQ=
-github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM=
-github.com/go-openapi/spec v0.20.12 h1:cgSLbrsmziAP2iais+Vz7kSazwZ8rsUZd6TUzdDgkVI=
-github.com/go-openapi/spec v0.20.12/go.mod h1:iSCgnBcwbMW9SfzJb8iYynXvcY6C/QFrI7otzF7xGM4=
-github.com/go-openapi/swag v0.22.5 h1:fVS63IE3M0lsuWRzuom3RLwUMVI2peDH01s6M70ugys=
-github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
+github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
+github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
+github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
+github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE=
+github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
+github.com/go-openapi/swag v0.22.6 h1:dnqg1XfHXL9aBxSbktBqFR5CxVyVI+7fYWhAf1JOeTw=
+github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
@@ -343,6 +343,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
 github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
 github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
@@ -370,8 +372,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
-github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -725,8 +727,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -756,16 +758,16 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
-k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
-k8s.io/apiextensions-apiserver v0.28.4 h1:AZpKY/7wQ8n+ZYDtNHbAJBb+N4AXXJvyZx6ww6yAJvU=
-k8s.io/apiextensions-apiserver v0.28.4/go.mod h1:pgQIZ1U8eJSMQcENew/0ShUTlePcSGFq6dxSxf2mwPM=
-k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
-k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
-k8s.io/cli-runtime v0.28.4 h1:IW3aqSNFXiGDllJF4KVYM90YX4cXPGxuCxCVqCD8X+Q=
-k8s.io/cli-runtime v0.28.4/go.mod h1:MLGRB7LWTIYyYR3d/DOgtUC8ihsAPA3P8K8FDNIqJ0k=
-k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
-k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
+k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A=
+k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA=
+k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0=
+k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc=
+k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
+k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
+k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4=
+k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk=
+k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8=
+k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38=
 k8s.io/code-generator v0.29.0 h1:2LQfayGDhaIlaamXjIjEQlCMy4JNCH9lrzas4DNW1GQ=
 k8s.io/code-generator v0.29.0/go.mod h1:5bqIZoCxs2zTRKMWNYqyQWW/bajc+ah4rh0tMY8zdGA=
 k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks=
@@ -773,12 +775,12 @@ k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAE
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
 k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
 k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
-k8s.io/kube-aggregator v0.28.4 h1:VIGTKc3cDaJ44bvj988MTapJyRPbWXXcCvlp7HVLq5Q=
-k8s.io/kube-aggregator v0.28.4/go.mod h1:SHehggsYGjVaE1CZTfhukAPpdhs7bflJiddLrabbQNY=
+k8s.io/kube-aggregator v0.29.0 h1:N4fmtePxOZ+bwiK1RhVEztOU+gkoVkvterHgpwAuiTw=
+k8s.io/kube-aggregator v0.29.0/go.mod h1:bjatII63ORkFg5yUFP2qm2OC49R0wwxZhRVIyJ4Z4X0=
 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
-k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
-k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY=
 oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/jaeger/charts/linkerd-jaeger/Chart.yaml b/jaeger/charts/linkerd-jaeger/Chart.yaml
index fd935ec5f..a0d5dde36 100644
--- a/jaeger/charts/linkerd-jaeger/Chart.yaml
+++ b/jaeger/charts/linkerd-jaeger/Chart.yaml
@@ -6,12 +6,12 @@ description: |
   OpenCensus and Jaeger.
 home: https://linkerd.io
 keywords:
-- service-mesh
+  - service-mesh
 kubeVersion: ">=1.22.0-0"
 name: linkerd-jaeger
 sources:
-- https://github.com/linkerd/linkerd2/
-version: 30.14.2-edge
+  - https://github.com/linkerd/linkerd2/
+version: 30.14.3-edge
 icon: https://linkerd.io/images/logo-only-200h.png
 maintainers:
   - name: Linkerd authors
diff --git a/jaeger/charts/linkerd-jaeger/README.md b/jaeger/charts/linkerd-jaeger/README.md
index 0bf664079..094dc624e 100644
--- a/jaeger/charts/linkerd-jaeger/README.md
+++ b/jaeger/charts/linkerd-jaeger/README.md
@@ -3,7 +3,7 @@
 The Linkerd-Jaeger extension adds distributed tracing to Linkerd using
 OpenCensus and Jaeger.
 
-![Version: 30.14.2-edge](https://img.shields.io/badge/Version-30.14.2--edge-informational?style=flat-square)
+![Version: 30.14.3-edge](https://img.shields.io/badge/Version-30.14.3--edge-informational?style=flat-square)
 
 ![AppVersion: edge-XX.X.X](https://img.shields.io/badge/AppVersion-edge--XX.X.X-informational?style=flat-square)
 
diff --git a/multicluster/charts/linkerd-multicluster/Chart.yaml b/multicluster/charts/linkerd-multicluster/Chart.yaml
index 5c93cabb2..6ac695e5d 100644
--- a/multicluster/charts/linkerd-multicluster/Chart.yaml
+++ b/multicluster/charts/linkerd-multicluster/Chart.yaml
@@ -6,12 +6,12 @@ description: |
   linking to remote clusters
 home: https://linkerd.io
 keywords:
-- service-mesh
+  - service-mesh
 kubeVersion: ">=1.22.0-0"
 name: "linkerd-multicluster"
 sources:
-- https://github.com/linkerd/linkerd2/
-version: 30.12.11-edge
+  - https://github.com/linkerd/linkerd2/
+version: 30.12.12-edge
 icon: https://linkerd.io/images/logo-only-200h.png
 maintainers:
   - name: Linkerd authors
diff --git a/multicluster/charts/linkerd-multicluster/README.md b/multicluster/charts/linkerd-multicluster/README.md
index 38a02d9dd..6e4a0a51a 100644
--- a/multicluster/charts/linkerd-multicluster/README.md
+++ b/multicluster/charts/linkerd-multicluster/README.md
@@ -3,7 +3,7 @@
 The Linkerd-Multicluster extension contains resources to support multicluster
 linking to remote clusters
 
-![Version: 30.12.11-edge](https://img.shields.io/badge/Version-30.12.11--edge-informational?style=flat-square)
+![Version: 30.12.12-edge](https://img.shields.io/badge/Version-30.12.12--edge-informational?style=flat-square)
 
 ![AppVersion: edge-XX.X.X](https://img.shields.io/badge/AppVersion-edge--XX.X.X-informational?style=flat-square)
 
diff --git a/pkg/charts/linkerd2/values.go b/pkg/charts/linkerd2/values.go
index 39445729a..eb17e9352 100644
--- a/pkg/charts/linkerd2/values.go
+++ b/pkg/charts/linkerd2/values.go
@@ -121,6 +121,19 @@ type (
 		ShutdownGracePeriod                  string           `json:"shutdownGracePeriod"`
 		NativeSidecar                        bool             `json:"nativeSidecar"`
 		StartupProbe                         *StartupProbe    `json:"startupProbe"`
+		Control                              *ProxyControl    `json:"control"`
+
+		ExperimentalEnv map[string]string `json:"experimentalEnv"`
+	}
+
+	ProxyControl struct {
+		Streams *ProxyControlStreams `json:"streams"`
+	}
+
+	ProxyControlStreams struct {
+		InitialTimeout string `json:"initialTimeout"`
+		IdleTimeout    string `json:"idleTimeout"`
+		Lifetime       string `json:"lifetime"`
 	}
 
 	// ProxyInit contains the fields to set the proxy-init container
diff --git a/policy-controller/Cargo.toml b/policy-controller/Cargo.toml
index 487855eab..5bf353d43 100644
--- a/policy-controller/Cargo.toml
+++ b/policy-controller/Cargo.toml
@@ -17,8 +17,8 @@ anyhow = "1"
 async-trait = "0.1"
 drain = "0.1"
 futures = { version = "0.3", default-features = false }
-k8s-gateway-api = "0.13"
-k8s-openapi = { version = "0.19", features = ["v1_22"] }
+k8s-gateway-api = "0.15"
+k8s-openapi = { version = "0.20", features = ["v1_22"] }
 hyper = { version = "0.14", features = ["http1", "http2", "runtime", "server"] }
 ipnet = { version = "2", default-features = false }
 linkerd-policy-controller-core = { path = "./core" }
@@ -40,18 +40,18 @@ default-features = false
 features = ["derive", "env", "std"]
 
 [dependencies.kube]
-version = "0.85"
+version = "0.87.1"
 default-features = false
 features = ["admission", "derive"]
 
 [dependencies.kubert]
-version = "0.19"
+version = "0.21.1"
 default-features = false
 features = [
     "clap",
     "index",
     "lease",
-    "metrics",
+    "prometheus-client",
     "runtime",
     "server",
     "rustls-tls",
diff --git a/policy-controller/Dockerfile b/policy-controller/Dockerfile
index c172d374e..6f81785eb 100644
--- a/policy-controller/Dockerfile
+++ b/policy-controller/Dockerfile
@@ -8,6 +8,8 @@ RUN cargo new policy-test --lib
 RUN --mount=type=cache,target=/usr/local/cargo/registry \
     cargo fetch
 ARG TARGETARCH
+# Enable tokio runtime metrics
+ENV RUSTFLAGS="--cfg tokio_unstable"
 RUN --mount=type=cache,target=target \
     --mount=type=cache,target=/usr/local/cargo/registry \
     target=$(case "$TARGETARCH" in \
diff --git a/policy-controller/grpc/src/outbound.rs b/policy-controller/grpc/src/outbound.rs
index 3b631043b..fbe7f1f16 100644
--- a/policy-controller/grpc/src/outbound.rs
+++ b/policy-controller/grpc/src/outbound.rs
@@ -467,7 +467,14 @@ fn convert_http_backend(
 fn default_backend(outbound: &OutboundPolicy) -> outbound::Backend {
     outbound::Backend {
         metadata: Some(Metadata {
-            kind: Some(metadata::Kind::Default("service".to_string())),
+            kind: Some(metadata::Kind::Resource(api::meta::Resource {
+                group: "core".to_string(),
+                kind: "Service".to_string(),
+                name: outbound.name.clone(),
+                namespace: outbound.namespace.clone(),
+                section: Default::default(),
+                port: u16::from(outbound.port).into(),
+            })),
         }),
         queue: Some(default_queue_config()),
         kind: Some(outbound::backend::Kind::Balancer(
diff --git a/policy-controller/k8s/api/Cargo.toml b/policy-controller/k8s/api/Cargo.toml
index 3b97850ef..3c0b07a5b 100644
--- a/policy-controller/k8s/api/Cargo.toml
+++ b/policy-controller/k8s/api/Cargo.toml
@@ -6,11 +6,11 @@ license = "Apache-2.0"
 publish = false
 
 [dependencies]
-k8s-openapi = { version = "0.19", default-features = false, features = [
+k8s-openapi = { version = "0.20", default-features = false, features = [
     "v1_22",
 ] }
-k8s-gateway-api = "0.13"
-kube = { version = "0.85", default-features = false, features = [
+k8s-gateway-api = "0.15"
+kube = { version = "0.87.1", default-features = false, features = [
     "client",
     "derive",
     "runtime",
diff --git a/policy-controller/k8s/api/src/policy/httproute.rs b/policy-controller/k8s/api/src/policy/httproute.rs
index 9844b34b2..e50f408b0 100644
--- a/policy-controller/k8s/api/src/policy/httproute.rs
+++ b/policy-controller/k8s/api/src/policy/httproute.rs
@@ -22,7 +22,7 @@ pub use k8s_gateway_api::{
     group = "policy.linkerd.io",
     version = "v1beta3",
     kind = "HTTPRoute",
-    struct = "HttpRoute",
+    root = "HttpRoute",
     status = "HttpRouteStatus",
     namespaced
 )]
@@ -259,6 +259,6 @@ where
     // Default kind is assumed to be service for backend ref objects
     super::targets_kind::<T>(
         backend_ref.group.as_deref(),
-        backend_ref.kind.as_deref().unwrap_or("service"),
+        backend_ref.kind.as_deref().unwrap_or("Service"),
     )
 }
diff --git a/policy-controller/k8s/index/Cargo.toml b/policy-controller/k8s/index/Cargo.toml
index 63c364b04..cfc64610b 100644
--- a/policy-controller/k8s/index/Cargo.toml
+++ b/policy-controller/k8s/index/Cargo.toml
@@ -10,13 +10,13 @@ ahash = "0.8"
 anyhow = "1"
 futures = { version = "0.3", default-features = false }
 http = "0.2"
-k8s-gateway-api = "0.13"
-kube = { version = "0.85", default-features = false, features = [
+k8s-gateway-api = "0.15"
+kube = { version = "0.87.1", default-features = false, features = [
     "client",
     "derive",
     "runtime",
 ] }
-kubert = { version = "0.19", default-features = false, features = ["index"] }
+kubert = { version = "0.21.1", default-features = false, features = ["index"] }
 linkerd-policy-controller-core = { path = "../../core" }
 linkerd-policy-controller-k8s-api = { path = "../api" }
 parking_lot = "0.12"
diff --git a/policy-controller/k8s/index/src/outbound/index.rs b/policy-controller/k8s/index/src/outbound/index.rs
index 20defded0..b41f6c32d 100644
--- a/policy-controller/k8s/index/src/outbound/index.rs
+++ b/policy-controller/k8s/index/src/outbound/index.rs
@@ -611,7 +611,7 @@ fn convert_backend(
         weight: weight.into(),
         authority: cluster.service_dns_authority(&service_ref.namespace, &name, port),
         name,
-        namespace: ns.to_string(),
+        namespace: service_ref.namespace.to_string(),
         port,
         filters,
     }))
diff --git a/policy-controller/k8s/status/Cargo.toml b/policy-controller/k8s/status/Cargo.toml
index 02395ead0..c29cdf720 100644
--- a/policy-controller/k8s/status/Cargo.toml
+++ b/policy-controller/k8s/status/Cargo.toml
@@ -10,15 +10,15 @@ ahash = "0.8"
 anyhow = "1"
 # Fix for https://github.com/chronotope/chrono/issues/602
 chrono = { version = "0.4.24", default-features = false, features = ["clock"] }
-k8s-gateway-api = "0.13"
-kubert = { version = "0.19", default-features = false, features = [
+k8s-gateway-api = "0.15"
+kubert = { version = "0.21.1", default-features = false, features = [
     "index",
     "lease",
 ] }
 linkerd-policy-controller-core = { path = "../../core" }
 linkerd-policy-controller-k8s-api = { path = "../api" }
 parking_lot = "0.12"
-serde_json = "1.0.94"
+serde_json = "1.0.109"
 thiserror = "1"
 tokio = { version = "1", features = ["macros"] }
 tracing = "0.1.37"
diff --git a/policy-controller/src/main.rs b/policy-controller/src/main.rs
index 75de5b317..9f40c6f0d 100644
--- a/policy-controller/src/main.rs
+++ b/policy-controller/src/main.rs
@@ -115,12 +115,9 @@ async fn main() -> Result<()> {
         Some(server)
     };
 
-    let mut admin = admin.into_builder();
-    admin.with_default_prometheus();
-
     let mut runtime = kubert::Runtime::builder()
         .with_log(log_level, log_format)
-        .with_admin(admin)
+        .with_admin(admin.into_builder().with_prometheus(Default::default()))
         .with_client(client)
         .with_optional_server(server)
         .build()
diff --git a/viz/charts/linkerd-viz/Chart.yaml b/viz/charts/linkerd-viz/Chart.yaml
index c1e06c268..9d1547e35 100644
--- a/viz/charts/linkerd-viz/Chart.yaml
+++ b/viz/charts/linkerd-viz/Chart.yaml
@@ -6,12 +6,12 @@ description: |
   components for Linkerd.
 home: https://linkerd.io
 keywords:
-- service-mesh
+  - service-mesh
 kubeVersion: ">=1.22.0-0"
 name: "linkerd-viz"
 sources:
-- https://github.com/linkerd/linkerd2/
-version: 30.14.2-edge
+  - https://github.com/linkerd/linkerd2/
+version: 30.14.3-edge
 icon: https://linkerd.io/images/logo-only-200h.png
 maintainers:
   - name: Linkerd authors
diff --git a/viz/charts/linkerd-viz/README.md b/viz/charts/linkerd-viz/README.md
index bd9750494..da60a78f7 100644
--- a/viz/charts/linkerd-viz/README.md
+++ b/viz/charts/linkerd-viz/README.md
@@ -3,7 +3,7 @@
 The Linkerd-Viz extension contains observability and visualization
 components for Linkerd.
 
-![Version: 30.14.2-edge](https://img.shields.io/badge/Version-30.14.2--edge-informational?style=flat-square)
+![Version: 30.14.3-edge](https://img.shields.io/badge/Version-30.14.3--edge-informational?style=flat-square)
 
 ![AppVersion: edge-XX.X.X](https://img.shields.io/badge/AppVersion-edge--XX.X.X-informational?style=flat-square)
 
@@ -142,7 +142,7 @@ Kubernetes: `>=1.22.0-0`
 | prometheus.image.name | string | `"prometheus"` | Docker image name for the prometheus instance |
 | prometheus.image.pullPolicy | string | defaultImagePullPolicy | Pull policy for the prometheus instance |
 | prometheus.image.registry | string | `"prom"` | Docker registry for the prometheus instance |
-| prometheus.image.tag | string | `"v2.48.0"` | Docker image tag for the prometheus instance |
+| prometheus.image.tag | string | `"v2.48.1"` | Docker image tag for the prometheus instance |
 | prometheus.logFormat | string | defaultLogLevel | log format (plain, json) of the prometheus instance |
 | prometheus.logLevel | string | defaultLogLevel | log level of the prometheus instance |
 | prometheus.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | NodeSelector section, See the [K8S documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) for more information |
diff --git a/viz/charts/linkerd-viz/values.yaml b/viz/charts/linkerd-viz/values.yaml
index 87e58bb4e..2aa82a673 100644
--- a/viz/charts/linkerd-viz/values.yaml
+++ b/viz/charts/linkerd-viz/values.yaml
@@ -423,7 +423,7 @@ prometheus:
     # -- Docker image name for the prometheus instance
     name: prometheus
     # -- Docker image tag for the prometheus instance
-    tag: v2.48.0
+    tag: v2.48.1
     # -- Pull policy for the prometheus instance
     # @default -- defaultImagePullPolicy
     pullPolicy: ""
diff --git a/viz/tap/api/handlers.go b/viz/tap/api/handlers.go
index d740dca27..5869eb7bb 100644
--- a/viz/tap/api/handlers.go
+++ b/viz/tap/api/handlers.go
@@ -55,19 +55,18 @@ var (
 
 	resources = []struct {
 		name       string
-		shortname  string
 		namespaced bool
 	}{
-		{"namespaces", "ns", false},
-		{"pods", "po", true},
-		{"replicationcontrollers", "rc", true},
-		{"services", "svc", true},
-		{"daemonsets", "ds", true},
-		{"deployments", "deploy", true},
-		{"replicasets", "rs", true},
-		{"statefulsets", "sts", true},
-		{"jobs", "", true},
-		{"cronjobs", "cj", true},
+		{"namespaces", false},
+		{"pods", true},
+		{"replicationcontrollers", true},
+		{"services", true},
+		{"daemonsets", true},
+		{"deployments", true},
+		{"replicasets", true},
+		{"statefulsets", true},
+		{"jobs", true},
+		{"cronjobs", true},
 	}
 )
 
@@ -257,7 +256,6 @@ func handleAPIResourceList(w http.ResponseWriter, _ *http.Request, _ httprouter.
 		resList.APIResources = append(resList.APIResources,
 			metav1.APIResource{
 				Name:       res.name,
-				ShortNames: []string{res.shortname},
 				Namespaced: res.namespaced,
 				Kind:       gvk.Kind,
 				Verbs:      metav1.Verbs{"watch"},
diff --git a/web/app/package.json b/web/app/package.json
index abaf8dbf8..3798e8dd6 100644
--- a/web/app/package.json
+++ b/web/app/package.json
@@ -15,14 +15,14 @@
     "@material-ui/core": "4.12.4",
     "@material-ui/icons": "4.11.3",
     "@material-ui/lab": "^4.0.0-alpha.61",
-    "classnames": "2.3.2",
-    "core-js": "^3.34.0",
+    "classnames": "2.5.1",
+    "core-js": "^3.35.0",
     "css-mediaquery": "^0.1.2",
     "d3-drag": "3.0.0",
     "d3-force": "3.0.0",
     "d3-format": "3.1.0",
     "d3-selection": "3.0.0",
-    "date-fns": "2.30.0",
+    "date-fns": "3.0.6",
     "jest-progress-bar-reporter": "^1.0.25",
     "locales-detector": "3.0.2",
     "lodash": "4.17.21",
@@ -41,10 +41,10 @@
     "whatwg-fetch": "3.6.20"
   },
   "devDependencies": {
-    "@babel/core": "^7.23.5",
+    "@babel/core": "^7.23.7",
     "@babel/eslint-parser": "^7.23.3",
     "@babel/plugin-proposal-class-properties": "^7.17.12",
-    "@babel/preset-env": "^7.23.6",
+    "@babel/preset-env": "^7.23.7",
     "@babel/preset-react": "^7.23.3",
     "@babel/runtime": "^7.23.6",
     "@lingui/cli": "3.17.2",
@@ -61,7 +61,7 @@
     "enzyme-adapter-react-16": "^1.15.7",
     "eslint": "^8.56.0",
     "eslint-config-airbnb": "^19.0.4",
-    "eslint-plugin-import": "^2.29.0",
+    "eslint-plugin-import": "^2.29.1",
     "eslint-plugin-jsx-a11y": "^6.7.1",
     "eslint-plugin-promise": "^6.1.1",
     "eslint-plugin-react": "^7.33.2",
@@ -69,7 +69,7 @@
     "eslint-webpack-plugin": "^4.0.1",
     "file-loader": "^6.2.0",
     "history": "5.3.0",
-    "html-webpack-plugin": "^5.5.4",
+    "html-webpack-plugin": "^5.6.0",
     "jest": "^29.7.0",
     "jest-environment-jsdom": "^29.7.0",
     "lodash-webpack-plugin": "^0.11.6",
diff --git a/web/app/yarn.lock b/web/app/yarn.lock
index e6dc789c6..493933218 100644
--- a/web/app/yarn.lock
+++ b/web/app/yarn.lock
@@ -28,21 +28,21 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98"
   integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==
 
-"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.5":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.5.tgz#6e23f2acbcb77ad283c5ed141f824fd9f70101c7"
-  integrity sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==
+"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.7.tgz#4d8016e06a14b5f92530a13ed0561730b5c6483f"
+  integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==
   dependencies:
     "@ampproject/remapping" "^2.2.0"
     "@babel/code-frame" "^7.23.5"
-    "@babel/generator" "^7.23.5"
-    "@babel/helper-compilation-targets" "^7.22.15"
+    "@babel/generator" "^7.23.6"
+    "@babel/helper-compilation-targets" "^7.23.6"
     "@babel/helper-module-transforms" "^7.23.3"
-    "@babel/helpers" "^7.23.5"
-    "@babel/parser" "^7.23.5"
+    "@babel/helpers" "^7.23.7"
+    "@babel/parser" "^7.23.6"
     "@babel/template" "^7.22.15"
-    "@babel/traverse" "^7.23.5"
-    "@babel/types" "^7.23.5"
+    "@babel/traverse" "^7.23.7"
+    "@babel/types" "^7.23.6"
     convert-source-map "^2.0.0"
     debug "^4.1.0"
     gensync "^1.0.0-beta.2"
@@ -65,12 +65,12 @@
   dependencies:
     eslint-rule-composer "^0.3.0"
 
-"@babel/generator@^7.20.14", "@babel/generator@^7.23.5", "@babel/generator@^7.7.2":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.5.tgz#17d0a1ea6b62f351d281350a5f80b87a810c4755"
-  integrity sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==
+"@babel/generator@^7.20.14", "@babel/generator@^7.23.6", "@babel/generator@^7.7.2":
+  version "7.23.6"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e"
+  integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==
   dependencies:
-    "@babel/types" "^7.23.5"
+    "@babel/types" "^7.23.6"
     "@jridgewell/gen-mapping" "^0.3.2"
     "@jridgewell/trace-mapping" "^0.3.17"
     jsesc "^2.5.1"
@@ -161,10 +161,10 @@
     regexpu-core "^5.3.1"
     semver "^6.3.0"
 
-"@babel/helper-define-polyfill-provider@^0.4.3":
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz#a71c10f7146d809f4a256c373f462d9bba8cf6ba"
-  integrity sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==
+"@babel/helper-define-polyfill-provider@^0.4.4":
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz#64df615451cb30e94b59a9696022cffac9a10088"
+  integrity sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==
   dependencies:
     "@babel/helper-compilation-targets" "^7.22.6"
     "@babel/helper-plugin-utils" "^7.22.5"
@@ -357,14 +357,14 @@
     "@babel/template" "^7.22.15"
     "@babel/types" "^7.22.19"
 
-"@babel/helpers@^7.23.5":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.5.tgz#52f522840df8f1a848d06ea6a79b79eefa72401e"
-  integrity sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==
+"@babel/helpers@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.7.tgz#eb543c36f81da2873e47b76ee032343ac83bba60"
+  integrity sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==
   dependencies:
     "@babel/template" "^7.22.15"
-    "@babel/traverse" "^7.23.5"
-    "@babel/types" "^7.23.5"
+    "@babel/traverse" "^7.23.7"
+    "@babel/types" "^7.23.6"
 
 "@babel/highlight@^7.23.4":
   version "7.23.4"
@@ -375,10 +375,10 @@
     chalk "^2.4.2"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.23.5":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563"
-  integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6":
+  version "7.23.6"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b"
+  integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.23.3":
   version "7.23.3"
@@ -396,10 +396,10 @@
     "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5"
     "@babel/plugin-transform-optional-chaining" "^7.23.3"
 
-"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.23.3":
-  version "7.23.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz#20c60d4639d18f7da8602548512e9d3a4c8d7098"
-  integrity sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==
+"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz#516462a95d10a9618f197d39ad291a9b47ae1d7b"
+  integrity sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==
   dependencies:
     "@babel/helper-environment-visitor" "^7.22.20"
     "@babel/helper-plugin-utils" "^7.22.5"
@@ -579,10 +579,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.22.5"
 
-"@babel/plugin-transform-async-generator-functions@^7.23.4":
-  version "7.23.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz#93ac8e3531f347fba519b4703f9ff2a75c6ae27a"
-  integrity sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==
+"@babel/plugin-transform-async-generator-functions@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz#3aa0b4f2fa3788b5226ef9346cf6d16ec61f99cd"
+  integrity sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==
   dependencies:
     "@babel/helper-environment-visitor" "^7.22.20"
     "@babel/helper-plugin-utils" "^7.22.5"
@@ -994,10 +994,10 @@
     "@babel/helper-create-regexp-features-plugin" "^7.22.15"
     "@babel/helper-plugin-utils" "^7.22.5"
 
-"@babel/preset-env@^7.23.6":
-  version "7.23.6"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.6.tgz#ad0ea799d5a3c07db5b9a172819bbd444092187a"
-  integrity sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ==
+"@babel/preset-env@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.7.tgz#e5d69b9f14db8a13bae4d8e5ce7f360973626241"
+  integrity sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==
   dependencies:
     "@babel/compat-data" "^7.23.5"
     "@babel/helper-compilation-targets" "^7.23.6"
@@ -1005,7 +1005,7 @@
     "@babel/helper-validator-option" "^7.23.5"
     "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.23.3"
     "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.23.3"
-    "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.23.3"
+    "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.23.7"
     "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2"
     "@babel/plugin-syntax-async-generators" "^7.8.4"
     "@babel/plugin-syntax-class-properties" "^7.12.13"
@@ -1026,7 +1026,7 @@
     "@babel/plugin-syntax-top-level-await" "^7.14.5"
     "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6"
     "@babel/plugin-transform-arrow-functions" "^7.23.3"
-    "@babel/plugin-transform-async-generator-functions" "^7.23.4"
+    "@babel/plugin-transform-async-generator-functions" "^7.23.7"
     "@babel/plugin-transform-async-to-generator" "^7.23.3"
     "@babel/plugin-transform-block-scoped-functions" "^7.23.3"
     "@babel/plugin-transform-block-scoping" "^7.23.4"
@@ -1074,9 +1074,9 @@
     "@babel/plugin-transform-unicode-regex" "^7.23.3"
     "@babel/plugin-transform-unicode-sets-regex" "^7.23.3"
     "@babel/preset-modules" "0.1.6-no-external-plugins"
-    babel-plugin-polyfill-corejs2 "^0.4.6"
-    babel-plugin-polyfill-corejs3 "^0.8.5"
-    babel-plugin-polyfill-regenerator "^0.5.3"
+    babel-plugin-polyfill-corejs2 "^0.4.7"
+    babel-plugin-polyfill-corejs3 "^0.8.7"
+    babel-plugin-polyfill-regenerator "^0.5.4"
     core-js-compat "^3.31.0"
     semver "^6.3.1"
 
@@ -1122,26 +1122,26 @@
     "@babel/parser" "^7.22.15"
     "@babel/types" "^7.22.15"
 
-"@babel/traverse@^7.18.6", "@babel/traverse@^7.23.5":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.5.tgz#f546bf9aba9ef2b042c0e00d245990c15508e7ec"
-  integrity sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==
+"@babel/traverse@^7.18.6", "@babel/traverse@^7.23.7":
+  version "7.23.7"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305"
+  integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==
   dependencies:
     "@babel/code-frame" "^7.23.5"
-    "@babel/generator" "^7.23.5"
+    "@babel/generator" "^7.23.6"
     "@babel/helper-environment-visitor" "^7.22.20"
     "@babel/helper-function-name" "^7.23.0"
     "@babel/helper-hoist-variables" "^7.22.5"
     "@babel/helper-split-export-declaration" "^7.22.6"
-    "@babel/parser" "^7.23.5"
-    "@babel/types" "^7.23.5"
-    debug "^4.1.0"
+    "@babel/parser" "^7.23.6"
+    "@babel/types" "^7.23.6"
+    debug "^4.3.1"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602"
-  integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==
+"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+  version "7.23.6"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd"
+  integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==
   dependencies:
     "@babel/helper-string-parser" "^7.23.4"
     "@babel/helper-validator-identifier" "^7.22.20"
@@ -2650,29 +2650,29 @@ babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0:
     cosmiconfig "^7.0.0"
     resolve "^1.19.0"
 
-babel-plugin-polyfill-corejs2@^0.4.6:
-  version "0.4.6"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313"
-  integrity sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==
+babel-plugin-polyfill-corejs2@^0.4.7:
+  version "0.4.7"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz#679d1b94bf3360f7682e11f2cb2708828a24fe8c"
+  integrity sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==
   dependencies:
     "@babel/compat-data" "^7.22.6"
-    "@babel/helper-define-polyfill-provider" "^0.4.3"
+    "@babel/helper-define-polyfill-provider" "^0.4.4"
     semver "^6.3.1"
 
-babel-plugin-polyfill-corejs3@^0.8.5:
-  version "0.8.5"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz#a75fa1b0c3fc5bd6837f9ec465c0f48031b8cab1"
-  integrity sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==
+babel-plugin-polyfill-corejs3@^0.8.7:
+  version "0.8.7"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz#941855aa7fdaac06ed24c730a93450d2b2b76d04"
+  integrity sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.4.3"
-    core-js-compat "^3.32.2"
+    "@babel/helper-define-polyfill-provider" "^0.4.4"
+    core-js-compat "^3.33.1"
 
-babel-plugin-polyfill-regenerator@^0.5.3:
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz#d4c49e4b44614607c13fb769bcd85c72bb26a4a5"
-  integrity sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==
+babel-plugin-polyfill-regenerator@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz#c6fc8eab610d3a11eb475391e52584bacfc020f4"
+  integrity sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.4.3"
+    "@babel/helper-define-polyfill-provider" "^0.4.4"
 
 babel-plugin-transform-react-remove-prop-types@0.4.24:
   version "0.4.24"
@@ -2799,7 +2799,7 @@ browser-process-hrtime@^1.0.0:
   resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
   integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
 
-browserslist@^4.14.5, browserslist@^4.21.10:
+browserslist@^4.14.5:
   version "4.21.11"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.11.tgz#35f74a3e51adc4d193dcd76ea13858de7b8fecb8"
   integrity sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==
@@ -3023,10 +3023,10 @@ cjs-module-lexer@^1.0.0:
   resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
   integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
 
-classnames@2.3.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
-  integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
+classnames@2.5.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
+  integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
 
 clean-css@^5.1.5:
   version "5.2.1"
@@ -3244,17 +3244,17 @@ cookie@0.4.2:
   resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
   integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
 
-core-js-compat@^3.31.0, core-js-compat@^3.32.2:
-  version "3.32.2"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.2.tgz#8047d1a8b3ac4e639f0d4f66d4431aa3b16e004c"
-  integrity sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==
+core-js-compat@^3.31.0, core-js-compat@^3.33.1:
+  version "3.35.0"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.35.0.tgz#c149a3d1ab51e743bc1da61e39cb51f461a41873"
+  integrity sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==
   dependencies:
-    browserslist "^4.21.10"
+    browserslist "^4.22.2"
 
-core-js@^3.34.0:
-  version "3.34.0"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.34.0.tgz#5705e6ad5982678612e96987d05b27c6c7c274a5"
-  integrity sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==
+core-js@^3.35.0:
+  version "3.35.0"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.0.tgz#58e651688484f83c34196ca13f099574ee53d6b4"
+  integrity sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==
 
 core-util-is@~1.0.0:
   version "1.0.3"
@@ -3440,7 +3440,12 @@ data-urls@^3.0.2:
     whatwg-mimetype "^3.0.0"
     whatwg-url "^11.0.0"
 
-date-fns@2.30.0, date-fns@^2.16.1:
+date-fns@3.0.6:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.0.6.tgz#fe3aeb7592d359f075ffc41cb16139828810ca83"
+  integrity sha512-W+G99rycpKMMF2/YD064b2lE7jJGUe+EjOES7Q8BIGY8sbNdbgcs9XFTZwvzc9Jx1f3k7LB7gZaZa7f8Agzljg==
+
+date-fns@^2.16.1:
   version "2.30.0"
   resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
   integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
@@ -3459,7 +3464,7 @@ debug@2.6.9:
   dependencies:
     ms "2.0.0"
 
-debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
   version "4.3.4"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
   integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -4203,10 +4208,10 @@ eslint-module-utils@^2.8.0:
   dependencies:
     debug "^3.2.7"
 
-eslint-plugin-import@^2.29.0:
-  version "2.29.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155"
-  integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==
+eslint-plugin-import@^2.29.1:
+  version "2.29.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
+  integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
   dependencies:
     array-includes "^3.1.7"
     array.prototype.findlastindex "^1.2.3"
@@ -4224,7 +4229,7 @@ eslint-plugin-import@^2.29.0:
     object.groupby "^1.0.1"
     object.values "^1.1.7"
     semver "^6.3.1"
-    tsconfig-paths "^3.14.2"
+    tsconfig-paths "^3.15.0"
 
 eslint-plugin-jsx-a11y@^6.7.1:
   version "6.7.1"
@@ -5059,10 +5064,10 @@ html-minifier-terser@^6.0.2:
     relateurl "^0.2.7"
     terser "^5.7.2"
 
-html-webpack-plugin@^5.5.4:
-  version "5.5.4"
-  resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.4.tgz#517a48e6f046ff1ae1a172c983cd993eb79d2f6a"
-  integrity sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==
+html-webpack-plugin@^5.6.0:
+  version "5.6.0"
+  resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0"
+  integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==
   dependencies:
     "@types/html-minifier-terser" "^6.0.0"
     html-minifier-terser "^6.0.2"
@@ -8609,10 +8614,10 @@ tr46@^3.0.0:
   dependencies:
     punycode "^2.1.1"
 
-tsconfig-paths@^3.14.2:
-  version "3.14.2"
-  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
-  integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==
+tsconfig-paths@^3.15.0:
+  version "3.15.0"
+  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
+  integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
   dependencies:
     "@types/json5" "^0.0.29"
     json5 "^1.0.2"


Test patch:
diff --git a/cli/cmd/inject_test.go b/cli/cmd/inject_test.go
index 709526f46..6ed75fd8e 100644
--- a/cli/cmd/inject_test.go
+++ b/cli/cmd/inject_test.go
@@ -33,6 +33,8 @@ func mkFilename(filename string, verbose bool) string {
 }
 
 func testUninjectAndInject(t *testing.T, tc testCase) {
+	t.Helper()
+
 	file, err := os.Open("testdata/" + tc.inputFileName)
 	if err != nil {
 		t.Errorf("error opening test input file: %v\n", err)
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
index a035e8a45..f54302b0c 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx.yaml
@@ -48,6 +48,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 2202a79c4..c29b1c15c 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_nginx_redis.yaml
@@ -48,6 +48,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -262,6 +268,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
index 7da2ca85f..64f843149 100644
--- a/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
+++ b/cli/cmd/testdata/inject-filepath/expected/injected_redis.yaml
@@ -48,6 +48,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_contour.golden.yml b/cli/cmd/testdata/inject_contour.golden.yml
index f8144419e..f0fbe708a 100644
--- a/cli/cmd/testdata/inject_contour.golden.yml
+++ b/cli/cmd/testdata/inject_contour.golden.yml
@@ -56,6 +56,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
index 3f4085bd4..066d61ef5 100644
--- a/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_already_injected.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -275,6 +281,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -500,6 +512,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -725,6 +743,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
index 0733e684a..a5e12f618 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_access_log.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_access_log.golden.yml
index b3904a4c9..7fa9baab5 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_access_log.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_access_log.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_automountServiceAccountToken_false.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_automountServiceAccountToken_false.golden.yml
index 4469e3927..6cda7e096 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_automountServiceAccountToken_false.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_automountServiceAccountToken_false.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
index 6c4417e1f..af2980a20 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_capabilities.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 d159bc91d..bd541fcbb 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_config_overrides.golden.yml
@@ -60,6 +60,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 a13909723..31af59bc8 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_controller_name.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -275,6 +281,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
index acdf2fbec..a03614bc1 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_debug.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 c23e17076..d9da3231f 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_empty_resources.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 03dfa74d1..296d130fc 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_hostNetwork_false.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_native_sidecar.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_native_sidecar.golden.yml
index 9ba681505..a02eb5b1c 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_native_sidecar.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_native_sidecar.golden.yml
@@ -103,6 +103,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 54097aa88..fff2448b4 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
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
index ff17eb4d9..6f005e6a2 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_opaque_ports.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
index 22e3edaa6..86912d6ca 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_overridden.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
index c0c8e0ec5..76890e12d 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_proxyignores.golden.yml
@@ -52,6 +52,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
index 699d96513..fe22f4319 100644
--- a/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_deployment_udp.golden.yml
@@ -50,6 +50,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_list.golden.yml b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
index 6bb7c4dbb..f9e54ec38 100644
--- a/cli/cmd/testdata/inject_emojivoto_list.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list.golden.yml
@@ -52,6 +52,12 @@ items:
             value: all-unauthenticated
           - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
             value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+          - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+            value: 3s
+          - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+            value: 5m
+          - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+            value: 1h
           - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
             value: 100ms
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -276,6 +282,12 @@ items:
             value: all-unauthenticated
           - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
             value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+          - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+            value: 3s
+          - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+            value: 5m
+          - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+            value: 1h
           - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
             value: 100ms
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 8667ce0c4..72fcf66e2 100644
--- a/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_list_empty_resources.golden.yml
@@ -52,6 +52,12 @@ items:
             value: all-unauthenticated
           - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
             value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+          - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+            value: 3s
+          - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+            value: 5m
+          - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+            value: 1h
           - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
             value: 100ms
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -276,6 +282,12 @@ items:
             value: all-unauthenticated
           - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
             value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+          - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+            value: 3s
+          - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+            value: 5m
+          - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+            value: 1h
           - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
             value: 100ms
           - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
index 9a16bade9..93c5c0211 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod.golden.yml
@@ -42,6 +42,12 @@ spec:
       value: all-unauthenticated
     - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
       value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+    - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+      value: 3s
+    - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+      value: 5m
+    - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+      value: 1h
     - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
       value: 100ms
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
index 618d5e1d8..ff85a2a5e 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_ingress.golden.yml
@@ -43,6 +43,12 @@ spec:
       value: all-unauthenticated
     - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
       value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+    - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+      value: 3s
+    - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+      value: 5m
+    - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+      value: 1h
     - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
       value: 100ms
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
index 182c240b4..7ce5d234f 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_proxyignores.golden.yml
@@ -44,6 +44,12 @@ spec:
       value: all-unauthenticated
     - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
       value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+    - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+      value: 3s
+    - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+      value: 5m
+    - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+      value: 1h
     - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
       value: 100ms
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 c9ebe123f..745c45dc4 100644
--- a/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_pod_with_requests.golden.yml
@@ -46,6 +46,12 @@ spec:
       value: all-unauthenticated
     - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
       value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+    - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+      value: 3s
+    - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+      value: 5m
+    - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+      value: 1h
     - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
       value: 100ms
     - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
index f789363fd..f2f51c98b 100644
--- a/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
+++ b/cli/cmd/testdata/inject_emojivoto_statefulset.golden.yml
@@ -51,6 +51,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
index 45f177057..bc660d7ad 100644
--- a/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
+++ b/cli/cmd/testdata/inject_gettest_deployment.good.golden.yml
@@ -46,6 +46,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -273,6 +279,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
index 6028117f1..05fb2b80d 100644
--- a/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
+++ b/cli/cmd/testdata/inject_tap_deployment_debug.golden.yml
@@ -67,6 +67,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: 3s
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: 5m
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: 1h
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: 100ms
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_controlplane_tracing_output.golden b/cli/cmd/testdata/install_controlplane_tracing_output.golden
index 24455534c..17354f7e5 100644
--- a/cli/cmd/testdata/install_controlplane_tracing_output.golden
+++ b/cli/cmd/testdata/install_controlplane_tracing_output.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -937,6 +943,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1264,6 +1276,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1691,6 +1709,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_custom_domain.golden b/cli/cmd/testdata/install_custom_domain.golden
index 82a717f27..e872b5a48 100644
--- a/cli/cmd/testdata/install_custom_domain.golden
+++ b/cli/cmd/testdata/install_custom_domain.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden
index e4ec8f65e..089e06bed 100644
--- a/cli/cmd/testdata/install_custom_registry.golden
+++ b/cli/cmd/testdata/install_custom_registry.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: my.custom.registry/linkerd-io/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden
index 82a717f27..e872b5a48 100644
--- a/cli/cmd/testdata/install_default.golden
+++ b/cli/cmd/testdata/install_default.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 0f8b0fecf..c86044d96 100644
--- a/cli/cmd/testdata/install_default_override_dst_get_nets.golden
+++ b/cli/cmd/testdata/install_default_override_dst_get_nets.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.0.0.0/8"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.0.0.0/8"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.0.0.0/8"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_default_token.golden b/cli/cmd/testdata/install_default_token.golden
index 3ecf3dfca..5d0350cdd 100644
--- a/cli/cmd/testdata/install_default_token.golden
+++ b/cli/cmd/testdata/install_default_token.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1254,6 +1266,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1671,6 +1689,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden
index 11f673767..f2a821151 100644
--- a/cli/cmd/testdata/install_ha_output.golden
+++ b/cli/cmd/testdata/install_ha_output.golden
@@ -650,10 +650,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -1013,6 +1019,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1380,6 +1392,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1842,6 +1860,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden
index 1f673b836..1febd663b 100644
--- a/cli/cmd/testdata/install_ha_with_overrides_output.golden
+++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden
@@ -650,10 +650,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -1013,6 +1019,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1380,6 +1392,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1842,6 +1860,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_heartbeat_disabled_output.golden b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
index b07b29ece..7662b6a56 100644
--- a/cli/cmd/testdata/install_heartbeat_disabled_output.golden
+++ b/cli/cmd/testdata/install_heartbeat_disabled_output.golden
@@ -554,10 +554,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -867,6 +873,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1194,6 +1206,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1560,6 +1578,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_helm_control_plane_output.golden b/cli/cmd/testdata/install_helm_control_plane_output.golden
index d117cc5e1..adb265e72 100644
--- a/cli/cmd/testdata/install_helm_control_plane_output.golden
+++ b/cli/cmd/testdata/install_helm_control_plane_output.golden
@@ -600,10 +600,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -909,6 +915,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1238,6 +1250,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1668,6 +1686,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_helm_control_plane_output_ha.golden b/cli/cmd/testdata/install_helm_control_plane_output_ha.golden
index cdeb88309..b05e1eb0c 100644
--- a/cli/cmd/testdata/install_helm_control_plane_output_ha.golden
+++ b/cli/cmd/testdata/install_helm_control_plane_output_ha.golden
@@ -627,10 +627,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -986,6 +992,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1355,6 +1367,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1821,6 +1839,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_helm_output_ha_labels.golden b/cli/cmd/testdata/install_helm_output_ha_labels.golden
index 1e7a450fb..dc7543103 100644
--- a/cli/cmd/testdata/install_helm_output_ha_labels.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_labels.golden
@@ -631,10 +631,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -994,6 +1000,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1367,6 +1379,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1841,6 +1859,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
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 1a5d0a697..499ef81cc 100644
--- a/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
+++ b/cli/cmd/testdata/install_helm_output_ha_namespace_selector.golden
@@ -622,10 +622,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -976,6 +982,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1345,6 +1357,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1811,6 +1829,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden
index ee3cdf325..8768ea6b4 100644
--- a/cli/cmd/testdata/install_no_init_container.golden
+++ b/cli/cmd/testdata/install_no_init_container.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1257,6 +1269,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1677,6 +1695,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden
index a7b92eafe..3b2209808 100644
--- a/cli/cmd/testdata/install_output.golden
+++ b/cli/cmd/testdata/install_output.golden
@@ -603,10 +603,12 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control: null
       defaultInboundPolicy: default-allow-policy
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: ProxyImageName
         pullPolicy: ImagePullPolicy
@@ -909,6 +911,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "ClusterNetworks"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: ""
         - name: LINKERD2_PROXY_OUTBOUND_DISCOVERY_IDLE_TIMEOUT
           value: "5s"
         - name: LINKERD2_PROXY_INBOUND_DISCOVERY_IDLE_TIMEOUT
@@ -1233,6 +1241,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "ClusterNetworks"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: ""
         - name: LINKERD2_PROXY_OUTBOUND_DISCOVERY_IDLE_TIMEOUT
           value: "5s"
         - name: LINKERD2_PROXY_INBOUND_DISCOVERY_IDLE_TIMEOUT
@@ -1663,6 +1677,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "ClusterNetworks"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: ""
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: ""
         - name: LINKERD2_PROXY_OUTBOUND_DISCOVERY_IDLE_TIMEOUT
           value: "5s"
         - name: LINKERD2_PROXY_INBOUND_DISCOVERY_IDLE_TIMEOUT
@@ -1895,7 +1915,7 @@ spec:
 ---
 apiVersion: v1
 data:
-  linkerd-config-overrides: Y2xpVmVyc2lvbjogQ2xpVmVyc2lvbgpjbHVzdGVyTmV0d29ya3M6IENsdXN0ZXJOZXR3b3Jrcwpjb250cm9sUGxhbmVUcmFjaW5nTmFtZXNwYWNlOiAiIgpjb250cm9sbGVySW1hZ2U6IENvbnRyb2xsZXJJbWFnZQpjb250cm9sbGVyTG9nRm9ybWF0OiBDb250cm9sbGVyTG9nRm9ybWF0CmNvbnRyb2xsZXJMb2dMZXZlbDogQ29udHJvbGxlckxvZ0xldmVsCmRlYnVnQ29udGFpbmVyOgogIGltYWdlOgogICAgbmFtZTogRGVidWdJbWFnZU5hbWUKICAgIHB1bGxQb2xpY3k6IERlYnVnSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBEZWJ1Z1ZlcnNpb24KZW5hYmxlRW5kcG9pbnRTbGljZXM6IGZhbHNlCmhlYXJ0YmVhdFNjaGVkdWxlOiAxIDIgMyA0IDUKaWRlbnRpdHk6CiAgaXNzdWVyOgogICAgdGxzOgogICAgICBjcnRQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICAgICAgICBNSUlCd0RDQ0FXZWdBd0lCQWdJUkFKUklnWjhSdE84RXdnMVhlcGY4VDQ0d0NnWUlLb1pJemowRUF3SXdLVEVuCiAgICAgICAgTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01CNFhEVEl3TURneQogICAgICAgIE9EQTNNVE0wTjFvWERUTXdNRGd5TmpBM01UTTBOMW93S1RFbk1DVUdBMVVFQXhNZWFXUmxiblJwZEhrdWJHbHUKICAgICAgICBhMlZ5WkM1amJIVnpkR1Z5TG14dlkyRnNNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxL0ZwCiAgICAgICAgZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyZFF2UmFZYW51eEQzNkR0MQogICAgICAgIDIvSnh5aVNneEtXUmRvYXkrYU53TUc0d0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUIKICAgICAgICBBZjhDQVFBd0hRWURWUjBPQkJZRUZJMVducnFNWUthSEhPbyt6cHlpaURxMnBPMEtNQ2tHQTFVZEVRUWlNQ0NDCiAgICAgICAgSG1sa1pXNTBhWFI1TG14cGJtdGxjbVF1WTJ4MWMzUmxjaTVzYjJOaGJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRQogICAgICAgIEFpQXR1b0k1WHVDdHJHVlJ6U21SVGwycmEyOGFWOU15VFU3ZDVxblRBRkhLU2dJZ1JLQ3ZsdU9TZ0E1TzIxcDUKICAgICAgICA1MXRkcm1rSEVaUnIwcWxMU0pkSFlnRWZNems9CiAgICAgICAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQogICAgICBrZXlQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KICAgICAgICBNSGNDQVFFRUlBQWU4bmZielp1OWMvT0IyKzh4Sk0wRno3TlV3VFFhenVsa0ZOczRUSTUrb0FvR0NDcUdTTTQ5CiAgICAgICAgQXdFSG9VUURRZ0FFMS9GcGZjUm5EY2VkTDZBalVhWFlQdjRESU1CYUp1Zk9JNU5XdHkrWFNYN0pqWGdadE03MgogICAgICAgIGRRdlJhWWFudXhEMzZEdDEyL0p4eWlTZ3hLV1Jkb2F5K1E9PQogICAgICAgIC0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0KaWRlbnRpdHlUcnVzdEFuY2hvcnNQRU06IHwKICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICBNSUlCd1RDQ0FXYWdBd0lCQWdJUWVEWnA1bERhSXlnUTVVZk1LWnJGQVRBS0JnZ3Foa2pPUFFRREFqQXBNU2N3CiAgSlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1clpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d0hoY05NakF3T0RJNAogIE1EY3hNalEzV2hjTk16QXdPREkyTURjeE1qUTNXakFwTVNjd0pRWURWUVFERXg1cFpHVnVkR2wwZVM1c2FXNXIKICBaWEprTG1Oc2RYTjBaWEl1Ykc5allXd3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBUnFjNzBaCiAgbDF2Z3c3OXJqQjV1U0lUSUNVQTZHeWZ2U0ZmY3VJaXM3Qi9YRlNra3dBSFU1Uy9zMUFBUCtSMFRYN0hCV1VDNAogIHVhRzRXV3Npd0pLTm43bWdvM0F3YmpBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIKICAvd0lCQVRBZEJnTlZIUTRFRmdRVTVZdGpWVlBmZDdJN05MSHNuMkMyNkVCeUdWMHdLUVlEVlIwUkJDSXdJSUllCiAgYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQwogIElRQ043bEJGTEREdmp4NlYwK1hranBLRVJSc0pZZjVhZE12bmxvRmw0OGlsSmdJaEFOdHhobmRjcitRSlB1QzgKICB2Z1VDMGQyLzlGTXVlSVZNYis0NldUQ09qc3FyCiAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQppbWFnZVB1bGxQb2xpY3k6IEltYWdlUHVsbFBvbGljeQppbWFnZVB1bGxTZWNyZXRzOiBudWxsCmxpbmtlcmRWZXJzaW9uOiBMaW5rZXJkVmVyc2lvbgpuZXR3b3JrVmFsaWRhdG9yOgogIGVuYWJsZVNlY3VyaXR5Q29udGV4dDogZmFsc2UKcG9kTW9uaXRvcjogbnVsbApwb2xpY3lDb250cm9sbGVyOgogIGltYWdlOgogICAgbmFtZTogUG9saWN5Q29udHJvbGxlckltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQb2xpY3lDb250cm9sbGVyVmVyc2lvbgogIGxvZ0xldmVsOiBsb2ctbGV2ZWwKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIGxpbWl0OiBjcHUtbGltaXQKICAgICAgcmVxdWVzdDogY3B1LXJlcXVlc3QKICAgIG1lbW9yeToKICAgICAgbGltaXQ6IG1lbW9yeS1saW1pdAogICAgICByZXF1ZXN0OiBtZW1vcnktcmVxdWVzdApwb2xpY3lWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHBvbGljeSB2YWxpZGF0b3IgQ0EgYnVuZGxlCiAgZXh0ZXJuYWxTZWNyZXQ6IHRydWUKcHJpb3JpdHlDbGFzc05hbWU6IFByaW9yaXR5Q2xhc3NOYW1lCnByb2ZpbGVWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHByb2ZpbGUgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGV4dGVybmFsU2VjcmV0OiB0cnVlCnByb3h5OgogIGRlZmF1bHRJbmJvdW5kUG9saWN5OiBkZWZhdWx0LWFsbG93LXBvbGljeQogIGltYWdlOgogICAgbmFtZTogUHJveHlJbWFnZU5hbWUKICAgIHB1bGxQb2xpY3k6IEltYWdlUHVsbFBvbGljeQogICAgdmVyc2lvbjogUHJveHlWZXJzaW9uCiAgaW5ib3VuZENvbm5lY3RUaW1lb3V0OiAiIgogIGluYm91bmREaXNjb3ZlcnlDYWNoZVVudXNlZFRpbWVvdXQ6ICIiCiAgbG9nTGV2ZWw6IHdhcm4sbGlua2VyZD1pbmZvCiAgb3BhcXVlUG9ydHM6IDI1LDQ0Myw1ODcsMzMwNiw1NDMyLDExMjExCiAgb3V0Ym91bmRDb25uZWN0VGltZW91dDogIiIKICBvdXRib3VuZERpc2NvdmVyeUNhY2hlVW51c2VkVGltZW91dDogIiIKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIGxpbWl0OiBjcHUtbGltaXQKICAgICAgcmVxdWVzdDogY3B1LXJlcXVlc3QKICAgIG1lbW9yeToKICAgICAgbGltaXQ6IG1lbW9yeS1saW1pdAogICAgICByZXF1ZXN0OiBtZW1vcnktcmVxdWVzdAogIHN0YXJ0dXBQcm9iZTogbnVsbApwcm94eUNvbnRhaW5lck5hbWU6IFByb3h5Q29udGFpbmVyTmFtZQpwcm94eUluaXQ6CiAgaWdub3JlSW5ib3VuZFBvcnRzOiAiIgogIGlnbm9yZU91dGJvdW5kUG9ydHM6ICI0NDMiCiAgaW1hZ2U6CiAgICBuYW1lOiBQcm94eUluaXRJbWFnZU5hbWUKICAgIHB1bGxQb2xpY3k6IEltYWdlUHVsbFBvbGljeQogICAgdmVyc2lvbjogUHJveHlJbml0VmVyc2lvbgogIGt1YmVBUElTZXJ2ZXJQb3J0czogIiIKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIHJlcXVlc3Q6IDEwbQogICAgbWVtb3J5OgogICAgICBsaW1pdDogNTBNaQogICAgICByZXF1ZXN0OiAxME1pCnByb3h5SW5qZWN0b3I6CiAgY2FCdW5kbGU6IHByb3h5IGluamVjdG9yIENBIGJ1bmRsZQogIGV4dGVybmFsU2VjcmV0OiB0cnVlCndlYmhvb2tGYWlsdXJlUG9saWN5OiBXZWJob29rRmFpbHVyZVBvbGljeQo=
+  linkerd-config-overrides: Y2xpVmVyc2lvbjogQ2xpVmVyc2lvbgpjbHVzdGVyTmV0d29ya3M6IENsdXN0ZXJOZXR3b3Jrcwpjb250cm9sUGxhbmVUcmFjaW5nTmFtZXNwYWNlOiAiIgpjb250cm9sbGVySW1hZ2U6IENvbnRyb2xsZXJJbWFnZQpjb250cm9sbGVyTG9nRm9ybWF0OiBDb250cm9sbGVyTG9nRm9ybWF0CmNvbnRyb2xsZXJMb2dMZXZlbDogQ29udHJvbGxlckxvZ0xldmVsCmRlYnVnQ29udGFpbmVyOgogIGltYWdlOgogICAgbmFtZTogRGVidWdJbWFnZU5hbWUKICAgIHB1bGxQb2xpY3k6IERlYnVnSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBEZWJ1Z1ZlcnNpb24KZW5hYmxlRW5kcG9pbnRTbGljZXM6IGZhbHNlCmhlYXJ0YmVhdFNjaGVkdWxlOiAxIDIgMyA0IDUKaWRlbnRpdHk6CiAgaXNzdWVyOgogICAgdGxzOgogICAgICBjcnRQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICAgICAgICBNSUlCd0RDQ0FXZWdBd0lCQWdJUkFKUklnWjhSdE84RXdnMVhlcGY4VDQ0d0NnWUlLb1pJemowRUF3SXdLVEVuCiAgICAgICAgTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01CNFhEVEl3TURneQogICAgICAgIE9EQTNNVE0wTjFvWERUTXdNRGd5TmpBM01UTTBOMW93S1RFbk1DVUdBMVVFQXhNZWFXUmxiblJwZEhrdWJHbHUKICAgICAgICBhMlZ5WkM1amJIVnpkR1Z5TG14dlkyRnNNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxL0ZwCiAgICAgICAgZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyZFF2UmFZYW51eEQzNkR0MQogICAgICAgIDIvSnh5aVNneEtXUmRvYXkrYU53TUc0d0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUIKICAgICAgICBBZjhDQVFBd0hRWURWUjBPQkJZRUZJMVducnFNWUthSEhPbyt6cHlpaURxMnBPMEtNQ2tHQTFVZEVRUWlNQ0NDCiAgICAgICAgSG1sa1pXNTBhWFI1TG14cGJtdGxjbVF1WTJ4MWMzUmxjaTVzYjJOaGJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRQogICAgICAgIEFpQXR1b0k1WHVDdHJHVlJ6U21SVGwycmEyOGFWOU15VFU3ZDVxblRBRkhLU2dJZ1JLQ3ZsdU9TZ0E1TzIxcDUKICAgICAgICA1MXRkcm1rSEVaUnIwcWxMU0pkSFlnRWZNems9CiAgICAgICAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQogICAgICBrZXlQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KICAgICAgICBNSGNDQVFFRUlBQWU4bmZielp1OWMvT0IyKzh4Sk0wRno3TlV3VFFhenVsa0ZOczRUSTUrb0FvR0NDcUdTTTQ5CiAgICAgICAgQXdFSG9VUURRZ0FFMS9GcGZjUm5EY2VkTDZBalVhWFlQdjRESU1CYUp1Zk9JNU5XdHkrWFNYN0pqWGdadE03MgogICAgICAgIGRRdlJhWWFudXhEMzZEdDEyL0p4eWlTZ3hLV1Jkb2F5K1E9PQogICAgICAgIC0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0KaWRlbnRpdHlUcnVzdEFuY2hvcnNQRU06IHwKICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICBNSUlCd1RDQ0FXYWdBd0lCQWdJUWVEWnA1bERhSXlnUTVVZk1LWnJGQVRBS0JnZ3Foa2pPUFFRREFqQXBNU2N3CiAgSlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1clpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d0hoY05NakF3T0RJNAogIE1EY3hNalEzV2hjTk16QXdPREkyTURjeE1qUTNXakFwTVNjd0pRWURWUVFERXg1cFpHVnVkR2wwZVM1c2FXNXIKICBaWEprTG1Oc2RYTjBaWEl1Ykc5allXd3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBUnFjNzBaCiAgbDF2Z3c3OXJqQjV1U0lUSUNVQTZHeWZ2U0ZmY3VJaXM3Qi9YRlNra3dBSFU1Uy9zMUFBUCtSMFRYN0hCV1VDNAogIHVhRzRXV3Npd0pLTm43bWdvM0F3YmpBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIKICAvd0lCQVRBZEJnTlZIUTRFRmdRVTVZdGpWVlBmZDdJN05MSHNuMkMyNkVCeUdWMHdLUVlEVlIwUkJDSXdJSUllCiAgYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQwogIElRQ043bEJGTEREdmp4NlYwK1hranBLRVJSc0pZZjVhZE12bmxvRmw0OGlsSmdJaEFOdHhobmRjcitRSlB1QzgKICB2Z1VDMGQyLzlGTXVlSVZNYis0NldUQ09qc3FyCiAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQppbWFnZVB1bGxQb2xpY3k6IEltYWdlUHVsbFBvbGljeQppbWFnZVB1bGxTZWNyZXRzOiBudWxsCmxpbmtlcmRWZXJzaW9uOiBMaW5rZXJkVmVyc2lvbgpuZXR3b3JrVmFsaWRhdG9yOgogIGVuYWJsZVNlY3VyaXR5Q29udGV4dDogZmFsc2UKcG9kTW9uaXRvcjogbnVsbApwb2xpY3lDb250cm9sbGVyOgogIGltYWdlOgogICAgbmFtZTogUG9saWN5Q29udHJvbGxlckltYWdlTmFtZQogICAgcHVsbFBvbGljeTogSW1hZ2VQdWxsUG9saWN5CiAgICB2ZXJzaW9uOiBQb2xpY3lDb250cm9sbGVyVmVyc2lvbgogIGxvZ0xldmVsOiBsb2ctbGV2ZWwKICByZXNvdXJjZXM6CiAgICBjcHU6CiAgICAgIGxpbWl0OiBjcHUtbGltaXQKICAgICAgcmVxdWVzdDogY3B1LXJlcXVlc3QKICAgIG1lbW9yeToKICAgICAgbGltaXQ6IG1lbW9yeS1saW1pdAogICAgICByZXF1ZXN0OiBtZW1vcnktcmVxdWVzdApwb2xpY3lWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHBvbGljeSB2YWxpZGF0b3IgQ0EgYnVuZGxlCiAgZXh0ZXJuYWxTZWNyZXQ6IHRydWUKcHJpb3JpdHlDbGFzc05hbWU6IFByaW9yaXR5Q2xhc3NOYW1lCnByb2ZpbGVWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHByb2ZpbGUgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGV4dGVybmFsU2VjcmV0OiB0cnVlCnByb3h5OgogIGNvbnRyb2w6IG51bGwKICBkZWZhdWx0SW5ib3VuZFBvbGljeTogZGVmYXVsdC1hbGxvdy1wb2xpY3kKICBpbWFnZToKICAgIG5hbWU6IFByb3h5SW1hZ2VOYW1lCiAgICBwdWxsUG9saWN5OiBJbWFnZVB1bGxQb2xpY3kKICAgIHZlcnNpb246IFByb3h5VmVyc2lvbgogIGluYm91bmRDb25uZWN0VGltZW91dDogIiIKICBpbmJvdW5kRGlzY292ZXJ5Q2FjaGVVbnVzZWRUaW1lb3V0OiAiIgogIGxvZ0xldmVsOiB3YXJuLGxpbmtlcmQ9aW5mbwogIG9wYXF1ZVBvcnRzOiAyNSw0NDMsNTg3LDMzMDYsNTQzMiwxMTIxMQogIG91dGJvdW5kQ29ubmVjdFRpbWVvdXQ6ICIiCiAgb3V0Ym91bmREaXNjb3ZlcnlDYWNoZVVudXNlZFRpbWVvdXQ6ICIiCiAgcmVzb3VyY2VzOgogICAgY3B1OgogICAgICBsaW1pdDogY3B1LWxpbWl0CiAgICAgIHJlcXVlc3Q6IGNwdS1yZXF1ZXN0CiAgICBtZW1vcnk6CiAgICAgIGxpbWl0OiBtZW1vcnktbGltaXQKICAgICAgcmVxdWVzdDogbWVtb3J5LXJlcXVlc3QKICBzdGFydHVwUHJvYmU6IG51bGwKcHJveHlDb250YWluZXJOYW1lOiBQcm94eUNvbnRhaW5lck5hbWUKcHJveHlJbml0OgogIGlnbm9yZUluYm91bmRQb3J0czogIiIKICBpZ25vcmVPdXRib3VuZFBvcnRzOiAiNDQzIgogIGltYWdlOgogICAgbmFtZTogUHJveHlJbml0SW1hZ2VOYW1lCiAgICBwdWxsUG9saWN5OiBJbWFnZVB1bGxQb2xpY3kKICAgIHZlcnNpb246IFByb3h5SW5pdFZlcnNpb24KICBrdWJlQVBJU2VydmVyUG9ydHM6ICIiCiAgcmVzb3VyY2VzOgogICAgY3B1OgogICAgICByZXF1ZXN0OiAxMG0KICAgIG1lbW9yeToKICAgICAgbGltaXQ6IDUwTWkKICAgICAgcmVxdWVzdDogMTBNaQpwcm94eUluamVjdG9yOgogIGNhQnVuZGxlOiBwcm94eSBpbmplY3RvciBDQSBidW5kbGUKICBleHRlcm5hbFNlY3JldDogdHJ1ZQp3ZWJob29rRmFpbHVyZVBvbGljeTogV2ViaG9va0ZhaWx1cmVQb2xpY3kK
 kind: Secret
 metadata:
   creationTimestamp: null
diff --git a/cli/cmd/testdata/install_proxy_ignores.golden b/cli/cmd/testdata/install_proxy_ignores.golden
index 9b03fd192..101ba5eea 100644
--- a/cli/cmd/testdata/install_proxy_ignores.golden
+++ b/cli/cmd/testdata/install_proxy_ignores.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/cli/cmd/testdata/install_values_file.golden b/cli/cmd/testdata/install_values_file.golden
index c7ce41706..54aff46a2 100644
--- a/cli/cmd/testdata/install_values_file.golden
+++ b/cli/cmd/testdata/install_values_file.golden
@@ -623,10 +623,16 @@ data:
       accessLog: ""
       await: true
       capabilities: null
+      control:
+        streams:
+          idleTimeout: 5m
+          initialTimeout: 3s
+          lifetime: 1h
       defaultInboundPolicy: all-unauthenticated
       disableInboundProtocolDetectTimeout: false
       disableOutboundProtocolDetectTimeout: false
       enableExternalProfiles: false
+      experimentalEnv: null
       image:
         name: cr.l5d.io/linkerd/proxy
         pullPolicy: ""
@@ -936,6 +942,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1263,6 +1275,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
@@ -1689,6 +1707,12 @@ spec:
           value: all-unauthenticated
         - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS
           value: "10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT
+          value: "3s"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT
+          value: "5m"
+        - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME
+          value: "1h"
         - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT
           value: "100ms"
         - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT
diff --git a/controller/api/destination/endpoint_profile_translator_test.go b/controller/api/destination/endpoint_profile_translator_test.go
new file mode 100644
index 000000000..f15fd8baa
--- /dev/null
+++ b/controller/api/destination/endpoint_profile_translator_test.go
@@ -0,0 +1,125 @@
+package destination
+
+import (
+	"testing"
+	"time"
+
+	pb "github.com/linkerd/linkerd2-proxy-api/go/destination"
+	"github.com/linkerd/linkerd2/controller/api/destination/watcher"
+	consts "github.com/linkerd/linkerd2/pkg/k8s"
+	logging "github.com/sirupsen/logrus"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestEndpointProfileTranslator(t *testing.T) {
+	// logging.SetLevel(logging.TraceLevel)
+	// defer logging.SetLevel(logging.PanicLevel)
+
+	addr := &watcher.Address{
+		IP:   "10.10.11.11",
+		Port: 8080,
+	}
+	podAddr := &watcher.Address{
+		IP:   "10.10.11.11",
+		Port: 8080,
+		Pod: &corev1.Pod{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{
+					consts.ProxyOpaquePortsAnnotation: "8080",
+				},
+			},
+		},
+	}
+
+	t.Run("Sends update", func(t *testing.T) {
+		mockGetProfileServer := &mockDestinationGetProfileServer{
+			profilesReceived: make(chan *pb.DestinationProfile, 1),
+		}
+		log := logging.WithField("test", t.Name())
+		translator := newEndpointProfileTranslator(
+			true, "cluster", "identity", make(map[uint32]struct{}),
+			mockGetProfileServer,
+			nil,
+			log,
+		)
+		translator.Start()
+		defer translator.Stop()
+
+		if err := translator.Update(addr); err != nil {
+			t.Fatal("Expected update")
+		}
+		select {
+		case p := <-mockGetProfileServer.profilesReceived:
+			log.Debugf("Received update: %v", p)
+		case <-time.After(1 * time.Second):
+			t.Fatal("No update received")
+		}
+
+		if err := translator.Update(addr); err != nil {
+			t.Fatal("Unexpected update")
+		}
+		select {
+		case p := <-mockGetProfileServer.profilesReceived:
+			t.Fatalf("Duplicate update sent: %v", p)
+		case <-time.After(1 * time.Second):
+		}
+
+		if err := translator.Update(podAddr); err != nil {
+			t.Fatal("Expected update")
+		}
+		select {
+		case p := <-mockGetProfileServer.profilesReceived:
+			log.Debugf("Received update: %v", p)
+		case <-time.After(1 * time.Second):
+		}
+	})
+
+	t.Run("Handles overflow", func(t *testing.T) {
+		mockGetProfileServer := &mockDestinationGetProfileServer{
+			profilesReceived: make(chan *pb.DestinationProfile, 1),
+		}
+		log := logging.WithField("test", t.Name())
+		endStream := make(chan struct{})
+		translator := newEndpointProfileTranslator(
+			true, "cluster", "identity", make(map[uint32]struct{}),
+			mockGetProfileServer,
+			endStream,
+			log,
+		)
+		translator.Start()
+		defer translator.Stop()
+
+		for i := 0; i < updateQueueCapacity/2; i++ {
+			if err := translator.Update(podAddr); err != nil {
+				t.Fatal("Expected update")
+			}
+			select {
+			case <-endStream:
+				t.Fatal("Stream ended prematurely")
+			default:
+			}
+
+			if err := translator.Update(addr); err != nil {
+				t.Fatal("Expected update")
+			}
+			select {
+			case <-endStream:
+				t.Fatal("Stream ended prematurely")
+			default:
+			}
+		}
+
+		if err := translator.Update(podAddr); err == nil {
+			t.Fatal("Expected update to fail")
+		}
+		select {
+		case <-endStream:
+		default:
+			t.Fatal("Stream should have ended")
+		}
+
+		// XXX We should assert that endpointProfileUpdatesQueueOverflowCounter
+		// == 1 but we can't read counter values.
+	})
+}
diff --git a/controller/api/destination/test_util.go b/controller/api/destination/test_util.go
index 3b9f8366c..3ae6430d7 100644
--- a/controller/api/destination/test_util.go
+++ b/controller/api/destination/test_util.go
@@ -464,7 +464,7 @@ spec:
 		t.Fatalf("NewFakeMetadataAPI returned an error: %s", err)
 	}
 	log := logging.WithField("test", t.Name())
-	logging.SetLevel(logging.TraceLevel)
+	// logging.SetLevel(logging.TraceLevel)
 	defaultOpaquePorts := map[uint32]struct{}{
 		25:    {},
 		443:   {},
diff --git a/controller/proxy-injector/webhook_test.go b/controller/proxy-injector/webhook_test.go
index 1ef380b0d..3370d1fc1 100644
--- a/controller/proxy-injector/webhook_test.go
+++ b/controller/proxy-injector/webhook_test.go
@@ -2,7 +2,6 @@ package injector
 
 import (
 	"encoding/json"
-	"fmt"
 	"path/filepath"
 	"testing"
 
@@ -111,9 +110,9 @@ func TestGetPodPatch(t *testing.T) {
 			t.Fatalf("Unexpected error: %s", err)
 		}
 
-		for id, testCase := range testCases {
+		for _, testCase := range testCases {
 			testCase := testCase // pin
-			t.Run(fmt.Sprintf("%d", id), func(t *testing.T) {
+			t.Run(testCase.filename, func(t *testing.T) {
 				pod, err := factory.FileContents(testCase.filename)
 				if err != nil {
 					t.Fatalf("Unexpected error: %s", err)
@@ -139,7 +138,6 @@ func TestGetPodPatch(t *testing.T) {
 				if diff := deep.Equal(expectedPatch, actualPatch); diff != nil {
 					t.Fatalf("The actual patch didn't match what was expected.\n%+v", diff)
 				}
-
 			})
 		}
 	})
diff --git a/pkg/charts/linkerd2/values_test.go b/pkg/charts/linkerd2/values_test.go
index a6e17a7cb..3b6487c86 100644
--- a/pkg/charts/linkerd2/values_test.go
+++ b/pkg/charts/linkerd2/values_test.go
@@ -139,6 +139,13 @@ func TestNewValues(t *testing.T) {
 				InitialDelaySeconds: 0,
 				PeriodSeconds:       1,
 			},
+			Control: &ProxyControl{
+				Streams: &ProxyControlStreams{
+					InitialTimeout: "3s",
+					IdleTimeout:    "5m",
+					Lifetime:       "1h",
+				},
+			},
 		},
 		ProxyInit: &ProxyInit{
 			IptablesMode:        "legacy",
diff --git a/policy-test/Cargo.toml b/policy-test/Cargo.toml
index c75c45adc..b8505a5a3 100644
--- a/policy-test/Cargo.toml
+++ b/policy-test/Cargo.toml
@@ -10,8 +10,8 @@ anyhow = "1"
 hyper = { version = "0.14", features = ["client", "http2"] }
 futures = { version = "0.3", default-features = false }
 ipnet = "2"
-k8s-gateway-api = "0.13"
-k8s-openapi = { version = "0.19", features = ["v1_22"] }
+k8s-gateway-api = "0.15"
+k8s-openapi = { version = "0.20", features = ["v1_22"] }
 linkerd-policy-controller-core = { path = "../policy-controller/core" }
 linkerd-policy-controller-k8s-api = { path = "../policy-controller/k8s/api" }
 maplit = "1"
@@ -25,7 +25,7 @@ tracing = "0.1"
 tracing-subscriber = { version = "0.3", features = ["env-filter"] }
 
 [dependencies.kube]
-version = "0.85"
+version = "0.87.1"
 default-features = false
 features = ["client", "openssl-tls", "runtime", "ws"]
 
diff --git a/policy-test/src/grpc.rs b/policy-test/src/grpc.rs
index 843ac5572..58d7903ec 100644
--- a/policy-test/src/grpc.rs
+++ b/policy-test/src/grpc.rs
@@ -46,7 +46,7 @@ macro_rules! assert_protocol_detect {
             Some(inbound::ProxyProtocol {
                 kind: Some(inbound::proxy_protocol::Kind::Detect(
                     inbound::proxy_protocol::Detect {
-                        timeout: Some(time::Duration::from_secs(10).try_into().unwrap()),
+                        timeout: Some(std::time::Duration::from_secs(10).try_into().unwrap()),
                         http_routes: vec![
                             $crate::grpc::defaults::http_route(),
                             $crate::grpc::defaults::probe_route(),
@@ -63,8 +63,8 @@ macro_rules! assert_default_accrual_backoff {
     ($backoff:expr) => {{
         use linkerd2_proxy_api::outbound;
         let default_backoff = outbound::ExponentialBackoff {
-            min_backoff: Some(Duration::from_secs(1).try_into().unwrap()),
-            max_backoff: Some(Duration::from_secs(60).try_into().unwrap()),
+            min_backoff: Some(std::time::Duration::from_secs(1).try_into().unwrap()),
+            max_backoff: Some(std::time::Duration::from_secs(60).try_into().unwrap()),
             jitter_ratio: 0.5 as f32,
         };
         assert_eq!(&default_backoff, $backoff)
@@ -103,11 +103,24 @@ async fn connect_port_forward(
     client: &kube::Client,
     pod: &str,
 ) -> Result<impl io::AsyncRead + io::AsyncWrite + Unpin> {
-    let mut pf = kube::Api::<k8s::Pod>::namespaced(client.clone(), "linkerd")
-        .portforward(pod, &[8090])
-        .await?;
-    let io = pf.take_stream(8090).expect("must have a stream");
-    Ok(io)
+    loop {
+        let mut pf = match kube::Api::<k8s::Pod>::namespaced(client.clone(), "linkerd")
+            .portforward(pod, &[8090])
+            .await
+        {
+            Err(kube::Error::UpgradeConnection(
+                kube::client::UpgradeConnectionError::ProtocolSwitch(status),
+            )) => {
+                tracing::info!(?status, "Flakey port forward; retrying");
+                tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
+                continue;
+            }
+            res => res?,
+        };
+
+        let io = pf.take_stream(8090).expect("must have a stream");
+        return Ok(io);
+    }
 }
 
 // === impl InboundPolicyClient ===
diff --git a/policy-test/src/lib.rs b/policy-test/src/lib.rs
index 91f173a91..1ca964591 100644
--- a/policy-test/src/lib.rs
+++ b/policy-test/src/lib.rs
@@ -267,6 +267,24 @@ pub fn mk_service(ns: &str, name: &str, port: i32) -> k8s::Service {
     }
 }
 
+#[track_caller]
+pub fn assert_svc_meta(meta: &Option<grpc::meta::Metadata>, svc: &k8s::Service, port: u16) {
+    tracing::debug!(?meta, ?svc, port, "Asserting service metadata");
+    assert_eq!(
+        meta,
+        &Some(grpc::meta::Metadata {
+            kind: Some(grpc::meta::metadata::Kind::Resource(grpc::meta::Resource {
+                group: "core".to_string(),
+                kind: "Service".to_string(),
+                name: svc.name_unchecked(),
+                namespace: svc.namespace().unwrap(),
+                section: "".to_string(),
+                port: port.into()
+            })),
+        })
+    );
+}
+
 pub fn mk_route(
     ns: &str,
     name: &str,
diff --git a/policy-test/tests/outbound_api_gateway.rs b/policy-test/tests/outbound_api_gateway.rs
index 0aeafff7b..9242864d6 100644
--- a/policy-test/tests/outbound_api_gateway.rs
+++ b/policy-test/tests/outbound_api_gateway.rs
@@ -1,13 +1,13 @@
-use std::{collections::BTreeMap, time::Duration};
-
 use futures::prelude::*;
 use kube::ResourceExt;
 use linkerd_policy_controller_k8s_api as k8s;
 use linkerd_policy_test::{
-    assert_default_accrual_backoff, create, create_annotated_service, create_cluster_scoped,
-    create_opaque_service, create_service, delete_cluster_scoped, grpc, mk_service, with_temp_ns,
+    assert_default_accrual_backoff, assert_svc_meta, create, create_annotated_service,
+    create_cluster_scoped, create_opaque_service, create_service, delete_cluster_scoped, grpc,
+    mk_service, with_temp_ns,
 };
 use maplit::{btreemap, convert_args};
+use std::{collections::BTreeMap, time::Duration};
 use tokio::time;
 
 // These tests are copies of the tests in outbound_api_gateway.rs but using the
@@ -46,6 +46,8 @@ async fn service_with_no_http_routes() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -69,6 +71,8 @@ async fn service_with_http_route_without_rules() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -84,6 +88,8 @@ async fn service_with_http_route_without_rules() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with no rules.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -107,6 +113,8 @@ async fn service_with_http_routes_without_backends() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -126,6 +134,8 @@ async fn service_with_http_routes_without_backends() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with the logical backend.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -151,6 +161,8 @@ async fn service_with_http_routes_with_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -174,6 +186,8 @@ async fn service_with_http_routes_with_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend with no filters.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -201,6 +215,8 @@ async fn service_with_http_routes_with_cross_namespace_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -239,6 +255,8 @@ async fn service_with_http_routes_with_cross_namespace_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend with no filters.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -269,6 +287,8 @@ async fn service_with_http_routes_with_invalid_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -290,6 +310,8 @@ async fn service_with_http_routes_with_invalid_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -317,6 +339,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -340,6 +364,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         let _b_route = create(
             &client,
             mk_http_route(&ns, "b-route", &svc, Some(4191)).build(),
@@ -354,6 +380,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be 2 routes, returned in order.
         detect_http_routes(&config, |routes| {
             assert_eq!(routes.len(), 2);
@@ -1387,8 +1415,8 @@ fn assert_backend_matches_service(
     svc: &k8s::Service,
     port: u16,
 ) {
-    let kind = backend.backend.as_ref().unwrap().kind.as_ref().unwrap();
-    let dst = match kind {
+    let backend = backend.backend.as_ref().unwrap();
+    let dst = match backend.kind.as_ref().unwrap() {
         grpc::outbound::backend::Kind::Balancer(balance) => {
             let kind = balance.discovery.as_ref().unwrap().kind.as_ref().unwrap();
             match kind {
@@ -1409,6 +1437,8 @@ fn assert_backend_matches_service(
             port
         )
     );
+
+    assert_svc_meta(&backend.metadata, svc, port)
 }
 
 #[track_caller]
diff --git a/policy-test/tests/outbound_api_linkerd.rs b/policy-test/tests/outbound_api_linkerd.rs
index 1431b561a..36af6ca25 100644
--- a/policy-test/tests/outbound_api_linkerd.rs
+++ b/policy-test/tests/outbound_api_linkerd.rs
@@ -4,8 +4,9 @@ use futures::prelude::*;
 use kube::ResourceExt;
 use linkerd_policy_controller_k8s_api as k8s;
 use linkerd_policy_test::{
-    assert_default_accrual_backoff, create, create_annotated_service, create_cluster_scoped,
-    create_opaque_service, create_service, delete_cluster_scoped, grpc, mk_service, with_temp_ns,
+    assert_default_accrual_backoff, assert_svc_meta, create, create_annotated_service,
+    create_cluster_scoped, create_opaque_service, create_service, delete_cluster_scoped, grpc,
+    mk_service, with_temp_ns,
 };
 use maplit::{btreemap, convert_args};
 use tokio::time;
@@ -46,6 +47,8 @@ async fn service_with_no_http_routes() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -69,6 +72,8 @@ async fn service_with_http_route_without_rules() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -84,6 +89,8 @@ async fn service_with_http_route_without_rules() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with no rules.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -107,6 +114,8 @@ async fn service_with_http_routes_without_backends() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -126,6 +135,8 @@ async fn service_with_http_routes_without_backends() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with the logical backend.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -151,6 +162,8 @@ async fn service_with_http_routes_with_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -174,6 +187,8 @@ async fn service_with_http_routes_with_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend with no filters.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -201,6 +216,8 @@ async fn service_with_http_routes_with_cross_namespace_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -239,6 +256,8 @@ async fn service_with_http_routes_with_cross_namespace_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend with no filters.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -269,6 +288,8 @@ async fn service_with_http_routes_with_invalid_backend() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -290,6 +311,8 @@ async fn service_with_http_routes_with_invalid_backend() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route with a backend.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -317,6 +340,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -340,6 +365,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         let _b_route = create(
             &client,
             mk_http_route(&ns, "b-route", &svc, Some(4191)).build(),
@@ -354,6 +381,8 @@ async fn service_with_multiple_http_routes() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be 2 routes, returned in order.
         detect_http_routes(&config, |routes| {
             assert_eq!(routes.len(), 2);
@@ -405,6 +434,8 @@ async fn service_with_consecutive_failure_accrual() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         detect_failure_accrual(&config, |accrual| {
             let consecutive = failure_accrual_consecutive(accrual);
             assert_eq!(8, consecutive.max_failures);
@@ -449,6 +480,8 @@ async fn service_with_consecutive_failure_accrual_defaults() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // Expect default max_failures and default backoff
         detect_failure_accrual(&config, |accrual| {
             let consecutive = failure_accrual_consecutive(accrual);
@@ -614,6 +647,8 @@ async fn opaque_service() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // Proxy protocol should be opaque.
         match config.protocol.unwrap().kind.unwrap() {
             grpc::outbound::proxy_protocol::Kind::Opaque(_) => {}
@@ -754,6 +789,8 @@ async fn backend_with_filters() {
             .expect("watch must return an initial config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a default route.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -804,6 +841,8 @@ async fn backend_with_filters() {
             .expect("watch must return an updated config");
         tracing::trace!(?config);
 
+        assert_svc_meta(&config.metadata, &svc, 4191);
+
         // There should be a route without rule filters.
         detect_http_routes(&config, |routes| {
             let route = assert_singleton(routes);
@@ -873,6 +912,8 @@ async fn http_route_with_no_port() {
             .expect("watch must return an initial config");
         tracing::trace!(?config_4191);
 
+        assert_svc_meta(&config_4191.metadata, &svc, 4191);
+
         let mut rx_9999 = retry_watch_outbound_policy(&client, &ns, &svc, 9999).await;
         let config_9999 = rx_9999
             .next()
@@ -881,6 +922,8 @@ async fn http_route_with_no_port() {
             .expect("watch must return an initial config");
         tracing::trace!(?config_9999);
 
+        assert_svc_meta(&config_9999.metadata, &svc, 9999);
+
         // There should be a default route.
         detect_http_routes(&config_4191, |routes| {
             let route = assert_singleton(routes);
@@ -1399,8 +1442,8 @@ fn assert_backend_matches_service(
     svc: &k8s::Service,
     port: u16,
 ) {
-    let kind = backend.backend.as_ref().unwrap().kind.as_ref().unwrap();
-    let dst = match kind {
+    let backend = backend.backend.as_ref().unwrap();
+    let dst = match backend.kind.as_ref().unwrap() {
         grpc::outbound::backend::Kind::Balancer(balance) => {
             let kind = balance.discovery.as_ref().unwrap().kind.as_ref().unwrap();
             match kind {
@@ -1421,6 +1464,8 @@ fn assert_backend_matches_service(
             port
         )
     );
+
+    assert_svc_meta(&backend.metadata, svc, port)
 }
 
 #[track_caller]
diff --git a/testutil/test_data_diff.go b/testutil/test_data_diff.go
index 9e61f65d8..b3acb2dd5 100644
--- a/testutil/test_data_diff.go
+++ b/testutil/test_data_diff.go
@@ -66,6 +66,7 @@ func (td *TestDataDiffer) diffTestYAML(path, actualYAML, expectedYAML string) er
 
 // DiffTestdata generates the diff for actual w.r.the file in path
 func (td *TestDataDiffer) DiffTestdata(t *testing.T, path, actual string) {
+	t.Helper()
 	expected := ReadTestdata(path)
 	if actual == expected {
 		return
diff --git a/viz/cmd/testdata/install_default.golden b/viz/cmd/testdata/install_default.golden
index 8a61f7404..45c977391 100644
--- a/viz/cmd/testdata/install_default.golden
+++ b/viz/cmd/testdata/install_default.golden
@@ -732,7 +732,7 @@ spec:
         - --config.file=/etc/prometheus/prometheus.yml
         - --storage.tsdb.path=/data
         - --storage.tsdb.retention.time=6h
-        image: prom/prometheus:v2.48.0
+        image: prom/prometheus:v2.48.1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           httpGet:
diff --git a/viz/cmd/testdata/install_default_overrides.golden b/viz/cmd/testdata/install_default_overrides.golden
index 3dae2ddbb..8b6098b3a 100644
--- a/viz/cmd/testdata/install_default_overrides.golden
+++ b/viz/cmd/testdata/install_default_overrides.golden
@@ -732,7 +732,7 @@ spec:
         - --config.file=/etc/prometheus/prometheus.yml
         - --storage.tsdb.path=/data
         - --storage.tsdb.retention.time=6h
-        image: prom/prometheus:v2.48.0
+        image: prom/prometheus:v2.48.1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           httpGet:
diff --git a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
index c996adaf2..73cc6a799 100644
--- a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
+++ b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
@@ -732,7 +732,7 @@ spec:
         - --log.level=debug
         - --storage.tsdb.path=/data
         - --storage.tsdb.retention.time=6h
-        image: prom/prometheus:v2.48.0
+        image: prom/prometheus:v2.48.1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           httpGet:
diff --git a/viz/cmd/testdata/install_proxy_resources.golden b/viz/cmd/testdata/install_proxy_resources.golden
index c013871e4..3581b7f79 100644
--- a/viz/cmd/testdata/install_proxy_resources.golden
+++ b/viz/cmd/testdata/install_proxy_resources.golden
@@ -736,7 +736,7 @@ spec:
         - --config.file=/etc/prometheus/prometheus.yml
         - --storage.tsdb.path=/data
         - --storage.tsdb.retention.time=6h
-        image: prom/prometheus:v2.48.0
+        image: prom/prometheus:v2.48.1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           httpGet: