Repository: linkerd/linkerd2
Pull request #8625 (2022-06-07 00:51:31)

Remove grpc-over-http
For historical reasons, the linkerd-viz metrics API is served on a grpc-over-http protocol.  This was necessary when these API requests were being exposed through the kubernetes API.  Now we expose this API via a port-forward and the grpc-over-http protocol is no longer necessary.

We remove this protocol and instead have the metrics api simply serve plain gRPC.  We correspondingly update clients of this API to make regular gRPC requests.

<!--  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
-->


adleong: I had hoped to remove the

```
  # Gateways API is being deprecated in 2.12 and will be removed in 2.13
  - linters:
    - staticcheck
    text: "SA1019: .*.(GatewaysTable|GatewaysRequest|GatewaysResponse|Gateways) is deprecated: Do not use."
```

lint skip in this PR.  However, it turns out that golangci-lint produces a lint error if you even *implement* the deprecated API which is very ????????????  

Isn't the whole point of deprecating an API that the implementation of it remains while giving time to remove usages of it?  Anyway, guess we have to keep the lint skip until the API is removed entirely.

Patch:
diff --git a/.github/actions/docker-build/action.yml b/.github/actions/docker-build/action.yml
index 5207a211c..3b274095c 100644
--- a/.github/actions/docker-build/action.yml
+++ b/.github/actions/docker-build/action.yml
@@ -31,7 +31,7 @@ runs:
       echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV
       echo "DOCKER_BUILDKIT_CACHE=${{ runner.temp }}/.buildx-cache" >> $GITHUB_ENV
   - name: Cache docker layers
-    uses: actions/cache@30f413bfed0a2bc738fdfd409e5a9e96b24545fd
+    uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d
     with:
       path: ${{ env.DOCKER_BUILDKIT_CACHE }}
       key: ${{ runner.os }}-buildx-${{ inputs.component }}-${{ env.TAG }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1e709e6d0..84de00601 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -93,7 +93,7 @@ jobs:
         echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV
         echo "DOCKER_BUILDKIT_CACHE=${{ runner.temp }}/.buildx-cache" >> $GITHUB_ENV
     - name: Cache docker layers
-      uses: actions/cache@30f413bfed0a2bc738fdfd409e5a9e96b24545fd
+      uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d
       with:
         path: ${{ env.DOCKER_BUILDKIT_CACHE }}
         key: policy-controller-${{ matrix.arch }}-${{ env.TAG }}
diff --git a/go.mod b/go.mod
index 08a0c472c..4d58e3338 100644
--- a/go.mod
+++ b/go.mod
@@ -177,8 +177,9 @@ replace github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc
 // this should be removed when helm upgrades that dependency on runc
 replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.3
 
-// Addresses https://github.com/advisories/GHSA-crp2-qrr5-8pq7
-replace github.com/containerd/containerd => github.com/containerd/containerd v1.6.1
+// Addresses https://github.com/advisories/GHSA-crp2-qrr5-8pq7,
+// https://github.com/advisories/GHSA-5ffw-gxpp-mxpf
+replace github.com/containerd/containerd => github.com/containerd/containerd v1.6.6
 
 // Addresses https://github.com/advisories/GHSA-qq97-vm5h-rrhg
 replace github.com/docker/distribution => github.com/docker/distribution v2.8.1+incompatible
diff --git a/go.sum b/go.sum
index 2876368eb..ee1e81dbf 100644
--- a/go.sum
+++ b/go.sum
@@ -105,10 +105,10 @@ github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp
 github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
 github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
 github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
-github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
 github.com/Microsoft/hcsshim v0.9.1/go.mod h1:Y/0uV2jUab5kBI7SQgl62at0AVX7uaruzADAVmxm3eM=
-github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
 github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
+github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo=
+github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@@ -181,6 +181,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
 github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/clarketm/json v1.15.7 h1:zWsOtfj736/nP76KiS0HpcyO6W50ojEodx7T4LW4NMc=
@@ -209,16 +210,15 @@ github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJ
 github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
 github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
 github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
-github.com/containerd/containerd v1.6.1 h1:oa2uY0/0G+JX4X7hpGCYvkp9FjUancz56kSNnb1sG3o=
-github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
+github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
+github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
 github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
-github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
 github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
 github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
-github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
 github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
+github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34=
 github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
-github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4=
+github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo=
 github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
 github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
 github.com/containerd/stargz-snapshotter/estargz v0.10.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
@@ -231,8 +231,8 @@ github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNR
 github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
 github.com/containernetworking/cni v1.1.1 h1:ky20T7c0MvKvbMOwS/FrlbNwjEoqJEUUYfsL4b0mc4k=
 github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
-github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=
-github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
+github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -411,6 +411,7 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
 github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -602,7 +603,6 @@ github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
-github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
 github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
@@ -707,7 +707,7 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88J
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
-github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
 github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
@@ -763,6 +763,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+
 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/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
+github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb h1:YahEjAGkJtCrkqgVHhX6n8ZX+CZ3hDRL9fjLYugLfSs=
 github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
@@ -800,7 +801,6 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.2-0.20210819154149-5ad6f50d6283/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
 github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@@ -809,7 +809,7 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
 github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
-github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
+github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -843,6 +843,7 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ
 github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
 github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
@@ -889,7 +890,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
 github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
 github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -1315,6 +1315,7 @@ golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/policy-controller/grpc/src/lib.rs b/policy-controller/grpc/src/lib.rs
index 1f858b4c4..b65c64135 100644
--- a/policy-controller/grpc/src/lib.rs
+++ b/policy-controller/grpc/src/lib.rs
@@ -203,10 +203,12 @@ fn to_server(srv: &InboundServer, cluster_networks: &[IpNet]) -> proto::Server {
 
     let labels = match &srv.reference {
         ServerRef::Default(name) => convert_args!(hashmap!(
+            "group" => "",
             "kind" => "default",
             "name" => name,
         )),
         ServerRef::Server(name) => convert_args!(hashmap!(
+            "group" => "policy.linkerd.io",
             "kind" => "server",
             "name" => name,
         )),
@@ -249,14 +251,17 @@ fn to_authz(
 
     let labels = match reference {
         AuthorizationRef::Default(name) => convert_args!(hashmap!(
+            "group" => "",
             "kind" => "default",
             "name" => name,
         )),
         AuthorizationRef::ServerAuthorization(name) => convert_args!(hashmap!(
+            "group" => "policy.linkerd.io",
             "kind" => "serverauthorization",
             "name" => name,
         )),
         AuthorizationRef::AuthorizationPolicy(name) => convert_args!(hashmap!(
+            "group" => "policy.linkerd.io",
             "kind" => "authorizationpolicy",
             "name" => name,
         )),
diff --git a/viz/charts/linkerd-viz/templates/web.yaml b/viz/charts/linkerd-viz/templates/web.yaml
index e39a3e40c..21b06932a 100644
--- a/viz/charts/linkerd-viz/templates/web.yaml
+++ b/viz/charts/linkerd-viz/templates/web.yaml
@@ -89,7 +89,6 @@ spec:
         - -jaeger-addr={{.Values.jaegerUrl}}
         {{- end}}
         - -controller-namespace={{.Values.linkerdNamespace}}
-        - -viz-namespace={{.Release.Namespace}}
         - -log-level={{.Values.dashboard.logLevel | default .Values.defaultLogLevel}}
         - -log-format={{.Values.dashboard.logFormat | default .Values.defaultLogFormat}}
         {{- if .Values.dashboard.enforcedHostRegexp }}
diff --git a/viz/metrics-api/client/client.go b/viz/metrics-api/client/client.go
index 69eb7c746..3d23bdd79 100644
--- a/viz/metrics-api/client/client.go
+++ b/viz/metrics-api/client/client.go
@@ -1,159 +1,29 @@
 package client
 
 import (
-	"bufio"
-	"bytes"
 	"context"
-	"fmt"
-	"net/http"
-	"net/url"
 
 	"github.com/linkerd/linkerd2/pkg/k8s"
-	"github.com/linkerd/linkerd2/pkg/protohttp"
 	pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
-	log "github.com/sirupsen/logrus"
-	"go.opencensus.io/plugin/ochttp"
+	"go.opencensus.io/plugin/ocgrpc"
 	"google.golang.org/grpc"
-	"google.golang.org/protobuf/proto"
+	"google.golang.org/grpc/credentials/insecure"
 )
 
 const (
-	// APIRoot is the API's root path. It must be absolute (with a leading slash)
-	APIRoot = "/"
-
-	apiVersion = "v1"
-
-	// APIPrefix is the prefix all the API endpoints must share. It must be relative
-	// (without a leading slash)
-	APIPrefix = "api/" + apiVersion + "/"
-
 	apiPort       = 8085
 	apiDeployment = "metrics-api"
 )
 
-type grpcOverHTTPClient struct {
-	serverURL  *url.URL
-	httpClient *http.Client
-	namespace  string
-}
-
-func (c *grpcOverHTTPClient) StatSummary(ctx context.Context, req *pb.StatSummaryRequest, _ ...grpc.CallOption) (*pb.StatSummaryResponse, error) {
-	var msg pb.StatSummaryResponse
-	err := c.apiRequest(ctx, "StatSummary", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) Edges(ctx context.Context, req *pb.EdgesRequest, _ ...grpc.CallOption) (*pb.EdgesResponse, error) {
-	var msg pb.EdgesResponse
-	err := c.apiRequest(ctx, "Edges", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) TopRoutes(ctx context.Context, req *pb.TopRoutesRequest, _ ...grpc.CallOption) (*pb.TopRoutesResponse, error) {
-	var msg pb.TopRoutesResponse
-	err := c.apiRequest(ctx, "TopRoutes", req, &msg)
-	return &msg, err
-}
-
-// Gateways is being deprecated in 2.12 and will be removed in 2.13.
-//nolint:staticcheck
-func (c *grpcOverHTTPClient) Gateways(ctx context.Context, req *pb.GatewaysRequest, _ ...grpc.CallOption) (*pb.GatewaysResponse, error) {
-	var msg pb.GatewaysResponse
-	err := c.apiRequest(ctx, "Gateways", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) SelfCheck(ctx context.Context, req *pb.SelfCheckRequest, _ ...grpc.CallOption) (*pb.SelfCheckResponse, error) {
-	var msg pb.SelfCheckResponse
-	err := c.apiRequest(ctx, "SelfCheck", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) ListPods(ctx context.Context, req *pb.ListPodsRequest, _ ...grpc.CallOption) (*pb.ListPodsResponse, error) {
-	var msg pb.ListPodsResponse
-	err := c.apiRequest(ctx, "ListPods", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) ListServices(ctx context.Context, req *pb.ListServicesRequest, _ ...grpc.CallOption) (*pb.ListServicesResponse, error) {
-	var msg pb.ListServicesResponse
-	err := c.apiRequest(ctx, "ListServices", req, &msg)
-	return &msg, err
-}
-
-func (c *grpcOverHTTPClient) apiRequest(ctx context.Context, endpoint string, req proto.Message, protoResponse proto.Message) error {
-	url := c.endpointNameToPublicAPIURL(endpoint)
-
-	log.Debugf("Making gRPC-over-HTTP call to [%s] [%+v]", url.String(), req)
-	httpRsp, err := c.post(ctx, url, req)
-	if err != nil {
-		return err
-	}
-	defer httpRsp.Body.Close()
-	log.Debugf("gRPC-over-HTTP call returned status [%s] and content length [%d]", httpRsp.Status, httpRsp.ContentLength)
-
-	if err := protohttp.CheckIfResponseHasError(httpRsp); err != nil {
-		return err
-	}
-
-	reader := bufio.NewReader(httpRsp.Body)
-	return protohttp.FromByteStreamToProtocolBuffers(reader, protoResponse)
-}
-
-func (c *grpcOverHTTPClient) post(ctx context.Context, url *url.URL, req proto.Message) (*http.Response, error) {
-	reqBytes, err := proto.Marshal(req)
-	if err != nil {
-		return nil, err
-	}
-
-	httpReq, err := http.NewRequest(
-		http.MethodPost,
-		url.String(),
-		bytes.NewReader(reqBytes),
-	)
-	if err != nil {
-		return nil, err
-	}
-
-	rsp, err := c.httpClient.Do(httpReq.WithContext(ctx))
-	if err != nil {
-		log.Debugf("Error invoking [%s]: %v", url.String(), err)
-	} else {
-		log.Debugf("Response from [%s] had headers: %v", url.String(), rsp.Header)
-	}
-
-	return rsp, err
-}
-
-func (c *grpcOverHTTPClient) endpointNameToPublicAPIURL(endpoint string) *url.URL {
-	return c.serverURL.ResolveReference(&url.URL{Path: endpoint})
-}
-
-func newClient(apiURL *url.URL, httpClientToUse *http.Client, namespace string) (pb.ApiClient, error) {
-	if !apiURL.IsAbs() {
-		return nil, fmt.Errorf("server URL must be absolute, was [%s]", apiURL.String())
-	}
-
-	serverURL := apiURL.ResolveReference(&url.URL{Path: APIPrefix})
-
-	log.Debugf("Expecting API to be served over [%s]", serverURL)
-
-	return &grpcOverHTTPClient{
-		serverURL:  serverURL,
-		httpClient: httpClientToUse,
-		namespace:  namespace,
-	}, nil
-}
-
 // NewInternalClient creates a new Viz API client intended to run inside a
 // Kubernetes cluster.
-func NewInternalClient(namespace string, kubeAPIHost string) (pb.ApiClient, error) {
-	apiURL, err := url.Parse(fmt.Sprintf("http://%s/", kubeAPIHost))
+func NewInternalClient(addr string) (pb.ApiClient, error) {
+	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
 	if err != nil {
 		return nil, err
 	}
 
-	return newClient(apiURL, &http.Client{Transport: &ochttp.Transport{}}, namespace)
+	return pb.NewApiClient(conn), nil
 }
 
 // NewExternalClient creates a new Viz API client intended to run from
@@ -173,19 +43,15 @@ func NewExternalClient(ctx context.Context, namespace string, kubeAPI *k8s.Kuber
 		return nil, err
 	}
 
-	apiURL, err := url.Parse(portforward.URLFor(""))
-	if err != nil {
-		return nil, err
-	}
-
+	addr := portforward.AddressAndPort()
 	if err = portforward.Init(); err != nil {
 		return nil, err
 	}
 
-	httpClientToUse, err := kubeAPI.NewClient()
+	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
 	if err != nil {
 		return nil, err
 	}
 
-	return newClient(apiURL, httpClientToUse, namespace)
+	return pb.NewApiClient(conn), nil
 }
diff --git a/viz/metrics-api/cmd/main.go b/viz/metrics-api/cmd/main.go
index 8db5503e4..a9cb5bb91 100644
--- a/viz/metrics-api/cmd/main.go
+++ b/viz/metrics-api/cmd/main.go
@@ -3,6 +3,7 @@ package main
 import (
 	"context"
 	"flag"
+	"net"
 	"os"
 	"os/signal"
 	"strings"
@@ -14,6 +15,7 @@ import (
 	"github.com/linkerd/linkerd2/pkg/trace"
 	api "github.com/linkerd/linkerd2/viz/metrics-api"
 	promApi "github.com/prometheus/client_golang/api"
+	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -64,9 +66,13 @@ func main() {
 		}
 	}
 
-	server := api.NewServer(
-		*addr,
-		prometheusClient,
+	var promAPI promv1.API
+	if prometheusClient != nil {
+		promAPI = promv1.NewAPI(prometheusClient)
+	}
+
+	server := api.NewGrpcServer(
+		promAPI,
 		k8sAPI,
 		*controllerNamespace,
 		*clusterDomain,
@@ -75,9 +81,14 @@ func main() {
 
 	k8sAPI.Sync(nil) // blocks until caches are synced
 
+	lis, err := net.Listen("tcp", *addr)
+	if err != nil {
+		log.Fatalf("Failed to listen on %s: %s", *addr, err)
+	}
 	go func() {
 		log.Infof("starting HTTP server on %+v", *addr)
-		if err := server.ListenAndServe(); err != nil {
+
+		if err := server.Serve(lis); err != nil {
 			log.Errorf("failed to start metrics API HTTP server: %s", err)
 		}
 	}()
@@ -94,6 +105,6 @@ func main() {
 	<-stop
 
 	log.Infof("shutting down HTTP server on %+v", *addr)
-	server.Shutdown(ctx)
+	server.GracefulStop()
 	adminServer.Shutdown(ctx)
 }
diff --git a/viz/metrics-api/grpc_server.go b/viz/metrics-api/grpc_server.go
index 66ce75596..60733ae15 100644
--- a/viz/metrics-api/grpc_server.go
+++ b/viz/metrics-api/grpc_server.go
@@ -14,6 +14,7 @@ import (
 	"github.com/linkerd/linkerd2/viz/metrics-api/util"
 	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/labels"
 )
@@ -45,15 +46,17 @@ const (
 	promClientCheckDescription = "linkerd viz can talk to Prometheus"
 )
 
-func newGrpcServer(
+// NewGrpcServer creates a new instance of the Api server and registers it
+// with Prometheus.
+func NewGrpcServer(
 	promAPI promv1.API,
 	k8sAPI *k8s.API,
 	controllerNamespace string,
 	clusterDomain string,
 	ignoredNamespaces []string,
-) *grpcServer {
+) *grpc.Server {
 
-	grpcServer := &grpcServer{
+	server := &grpcServer{
 		prometheusAPI:       promAPI,
 		k8sAPI:              k8sAPI,
 		controllerNamespace: controllerNamespace,
@@ -61,9 +64,11 @@ func newGrpcServer(
 		ignoredNamespaces:   ignoredNamespaces,
 	}
 
-	pb.RegisterApiServer(prometheus.NewGrpcServer(), grpcServer)
+	pb.RegisterApiServer(prometheus.NewGrpcServer(), server)
+	s := prometheus.NewGrpcServer()
+	pb.RegisterApiServer(s, server)
 
-	return grpcServer
+	return s
 }
 
 func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb.ListPodsResponse, error) {
diff --git a/viz/metrics-api/http_server.go b/viz/metrics-api/http_server.go
deleted file mode 100644
index 4d6f95be5..000000000
--- a/viz/metrics-api/http_server.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package api
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/linkerd/linkerd2/controller/k8s"
-	"github.com/linkerd/linkerd2/pkg/prometheus"
-	"github.com/linkerd/linkerd2/pkg/protohttp"
-	"github.com/linkerd/linkerd2/viz/metrics-api/client"
-	pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
-	promApi "github.com/prometheus/client_golang/api"
-	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
-	log "github.com/sirupsen/logrus"
-)
-
-var (
-	gatewaysPath     = fullURLPathFor("Gateways")
-	statSummaryPath  = fullURLPathFor("StatSummary")
-	topRoutesPath    = fullURLPathFor("TopRoutes")
-	listPodsPath     = fullURLPathFor("ListPods")
-	listServicesPath = fullURLPathFor("ListServices")
-	selfCheckPath    = fullURLPathFor("SelfCheck")
-	edgesPath        = fullURLPathFor("Edges")
-)
-
-type handler struct {
-	grpcServer Server
-}
-
-func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	log.Debugf("Serving %s %q", req.Method, req.URL.Path)
-
-	// Validate request method
-	if req.Method != http.MethodPost {
-		protohttp.WriteErrorToHTTPResponse(w, fmt.Errorf("POST required"))
-		return
-	}
-
-	// Serve request
-	switch req.URL.Path {
-	case gatewaysPath:
-		h.handleGateways(w, req)
-	case statSummaryPath:
-		h.handleStatSummary(w, req)
-	case topRoutesPath:
-		h.handleTopRoutes(w, req)
-	case listPodsPath:
-		h.handleListPods(w, req)
-	case listServicesPath:
-		h.handleListServices(w, req)
-	case selfCheckPath:
-		h.handleSelfCheck(w, req)
-	case edgesPath:
-		h.handleEdges(w, req)
-	default:
-		http.NotFound(w, req)
-	}
-
-}
-
-func (h *handler) handleGateways(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.GatewaysRequest
-
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.Gateways(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleStatSummary(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.StatSummaryRequest
-
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.StatSummary(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleEdges(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.EdgesRequest
-
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.Edges(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleTopRoutes(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.TopRoutesRequest
-
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.TopRoutes(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleSelfCheck(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.SelfCheckRequest
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.SelfCheck(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleListPods(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.ListPodsRequest
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.ListPods(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func (h *handler) handleListServices(w http.ResponseWriter, req *http.Request) {
-	var protoRequest pb.ListServicesRequest
-
-	err := protohttp.HTTPRequestToProto(req, &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	rsp, err := h.grpcServer.ListServices(req.Context(), &protoRequest)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-
-	err = protohttp.WriteProtoToHTTPResponse(w, rsp)
-	if err != nil {
-		protohttp.WriteErrorToHTTPResponse(w, err)
-		return
-	}
-}
-
-func fullURLPathFor(method string) string {
-	return client.APIRoot + client.APIPrefix + method
-}
-
-// NewServer creates a Public API HTTP server.
-func NewServer(
-	addr string,
-	prometheusClient promApi.Client,
-	k8sAPI *k8s.API,
-	controllerNamespace string,
-	clusterDomain string,
-	ignoredNamespaces []string,
-) *http.Server {
-
-	var promAPI promv1.API
-	if prometheusClient != nil {
-		promAPI = promv1.NewAPI(prometheusClient)
-	}
-
-	grpcServer := newGrpcServer(
-		promAPI,
-		k8sAPI,
-		controllerNamespace,
-		clusterDomain,
-		ignoredNamespaces,
-	)
-	baseHandler := &handler{
-		grpcServer: grpcServer,
-	}
-
-	instrumentedHandler := prometheus.WithTelemetry(baseHandler)
-
-	return &http.Server{
-		Addr:    addr,
-		Handler: instrumentedHandler,
-	}
-}
diff --git a/web/main.go b/web/main.go
index 41710c627..281165878 100644
--- a/web/main.go
+++ b/web/main.go
@@ -37,7 +37,6 @@ func main() {
 	staticDir := cmd.String("static-dir", "app/dist", "directory to search for static files")
 	reload := cmd.Bool("reload", true, "reloading set to true or false")
 	controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed")
-	vizNamespace := cmd.String("viz-namespace", "linkerd", "namespace in which Linkerd viz is installed")
 	enforcedHost := cmd.String("enforced-host", "", "regexp describing the allowed values for the Host header; protects from DNS-rebinding attacks")
 	kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config")
 	clusterDomain := cmd.String("cluster-domain", "", "kubernetes cluster domain")
@@ -52,7 +51,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("failed to parse metrics API server address: %s", *vizAPIAddr)
 	}
-	client, err := client.NewInternalClient(*vizNamespace, *vizAPIAddr)
+	client, err := client.NewInternalClient(*vizAPIAddr)
 	if err != nil {
 		log.Fatalf("failed to construct client for viz API server URL %s", *vizAPIAddr)
 	}


Test patch:
diff --git a/policy-test/src/grpc.rs b/policy-test/src/grpc.rs
index 0ec072717..2082e4425 100644
--- a/policy-test/src/grpc.rs
+++ b/policy-test/src/grpc.rs
@@ -15,6 +15,7 @@ macro_rules! assert_is_default_all_unauthenticated {
         assert_eq!(
             $config.labels,
             vec![
+                ("group".to_string(), "".to_string()),
                 ("kind".to_string(), "default".to_string()),
                 ("name".to_string(), "all-unauthenticated".to_string()),
             ]
diff --git a/policy-test/tests/api.rs b/policy-test/tests/api.rs
index 2560ce605..c57689760 100644
--- a/policy-test/tests/api.rs
+++ b/policy-test/tests/api.rs
@@ -56,7 +56,11 @@ async fn server_with_server_authorization() {
         assert_eq!(config.authorizations, vec![]);
         assert_eq!(
             config.labels,
-            convert_args!(hashmap!("kind" => "server", "name" => "linkerd-admin")),
+            convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
+                "kind" => "server",
+                "name" => "linkerd-admin"
+            )),
         );
 
         // Create a server authorizaation that refers to the `linkerd-admin`
@@ -100,6 +104,7 @@ async fn server_with_server_authorization() {
         assert_eq!(
             config.authorizations.first().unwrap().labels,
             convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
                 "kind" => "serverauthorization",
                 "name" => "all-admin",
             )),
@@ -120,7 +125,11 @@ async fn server_with_server_authorization() {
         );
         assert_eq!(
             config.labels,
-            convert_args!(hashmap!("kind" => "server", "name" => server.name()))
+            convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
+                "kind" => "server",
+                "name" => server.name()
+            ))
         );
 
         // Delete the `Server` and ensure that the update reverts to the
@@ -188,7 +197,11 @@ async fn server_with_authorization_policy() {
         assert_eq!(config.authorizations, vec![]);
         assert_eq!(
             config.labels,
-            convert_args!(hashmap!("kind" => "server", "name" => server.name()))
+            convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
+                "kind" => "server",
+                "name" => server.name()
+            ))
         );
 
         let all_nets = create(
@@ -251,6 +264,7 @@ async fn server_with_authorization_policy() {
         assert_eq!(
             config.authorizations.first().unwrap().labels,
             convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
                 "kind" => "authorizationpolicy",
                 "name" => authz_policy.name(),
             ))
@@ -271,7 +285,11 @@ async fn server_with_authorization_policy() {
         );
         assert_eq!(
             config.labels,
-            convert_args!(hashmap!("kind" => "server", "name" => server.name()))
+            convert_args!(hashmap!(
+                "group" => "policy.linkerd.io",
+                "kind" => "server",
+                "name" => server.name()
+            ))
         );
     })
     .await;
diff --git a/viz/cmd/testdata/install_default.golden b/viz/cmd/testdata/install_default.golden
index 6d62df1d0..12ab3aa35 100644
--- a/viz/cmd/testdata/install_default.golden
+++ b/viz/cmd/testdata/install_default.golden
@@ -1248,7 +1248,6 @@ spec:
         - -linkerd-metrics-api-addr=metrics-api.linkerd-viz.svc.cluster.local:8085
         - -cluster-domain=cluster.local
         - -controller-namespace=linkerd
-        - -viz-namespace=linkerd-viz
         - -log-level=info
         - -log-format=plain
         - -enforced-host=^(localhost|127\.0\.0\.1|web\.linkerd-viz\.svc\.cluster\.local|web\.linkerd-viz\.svc|\[::1\])(:\d+)?$
diff --git a/viz/cmd/testdata/install_default_overrides.golden b/viz/cmd/testdata/install_default_overrides.golden
index 1ac98b72c..f61d42b0e 100644
--- a/viz/cmd/testdata/install_default_overrides.golden
+++ b/viz/cmd/testdata/install_default_overrides.golden
@@ -1249,7 +1249,6 @@ spec:
         - -cluster-domain=cluster.local
         - -grafana-addr=grafana.grafana:3000
         - -controller-namespace=linkerd
-        - -viz-namespace=linkerd-viz
         - -log-level=debug
         - -log-format=plain
         - -enforced-host=^(localhost|127\.0\.0\.1|web\.linkerd-viz\.svc\.cluster\.local|web\.linkerd-viz\.svc|\[::1\])(:\d+)?$
diff --git a/viz/cmd/testdata/install_prometheus_disabled.golden b/viz/cmd/testdata/install_prometheus_disabled.golden
index 20c18dbb0..c84104297 100644
--- a/viz/cmd/testdata/install_prometheus_disabled.golden
+++ b/viz/cmd/testdata/install_prometheus_disabled.golden
@@ -967,7 +967,6 @@ spec:
         - -linkerd-metrics-api-addr=metrics-api.linkerd-viz.svc.cluster.local:8085
         - -cluster-domain=cluster.local
         - -controller-namespace=linkerd
-        - -viz-namespace=linkerd-viz
         - -log-level=info
         - -log-format=plain
         - -enforced-host=^(localhost|127\.0\.0\.1|web\.linkerd-viz\.svc\.cluster\.local|web\.linkerd-viz\.svc|\[::1\])(:\d+)?$
diff --git a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
index 0225542bc..199e2e4b9 100644
--- a/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
+++ b/viz/cmd/testdata/install_prometheus_loglevel_from_args.golden
@@ -1248,7 +1248,6 @@ spec:
         - -linkerd-metrics-api-addr=metrics-api.linkerd-viz.svc.cluster.local:8085
         - -cluster-domain=cluster.local
         - -controller-namespace=linkerd
-        - -viz-namespace=linkerd-viz
         - -log-level=info
         - -log-format=plain
         - -enforced-host=^(localhost|127\.0\.0\.1|web\.linkerd-viz\.svc\.cluster\.local|web\.linkerd-viz\.svc|\[::1\])(:\d+)?$
diff --git a/viz/cmd/testdata/install_proxy_resources.golden b/viz/cmd/testdata/install_proxy_resources.golden
index eb33bf41f..3868a0da8 100644
--- a/viz/cmd/testdata/install_proxy_resources.golden
+++ b/viz/cmd/testdata/install_proxy_resources.golden
@@ -1260,7 +1260,6 @@ spec:
         - -linkerd-metrics-api-addr=metrics-api.linkerd-viz.svc.cluster.local:8085
         - -cluster-domain=cluster.local
         - -controller-namespace=linkerd
-        - -viz-namespace=linkerd-viz
         - -log-level=info
         - -log-format=plain
         - -enforced-host=^(localhost|127\.0\.0\.1|web\.linkerd-viz\.svc\.cluster\.local|web\.linkerd-viz\.svc|\[::1\])(:\d+)?$
diff --git a/viz/metrics-api/grpc_server_test.go b/viz/metrics-api/grpc_server_test.go
index ee886fdba..2153c113d 100644
--- a/viz/metrics-api/grpc_server_test.go
+++ b/viz/metrics-api/grpc_server_test.go
@@ -379,13 +379,13 @@ status:
 
 			mProm := prometheus.MockProm{Res: exp.promRes}
 
-			fakeGrpcServer := newGrpcServer(
-				&mProm,
-				k8sAPI,
-				"linkerd",
-				"mycluster.local",
-				[]string{},
-			)
+			fakeGrpcServer := grpcServer{
+				prometheusAPI:       &mProm,
+				k8sAPI:              k8sAPI,
+				controllerNamespace: "linkerd",
+				clusterDomain:       "mycluster.local",
+				ignoredNamespaces:   []string{},
+			}
 
 			k8sAPI.Sync(nil)
 
@@ -480,13 +480,13 @@ metadata:
 				t.Fatalf("NewFakeAPI returned an error: %s", err)
 			}
 
-			fakeGrpcServer := newGrpcServer(
-				&prometheus.MockProm{},
-				k8sAPI,
-				"linkerd",
-				"mycluster.local",
-				[]string{},
-			)
+			fakeGrpcServer := grpcServer{
+				prometheusAPI:       &prometheus.MockProm{},
+				k8sAPI:              k8sAPI,
+				controllerNamespace: "linkerd",
+				clusterDomain:       "mycluster.local",
+				ignoredNamespaces:   []string{},
+			}
 
 			k8sAPI.Sync(nil)
 
diff --git a/viz/metrics-api/http_server_test.go b/viz/metrics-api/http_server_test.go
deleted file mode 100644
index 8953aebee..000000000
--- a/viz/metrics-api/http_server_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package api
-
-import (
-	"context"
-	"errors"
-	"net"
-	"net/http"
-	"testing"
-
-	vizClient "github.com/linkerd/linkerd2/viz/metrics-api/client"
-	pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
-	"google.golang.org/protobuf/proto"
-)
-
-type mockServer struct {
-	LastRequestReceived proto.Message
-	ResponseToReturn    proto.Message
-	ErrorToReturn       error
-}
-
-type mockGrpcServer struct {
-	pb.UnimplementedApiServer
-	mockServer
-}
-
-func (m *mockGrpcServer) StatSummary(ctx context.Context, req *pb.StatSummaryRequest) (*pb.StatSummaryResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.StatSummaryResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) Gateways(ctx context.Context, req *pb.GatewaysRequest) (*pb.GatewaysResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.GatewaysResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) TopRoutes(ctx context.Context, req *pb.TopRoutesRequest) (*pb.TopRoutesResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.TopRoutesResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) Edges(ctx context.Context, req *pb.EdgesRequest) (*pb.EdgesResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.EdgesResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb.ListPodsResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.ListPodsResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) ListServices(ctx context.Context, req *pb.ListServicesRequest) (*pb.ListServicesResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.ListServicesResponse), m.ErrorToReturn
-}
-
-func (m *mockGrpcServer) SelfCheck(ctx context.Context, req *pb.SelfCheckRequest) (*pb.SelfCheckResponse, error) {
-	m.LastRequestReceived = req
-	return m.ResponseToReturn.(*pb.SelfCheckResponse), m.ErrorToReturn
-}
-
-type grpcCallTestCase struct {
-	expectedRequest  proto.Message
-	expectedResponse proto.Message
-	functionCall     func() (proto.Message, error)
-}
-
-func TestServer(t *testing.T) {
-	t.Run("Delegates all non-streaming RPC messages to the underlying grpc server", func(t *testing.T) {
-		mockGrpcServer, client := getServerVizClient(t)
-
-		listPodsReq := &pb.ListPodsRequest{}
-		testListPods := grpcCallTestCase{
-			expectedRequest: listPodsReq,
-			expectedResponse: &pb.ListPodsResponse{
-				Pods: []*pb.Pod{
-					{Status: "ok-ish"},
-				},
-			},
-			functionCall: func() (proto.Message, error) { return client.ListPods(context.TODO(), listPodsReq) },
-		}
-
-		statSummaryReq := &pb.StatSummaryRequest{}
-		testStatSummary := grpcCallTestCase{
-			expectedRequest:  statSummaryReq,
-			expectedResponse: &pb.StatSummaryResponse{},
-			functionCall:     func() (proto.Message, error) { return client.StatSummary(context.TODO(), statSummaryReq) },
-		}
-
-		for _, testCase := range []grpcCallTestCase{testListPods, testStatSummary} {
-			assertCallWasForwarded(t, &mockGrpcServer.mockServer, testCase.expectedRequest, testCase.expectedResponse, testCase.functionCall)
-		}
-	})
-}
-
-func getServerVizClient(t *testing.T) (*mockGrpcServer, pb.ApiClient) {
-	mockGrpcServer := &mockGrpcServer{}
-
-	listener, err := net.Listen("tcp", "localhost:0")
-	if err != nil {
-		t.Fatalf("Could not start listener: %v", err)
-	}
-
-	go func() {
-		handler := &handler{
-			grpcServer: mockGrpcServer,
-		}
-		err := http.Serve(listener, handler)
-		if err != nil {
-			t.Errorf("Could not start server: %v", err)
-			return
-		}
-	}()
-
-	client, err := vizClient.NewInternalClient("linkerd", listener.Addr().String())
-	if err != nil {
-		t.Fatalf("Unexpected error: %v", err)
-	}
-
-	return mockGrpcServer, client
-}
-
-func assertCallWasForwarded(t *testing.T, mockServer *mockServer, expectedRequest proto.Message, expectedResponse proto.Message, functionCall func() (proto.Message, error)) {
-	mockServer.ErrorToReturn = nil
-	mockServer.ResponseToReturn = expectedResponse
-	actualResponse, err := functionCall()
-	if err != nil {
-		t.Fatalf("Unexpected error: %v", err)
-	}
-	actualRequest := mockServer.LastRequestReceived
-	if !proto.Equal(actualRequest, expectedRequest) {
-		t.Fatalf("Expecting server call to return [%v], but got [%v]", expectedRequest, actualRequest)
-	}
-	if !proto.Equal(actualResponse, expectedResponse) {
-		t.Fatalf("Expecting server call to return [%v], but got [%v]", expectedResponse, actualResponse)
-	}
-
-	mockServer.ErrorToReturn = errors.New("expected")
-	_, err = functionCall()
-	if err == nil {
-		t.Fatalf("Expecting error, got nothing")
-	}
-}
diff --git a/viz/metrics-api/stat_summary_test.go b/viz/metrics-api/stat_summary_test.go
index 78908b93b..b689362ec 100644
--- a/viz/metrics-api/stat_summary_test.go
+++ b/viz/metrics-api/stat_summary_test.go
@@ -1382,13 +1382,13 @@ status:
 		}
 
 		for _, exp := range expectations {
-			fakeGrpcServer := newGrpcServer(
-				&prometheus.MockProm{Res: exp.mockPromResponse},
-				k8sAPI,
-				"linkerd",
-				"mycluster.local",
-				[]string{},
-			)
+			fakeGrpcServer := grpcServer{
+				prometheusAPI:       &prometheus.MockProm{Res: exp.mockPromResponse},
+				k8sAPI:              k8sAPI,
+				controllerNamespace: "linkerd",
+				clusterDomain:       "mycluster.local",
+				ignoredNamespaces:   []string{},
+			}
 
 			_, err := fakeGrpcServer.StatSummary(context.TODO(), exp.req)
 			if err != nil || exp.err != nil {
@@ -1406,13 +1406,13 @@ status:
 		if err != nil {
 			t.Fatalf("NewFakeAPI returned an error: %s", err)
 		}
-		fakeGrpcServer := newGrpcServer(
-			&prometheus.MockProm{Res: model.Vector{}},
-			k8sAPI,
-			"linkerd",
-			"mycluster.local",
-			[]string{},
-		)
+		fakeGrpcServer := grpcServer{
+			prometheusAPI:       &prometheus.MockProm{Res: model.Vector{}},
+			k8sAPI:              k8sAPI,
+			controllerNamespace: "linkerd",
+			clusterDomain:       "mycluster.local",
+			ignoredNamespaces:   []string{},
+		}
 
 		invalidRequests := []statSumExpected{
 			{
diff --git a/viz/metrics-api/test_helper.go b/viz/metrics-api/test_helper.go
index b8357a800..d8b0a6732 100644
--- a/viz/metrics-api/test_helper.go
+++ b/viz/metrics-api/test_helper.go
@@ -304,13 +304,13 @@ func newMockGrpcServer(exp expectedStatRPC) (*prometheus.MockProm, *grpcServer,
 	}
 
 	mockProm := &prometheus.MockProm{Res: exp.mockPromResponse}
-	fakeGrpcServer := newGrpcServer(
-		mockProm,
-		k8sAPI,
-		"linkerd",
-		"cluster.local",
-		[]string{},
-	)
+	fakeGrpcServer := &grpcServer{
+		prometheusAPI:       mockProm,
+		k8sAPI:              k8sAPI,
+		controllerNamespace: "linkerd",
+		clusterDomain:       "cluster.local",
+		ignoredNamespaces:   []string{},
+	}
 
 	k8sAPI.Sync(nil)