Repository: kumahq/kuma
Pull request #2427 (2021-07-26 06:10:15)

chore(*) fix information log output message format (backport #2415)
This is an automatic backport of pull request #2415 done by [Mergify](https://mergify.io).


---


<details>
<summary>Mergify commands and options</summary>

<br />

More conditions and actions can be found in the [documentation](https://docs.mergify.io/).

You can also trigger Mergify actions by commenting on this pull request:

- `@Mergifyio refresh` will re-evaluate the rules
- `@Mergifyio rebase` will rebase this PR on its base branch
- `@Mergifyio update` will merge the base branch into this PR
- `@Mergifyio backport <destination>` will backport this PR on `<destination>` branch

Additionally, on Mergify [dashboard](https://dashboard.mergify.io/) you can:

- look at your merge queues
- generate the Mergify configuration with the config editor.

Finally, you can contact us on https://mergify.io/
</details>



Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 7f521a536..c4eb28722 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -36,3 +36,6 @@ issues:
     - linters:
         - staticcheck
       text: "SA1019: l.UseOriginalDst is deprecated: Do not use." # TODO What is the up-to-date alternative ?
+    - linters:
+        - staticcheck
+      text: "IsIngress is deprecated: use ZoneIngress" # It's deprecated but Kuma still needs to support it for backwards compatibility.
diff --git a/api/go.mod b/api/go.mod
deleted file mode 100644
index 062f3512b..000000000
--- a/api/go.mod
+++ /dev/null
@@ -1,22 +0,0 @@
-module github.com/kumahq/kuma/api
-
-go 1.16
-
-require (
-	github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d
-	github.com/envoyproxy/protoc-gen-validate v0.4.1
-	github.com/ghodss/yaml v1.0.0
-	github.com/golang/protobuf v1.5.2
-	github.com/kumahq/protoc-gen-kumadoc v0.1.7
-	github.com/onsi/ginkgo v1.16.2
-	github.com/onsi/gomega v1.13.0
-	github.com/pkg/errors v0.9.1
-	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
-	google.golang.org/grpc v1.38.0
-	google.golang.org/protobuf v1.27.0
-// When running `make generate` in this folder, one can get into errors of missing proto dependecies
-// To solve the issue, uncomment the section below and run `go mod download`
-//github.com/cncf/udpa latest
-//github.com/envoyproxy/data-plane-api latest
-//github.com/googleapis/googleapis latest
-)
diff --git a/api/go.sum b/api/go.sum
deleted file mode 100644
index 5c6f5dfc2..000000000
--- a/api/go.sum
+++ /dev/null
@@ -1,185 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
-github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
-github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v0.4.1 h1:7dLaJvASGRD7X49jSCSXXHwKPm0ZN9r9kJD+p+vS7dM=
-github.com/envoyproxy/protoc-gen-validate v0.4.1/go.mod h1:E+IEazqdaWv3FrnGtZIu3b9fPFMK8AzeTTrk9SfVwWs=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
-github.com/kumahq/protoc-gen-kumadoc v0.1.7 h1:WgwGa7QgVbj2QVzRU5hQaMxSJ29WppDHVczo3FUIc84=
-github.com/kumahq/protoc-gen-kumadoc v0.1.7/go.mod h1:F+c9RjgKlv1Q3UEoPJCtMJw8Fd+X5PfG5jlkTSfZOMA=
-github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
-github.com/lyft/protoc-gen-star v0.5.2/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
-github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4=
-github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
-github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.16.2 h1:HFB2fbVIlhIfCfOW81bZFbiC/RvnpXSdhbF2/DJr134=
-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
-github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-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.27.0 h1:KhgSLlr/moiqjv0qUsSnLvdUL7NH7PHW8aZGn7Jpjko=
-google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/api/mesh/v1alpha1/dataplane.pb.go b/api/mesh/v1alpha1/dataplane.pb.go
index 7a9ecce8a..62bb45230 100644
--- a/api/mesh/v1alpha1/dataplane.pb.go
+++ b/api/mesh/v1alpha1/dataplane.pb.go
@@ -24,6 +24,56 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+type Dataplane_Networking_Gateway_GatewayType int32
+
+const (
+	// A DELEGATED gateway is a independently deployed proxy that
+	// receives inbound traffic that is not proxied by Kuma, and
+	// sends outbound traffic into the Kuma dataplane proxy.
+	Dataplane_Networking_Gateway_DELEGATED Dataplane_Networking_Gateway_GatewayType = 0
+	// The BUILTIN gateway type is experimental and unsupported.
+	Dataplane_Networking_Gateway_BUILTIN Dataplane_Networking_Gateway_GatewayType = 1
+)
+
+// Enum value maps for Dataplane_Networking_Gateway_GatewayType.
+var (
+	Dataplane_Networking_Gateway_GatewayType_name = map[int32]string{
+		0: "DELEGATED",
+		1: "BUILTIN",
+	}
+	Dataplane_Networking_Gateway_GatewayType_value = map[string]int32{
+		"DELEGATED": 0,
+		"BUILTIN":   1,
+	}
+)
+
+func (x Dataplane_Networking_Gateway_GatewayType) Enum() *Dataplane_Networking_Gateway_GatewayType {
+	p := new(Dataplane_Networking_Gateway_GatewayType)
+	*p = x
+	return p
+}
+
+func (x Dataplane_Networking_Gateway_GatewayType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Dataplane_Networking_Gateway_GatewayType) Descriptor() protoreflect.EnumDescriptor {
+	return file_mesh_v1alpha1_dataplane_proto_enumTypes[0].Descriptor()
+}
+
+func (Dataplane_Networking_Gateway_GatewayType) Type() protoreflect.EnumType {
+	return &file_mesh_v1alpha1_dataplane_proto_enumTypes[0]
+}
+
+func (x Dataplane_Networking_Gateway_GatewayType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Dataplane_Networking_Gateway_GatewayType.Descriptor instead.
+func (Dataplane_Networking_Gateway_GatewayType) EnumDescriptor() ([]byte, []int) {
+	return file_mesh_v1alpha1_dataplane_proto_rawDescGZIP(), []int{0, 0, 3, 0}
+}
+
 // Dataplane defines configuration of a side-car proxy.
 type Dataplane struct {
 	state         protoimpl.MessageState
@@ -532,6 +582,10 @@ type Dataplane_Networking_Gateway struct {
 	// dataplane is deployed next to, e.g. service=gateway, env=prod.
 	// `service` tag is mandatory.
 	Tags map[string]string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// Type of gateway this dataplane manages. The default is a DELEGATED
+	// gateway, which is an external proxy. The BUILTIN gateway type causes
+	// the dataplane proxy itself to be configured as a gateway.
+	Type Dataplane_Networking_Gateway_GatewayType `protobuf:"varint,2,opt,name=type,proto3,enum=kuma.mesh.v1alpha1.Dataplane_Networking_Gateway_GatewayType" json:"type,omitempty"`
 }
 
 func (x *Dataplane_Networking_Gateway) Reset() {
@@ -573,6 +627,13 @@ func (x *Dataplane_Networking_Gateway) GetTags() map[string]string {
 	return nil
 }
 
+func (x *Dataplane_Networking_Gateway) GetType() Dataplane_Networking_Gateway_GatewayType {
+	if x != nil {
+		return x.Type
+	}
+	return Dataplane_Networking_Gateway_DELEGATED
+}
+
 // TransparentProxying describes configuration for transparent proxying.
 type Dataplane_Networking_TransparentProxying struct {
 	state         protoimpl.MessageState
@@ -968,7 +1029,7 @@ var file_mesh_v1alpha1_dataplane_proto_rawDesc = []byte{
 	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76,
-	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf3, 0x16,
+	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf0, 0x17,
 	0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x12, 0x48, 0x0a, 0x0a, 0x6e,
 	0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
 	0x28, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
@@ -982,7 +1043,7 @@ var file_mesh_v1alpha1_dataplane_proto_rawDesc = []byte{
 	0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e,
 	0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61,
 	0x6e, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x73, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x62, 0x65,
-	0x73, 0x1a, 0x95, 0x13, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67,
+	0x73, 0x1a, 0x92, 0x14, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67,
 	0x12, 0x4a, 0x0a, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
 	0x0b, 0x32, 0x30, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31,
 	0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65,
@@ -1108,54 +1169,62 @@ var file_mesh_v1alpha1_dataplane_proto_rawDesc = []byte{
 	0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
 	0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
 	0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
-	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x9c, 0x01, 0x0a, 0x07, 0x47, 0x61, 0x74,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x99, 0x02, 0x0a, 0x07, 0x47, 0x61, 0x74,
 	0x65, 0x77, 0x61, 0x79, 0x12, 0x58, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03,
 	0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76,
 	0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e,
 	0x65, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x61, 0x74,
 	0x65, 0x77, 0x61, 0x79, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x08,
-	0xfa, 0x42, 0x05, 0x9a, 0x01, 0x02, 0x08, 0x01, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x37,
-	0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
-	0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
-	0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x8f, 0x02, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e,
-	0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x69, 0x6e, 0x67, 0x12,
-	0x3d, 0x0a, 0x15, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74,
-	0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09,
-	0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72,
-	0x65, 0x63, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3f,
-	0x0a, 0x16, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f,
-	0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09,
-	0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x14, 0x72, 0x65, 0x64, 0x69, 0x72,
-	0x65, 0x63, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12,
-	0x34, 0x0a, 0x16, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73,
-	0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
-	0x14, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72,
-	0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x18, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63,
-	0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x76,
-	0x36, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0xff,
-	0xff, 0x03, 0x52, 0x15, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x50, 0x6f, 0x72, 0x74,
-	0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x36, 0x1a, 0xcf, 0x01, 0x0a, 0x06, 0x50, 0x72,
-	0x6f, 0x62, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x4b, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70,
-	0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6b, 0x75,
-	0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
-	0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65,
-	0x73, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70,
-	0x6f, 0x69, 0x6e, 0x74, 0x73, 0x1a, 0x64, 0x0a, 0x08, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
-	0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72,
-	0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
-	0x50, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f,
-	0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f,
-	0x75, 0x6e, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x3a, 0x36, 0xaa, 0x8c, 0x89,
-	0xa6, 0x01, 0x13, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x52, 0x65,
-	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x0b, 0x12, 0x09, 0x44, 0x61,
-	0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x06, 0x22, 0x04, 0x6d,
-	0x65, 0x73, 0x68, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
-	0x6d, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x68, 0x71, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70,
-	0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0xfa, 0x42, 0x05, 0x9a, 0x01, 0x02, 0x08, 0x01, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x50,
+	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x6b,
+	0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
+	0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x77,
+	0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x47,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0b, 0x47, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x45, 0x4c, 0x45,
+	0x47, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x55, 0x49, 0x4c, 0x54,
+	0x49, 0x4e, 0x10, 0x01, 0x1a, 0x8f, 0x02, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61,
+	0x72, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x69, 0x6e, 0x67, 0x12, 0x3d, 0x0a, 0x15,
+	0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e,
+	0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06,
+	0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x13, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
+	0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3f, 0x0a, 0x16, 0x72,
+	0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x75, 0x74,
+	0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06,
+	0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x14, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
+	0x50, 0x6f, 0x72, 0x74, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x34, 0x0a, 0x16,
+	0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x64, 0x69,
+	0x72, 0x65, 0x63, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+	0x65, 0x73, 0x12, 0x42, 0x0a, 0x18, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70,
+	0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x76, 0x36, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52,
+	0x15, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x62,
+	0x6f, 0x75, 0x6e, 0x64, 0x56, 0x36, 0x1a, 0xcf, 0x01, 0x0a, 0x06, 0x50, 0x72, 0x6f, 0x62, 0x65,
+	0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x4b, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
+	0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e,
+	0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x61,
+	0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x73, 0x2e, 0x45,
+	0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
+	0x74, 0x73, 0x1a, 0x64, 0x0a, 0x08, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x21,
+	0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x6f, 0x72,
+	0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x74,
+	0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
+	0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x3a, 0x36, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x13,
+	0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x0b, 0x12, 0x09, 0x44, 0x61, 0x74, 0x61, 0x70,
+	0x6c, 0x61, 0x6e, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x06, 0x22, 0x04, 0x6d, 0x65, 0x73, 0x68,
+	0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b,
+	0x75, 0x6d, 0x61, 0x68, 0x71, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d,
+	0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1170,56 +1239,59 @@ func file_mesh_v1alpha1_dataplane_proto_rawDescGZIP() []byte {
 	return file_mesh_v1alpha1_dataplane_proto_rawDescData
 }
 
+var file_mesh_v1alpha1_dataplane_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_mesh_v1alpha1_dataplane_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
 var file_mesh_v1alpha1_dataplane_proto_goTypes = []interface{}{
-	(*Dataplane)(nil),                                     // 0: kuma.mesh.v1alpha1.Dataplane
-	(*Dataplane_Networking)(nil),                          // 1: kuma.mesh.v1alpha1.Dataplane.Networking
-	(*Dataplane_Probes)(nil),                              // 2: kuma.mesh.v1alpha1.Dataplane.Probes
-	(*Dataplane_Networking_Ingress)(nil),                  // 3: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress
-	(*Dataplane_Networking_Inbound)(nil),                  // 4: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound
-	(*Dataplane_Networking_Outbound)(nil),                 // 5: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound
-	(*Dataplane_Networking_Gateway)(nil),                  // 6: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway
-	(*Dataplane_Networking_TransparentProxying)(nil),      // 7: kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying
-	(*Dataplane_Networking_Ingress_AvailableService)(nil), // 8: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService
-	nil, // 9: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.TagsEntry
-	nil, // 10: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.TagsEntry
-	(*Dataplane_Networking_Inbound_Health)(nil),           // 11: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.Health
-	(*Dataplane_Networking_Inbound_ServiceProbe)(nil),     // 12: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe
-	(*Dataplane_Networking_Inbound_ServiceProbe_Tcp)(nil), // 13: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.Tcp
-	nil,                               // 14: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.TagsEntry
-	nil,                               // 15: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.TagsEntry
-	(*Dataplane_Probes_Endpoint)(nil), // 16: kuma.mesh.v1alpha1.Dataplane.Probes.Endpoint
-	(*MetricsBackend)(nil),            // 17: kuma.mesh.v1alpha1.MetricsBackend
-	(*durationpb.Duration)(nil),       // 18: google.protobuf.Duration
-	(*wrapperspb.UInt32Value)(nil),    // 19: google.protobuf.UInt32Value
+	(Dataplane_Networking_Gateway_GatewayType)(0), // 0: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.GatewayType
+	(*Dataplane)(nil),                                     // 1: kuma.mesh.v1alpha1.Dataplane
+	(*Dataplane_Networking)(nil),                          // 2: kuma.mesh.v1alpha1.Dataplane.Networking
+	(*Dataplane_Probes)(nil),                              // 3: kuma.mesh.v1alpha1.Dataplane.Probes
+	(*Dataplane_Networking_Ingress)(nil),                  // 4: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress
+	(*Dataplane_Networking_Inbound)(nil),                  // 5: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound
+	(*Dataplane_Networking_Outbound)(nil),                 // 6: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound
+	(*Dataplane_Networking_Gateway)(nil),                  // 7: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway
+	(*Dataplane_Networking_TransparentProxying)(nil),      // 8: kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying
+	(*Dataplane_Networking_Ingress_AvailableService)(nil), // 9: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService
+	nil, // 10: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.TagsEntry
+	nil, // 11: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.TagsEntry
+	(*Dataplane_Networking_Inbound_Health)(nil),           // 12: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.Health
+	(*Dataplane_Networking_Inbound_ServiceProbe)(nil),     // 13: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe
+	(*Dataplane_Networking_Inbound_ServiceProbe_Tcp)(nil), // 14: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.Tcp
+	nil,                               // 15: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.TagsEntry
+	nil,                               // 16: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.TagsEntry
+	(*Dataplane_Probes_Endpoint)(nil), // 17: kuma.mesh.v1alpha1.Dataplane.Probes.Endpoint
+	(*MetricsBackend)(nil),            // 18: kuma.mesh.v1alpha1.MetricsBackend
+	(*durationpb.Duration)(nil),       // 19: google.protobuf.Duration
+	(*wrapperspb.UInt32Value)(nil),    // 20: google.protobuf.UInt32Value
 }
 var file_mesh_v1alpha1_dataplane_proto_depIdxs = []int32{
-	1,  // 0: kuma.mesh.v1alpha1.Dataplane.networking:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking
-	17, // 1: kuma.mesh.v1alpha1.Dataplane.metrics:type_name -> kuma.mesh.v1alpha1.MetricsBackend
-	2,  // 2: kuma.mesh.v1alpha1.Dataplane.probes:type_name -> kuma.mesh.v1alpha1.Dataplane.Probes
-	3,  // 3: kuma.mesh.v1alpha1.Dataplane.Networking.ingress:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress
-	6,  // 4: kuma.mesh.v1alpha1.Dataplane.Networking.gateway:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Gateway
-	4,  // 5: kuma.mesh.v1alpha1.Dataplane.Networking.inbound:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound
-	5,  // 6: kuma.mesh.v1alpha1.Dataplane.Networking.outbound:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Outbound
-	7,  // 7: kuma.mesh.v1alpha1.Dataplane.Networking.transparent_proxying:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying
-	16, // 8: kuma.mesh.v1alpha1.Dataplane.Probes.endpoints:type_name -> kuma.mesh.v1alpha1.Dataplane.Probes.Endpoint
-	8,  // 9: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.availableServices:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService
-	10, // 10: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.TagsEntry
-	11, // 11: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.health:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.Health
-	12, // 12: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.serviceProbe:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe
-	14, // 13: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.TagsEntry
-	15, // 14: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.TagsEntry
-	9,  // 15: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.TagsEntry
-	18, // 16: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.interval:type_name -> google.protobuf.Duration
-	18, // 17: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.timeout:type_name -> google.protobuf.Duration
-	19, // 18: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.unhealthy_threshold:type_name -> google.protobuf.UInt32Value
-	19, // 19: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.healthy_threshold:type_name -> google.protobuf.UInt32Value
-	13, // 20: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.tcp:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.Tcp
-	21, // [21:21] is the sub-list for method output_type
-	21, // [21:21] is the sub-list for method input_type
-	21, // [21:21] is the sub-list for extension type_name
-	21, // [21:21] is the sub-list for extension extendee
-	0,  // [0:21] is the sub-list for field type_name
+	2,  // 0: kuma.mesh.v1alpha1.Dataplane.networking:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking
+	18, // 1: kuma.mesh.v1alpha1.Dataplane.metrics:type_name -> kuma.mesh.v1alpha1.MetricsBackend
+	3,  // 2: kuma.mesh.v1alpha1.Dataplane.probes:type_name -> kuma.mesh.v1alpha1.Dataplane.Probes
+	4,  // 3: kuma.mesh.v1alpha1.Dataplane.Networking.ingress:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress
+	7,  // 4: kuma.mesh.v1alpha1.Dataplane.Networking.gateway:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Gateway
+	5,  // 5: kuma.mesh.v1alpha1.Dataplane.Networking.inbound:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound
+	6,  // 6: kuma.mesh.v1alpha1.Dataplane.Networking.outbound:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Outbound
+	8,  // 7: kuma.mesh.v1alpha1.Dataplane.Networking.transparent_proxying:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying
+	17, // 8: kuma.mesh.v1alpha1.Dataplane.Probes.endpoints:type_name -> kuma.mesh.v1alpha1.Dataplane.Probes.Endpoint
+	9,  // 9: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.availableServices:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService
+	11, // 10: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.TagsEntry
+	12, // 11: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.health:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.Health
+	13, // 12: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.serviceProbe:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe
+	15, // 13: kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Outbound.TagsEntry
+	16, // 14: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.TagsEntry
+	0,  // 15: kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.type:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Gateway.GatewayType
+	10, // 16: kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.tags:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Ingress.AvailableService.TagsEntry
+	19, // 17: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.interval:type_name -> google.protobuf.Duration
+	19, // 18: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.timeout:type_name -> google.protobuf.Duration
+	20, // 19: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.unhealthy_threshold:type_name -> google.protobuf.UInt32Value
+	20, // 20: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.healthy_threshold:type_name -> google.protobuf.UInt32Value
+	14, // 21: kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.tcp:type_name -> kuma.mesh.v1alpha1.Dataplane.Networking.Inbound.ServiceProbe.Tcp
+	22, // [22:22] is the sub-list for method output_type
+	22, // [22:22] is the sub-list for method input_type
+	22, // [22:22] is the sub-list for extension type_name
+	22, // [22:22] is the sub-list for extension extendee
+	0,  // [0:22] is the sub-list for field type_name
 }
 
 func init() { file_mesh_v1alpha1_dataplane_proto_init() }
@@ -1391,13 +1463,14 @@ func file_mesh_v1alpha1_dataplane_proto_init() {
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_mesh_v1alpha1_dataplane_proto_rawDesc,
-			NumEnums:      0,
+			NumEnums:      1,
 			NumMessages:   17,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
 		GoTypes:           file_mesh_v1alpha1_dataplane_proto_goTypes,
 		DependencyIndexes: file_mesh_v1alpha1_dataplane_proto_depIdxs,
+		EnumInfos:         file_mesh_v1alpha1_dataplane_proto_enumTypes,
 		MessageInfos:      file_mesh_v1alpha1_dataplane_proto_msgTypes,
 	}.Build()
 	File_mesh_v1alpha1_dataplane_proto = out.File
diff --git a/api/mesh/v1alpha1/dataplane.proto b/api/mesh/v1alpha1/dataplane.proto
index a22fe0f4a..cf86bee23 100644
--- a/api/mesh/v1alpha1/dataplane.proto
+++ b/api/mesh/v1alpha1/dataplane.proto
@@ -135,10 +135,24 @@ message Dataplane {
 
     // Gateway describes a service that ingress should not be proxied.
     message Gateway {
+      enum GatewayType {
+        // A DELEGATED gateway is a independently deployed proxy that
+        // receives inbound traffic that is not proxied by Kuma, and
+        // sends outbound traffic into the Kuma dataplane proxy.
+        DELEGATED = 0;
+        // The BUILTIN gateway type is experimental and unsupported.
+        BUILTIN = 1;
+      }
+
       // Tags associated with a gateway (e.g., Kong, Contour, etc) this
       // dataplane is deployed next to, e.g. service=gateway, env=prod.
       // `service` tag is mandatory.
       map<string, string> tags = 1 [ (validate.rules).map.min_pairs = 1 ];
+
+      // Type of gateway this dataplane manages. The default is a DELEGATED
+      // gateway, which is an external proxy. The BUILTIN gateway type causes
+      // the dataplane proxy itself to be configured as a gateway.
+      GatewayType type = 2;
     }
 
     // TransparentProxying describes configuration for transparent proxying.
diff --git a/api/mesh/v1alpha1/dataplane_helpers.go b/api/mesh/v1alpha1/dataplane_helpers.go
index 8fa86e50d..326fe5069 100644
--- a/api/mesh/v1alpha1/dataplane_helpers.go
+++ b/api/mesh/v1alpha1/dataplane_helpers.go
@@ -394,7 +394,7 @@ func (d *Dataplane) GetIdentifyingService() string {
 // IsIngress returns true if this Dataplane specifies an ingress
 // configuration.
 //
-// Deprecated in favor of ZoneIngress.
+// Deprecated: use ZoneIngress instead.
 func (d *Dataplane) IsIngress() bool {
 	if d.GetNetworking() == nil {
 		return false
@@ -402,14 +402,14 @@ func (d *Dataplane) IsIngress() bool {
 	return d.GetNetworking().GetIngress() != nil
 }
 
-// IsDataplane returns true if this Dataplane specifies a gateway
-// configuration.
-func (d *Dataplane) IsGateway() bool {
-	if d.GetNetworking() == nil {
-		return false
-	}
+func (d *Dataplane) IsDelegatedGateway() bool {
+	return d.GetNetworking().GetGateway() != nil &&
+		d.GetNetworking().GetGateway().GetType() == Dataplane_Networking_Gateway_DELEGATED
+}
 
-	return d.GetNetworking().GetGateway() != nil
+func (d *Dataplane) IsBuiltinGateway() bool {
+	return d.GetNetworking().GetGateway() != nil &&
+		d.GetNetworking().GetGateway().GetType() == Dataplane_Networking_Gateway_BUILTIN
 }
 
 func (d *Dataplane) HasPublicAddress() bool {
diff --git a/app/kuma-cp/cmd/root.go b/app/kuma-cp/cmd/root.go
index fd97ee9e1..eb5402286 100644
--- a/app/kuma-cp/cmd/root.go
+++ b/app/kuma-cp/cmd/root.go
@@ -3,6 +3,7 @@ package cmd
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 
 	"github.com/spf13/cobra"
 
@@ -37,8 +38,13 @@ func newRootCmd() *cobra.Command {
 			}
 
 			if args.outputPath != "" {
-				fmt.Printf("logs will be stored in %v", args.outputPath)
-				core.SetLogger(core.NewLoggerWithRotation(level, args.outputPath, args.maxSize, args.maxBackups, args.maxAge))
+				output, err := filepath.Abs(args.outputPath)
+				if err != nil {
+					return err
+				}
+
+				fmt.Printf("%s: logs will be stored in %q\n", "kuma-cp", output)
+				core.SetLogger(core.NewLoggerWithRotation(level, output, args.maxSize, args.maxBackups, args.maxAge))
 			} else {
 				core.SetLogger(core.NewLogger(level))
 			}
diff --git a/app/kuma-dp/cmd/root.go b/app/kuma-dp/cmd/root.go
index c27778a05..9f27c5ad1 100644
--- a/app/kuma-dp/cmd/root.go
+++ b/app/kuma-dp/cmd/root.go
@@ -3,6 +3,7 @@ package cmd
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 
 	"github.com/spf13/cobra"
 
@@ -35,8 +36,13 @@ func NewRootCmd(rootCtx *RootContext) *cobra.Command {
 				return err
 			}
 			if args.outputPath != "" {
-				fmt.Printf("logs will be stored in %v", args.outputPath)
-				core.SetLogger(core.NewLoggerWithRotation(level, args.outputPath, args.maxSize, args.maxBackups, args.maxAge))
+				output, err := filepath.Abs(args.outputPath)
+				if err != nil {
+					return err
+				}
+
+				fmt.Printf("%s: logs will be stored in %q\n", "kuma-dp", output)
+				core.SetLogger(core.NewLoggerWithRotation(level, output, args.maxSize, args.maxBackups, args.maxAge))
 			} else {
 				core.SetLogger(core.NewLogger(level))
 			}
diff --git a/app/kuma-prometheus-sd/cmd/root.go b/app/kuma-prometheus-sd/cmd/root.go
index 95ef982b2..a57a3a2bf 100644
--- a/app/kuma-prometheus-sd/cmd/root.go
+++ b/app/kuma-prometheus-sd/cmd/root.go
@@ -3,6 +3,7 @@ package cmd
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 
 	"github.com/spf13/cobra"
 
@@ -35,8 +36,13 @@ func newRootCmd() *cobra.Command {
 				return err
 			}
 			if args.outputPath != "" {
-				fmt.Printf("logs will be stored in %v", args.outputPath)
-				core.SetLogger(core.NewLoggerWithRotation(level, args.outputPath, args.maxSize, args.maxBackups, args.maxAge))
+				output, err := filepath.Abs(args.outputPath)
+				if err != nil {
+					return err
+				}
+
+				fmt.Printf("%s: logs will be stored in %q\n", "kuma-prometheus-sd", output)
+				core.SetLogger(core.NewLoggerWithRotation(level, output, args.maxSize, args.maxBackups, args.maxAge))
 			} else {
 				core.SetLogger(core.NewLogger(level))
 			}
diff --git a/app/kuma-ui/pkg/resources/data/css/app.ba88165d.css b/app/kuma-ui/pkg/resources/data/css/app.e3a402b2.css
similarity index 65%
rename from app/kuma-ui/pkg/resources/data/css/app.ba88165d.css
rename to app/kuma-ui/pkg/resources/data/css/app.e3a402b2.css
index 8ad1b7684..9a67d9cae 100644
--- a/app/kuma-ui/pkg/resources/data/css/app.ba88165d.css
+++ b/app/kuma-ui/pkg/resources/data/css/app.e3a402b2.css
@@ -1,3 +1,3 @@
 .status[data-v-56071258]{font-size:var(--type-sm);color:var(--gray-3);letter-spacing:0;line-height:20px}.status__dot[data-v-56071258]{--status-color:var(--red-600);display:inline-block;width:8px;height:8px;border-radius:100%;margin-right:6px;background-color:var(--status-color)}.status__dot.is-active[data-v-56071258]{--status-color:var(--green-500)}.upgrade-check .k-alert.k-alert[data-v-548c3348]{padding:var(--spacing-xxs) var(--spacing-xs)}.alert-content[data-v-548c3348]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:var(--type-sm)}.alert-content>[data-v-548c3348]:first-of-type{margin-right:var(--spacing-sm)}.alert-content .k-button[data-v-548c3348]{text-decoration:none}.alert-content .k-button[data-v-548c3348]:after{display:none}.warning-button[data-v-548c3348]{--KButtonPrimaryBase:#f2a230;--KButtonPrimaryHover:#f2a230;--KButtonPrimaryActive:#f2a230}.alert-content[data-v-0c7749f3]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:var(--type-sm)}.alert-content>[data-v-0c7749f3]:first-of-type{margin-right:var(--spacing-sm)}.alert-content .k-button[data-v-0c7749f3]{text-decoration:none}.alert-content .k-button[data-v-0c7749f3]:after{display:none}.success-button[data-v-0c7749f3]{--KButtonPrimaryBase:#19a654;--KButtonPrimaryHover:#19a654;--KButtonPrimaryActive:#19a654}.main-header[data-v-74be839c]{position:fixed;z-index:1030;top:0;left:0;width:100%;height:var(--topbar-height);border-bottom:1px solid var(--black-10);background-color:#fff}.main-header--simple[data-v-74be839c]{border-bottom:0;background:none}.logo img[data-v-74be839c]{display:block;width:auto;height:auto;max-height:var(--logo-max-height)}.upgrade-check-wrapper[data-v-74be839c]{margin-left:auto}.status-badge[data-v-74be839c]{--KBadgeWidth:auto;--KBadgePaddingX:var(--spacing-sm)}.app-status[data-v-74be839c]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-status .kpop-control[data-v-74be839c]{max-height:27px}.app-status .kpop-control[data-v-74be839c]:after{display:none}@media screen and (min-width:1024px){.app-status--desktop[data-v-74be839c]{display:block}.app-status--mobile[data-v-74be839c]{display:none}}@media screen and (max-width:1023px){.app-status--desktop[data-v-74be839c]{display:none}.app-status--mobile[data-v-74be839c]{display:block}}@media screen and (min-width:990px){.status-badge[data-v-74be839c]{margin-left:var(--spacing-sm)}}@media screen and (max-width:989px){.status-badge[data-v-74be839c]{margin-top:var(--spacing-sm)}}@media screen and (max-width:599px){.upgrade-check-wrapper[data-v-74be839c]{display:none}}.loading-container[data-v-024cc085]{display:-webkit-box;display:-ms-flexbox;display:flex;max-width:350px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.loading-container .progress[data-v-024cc085]{margin-top:1rem;width:130%;background-color:#e6e6e6}.loading-container .progress .progress-bar[data-v-024cc085]{height:5px;background-color:var(--LoaderProgressBarBG)}.full-screen[data-v-9cbb746e]{background:#fff;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:50000;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}
 
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}details{display:block}summary{display:list-item}[hidden],template{display:none}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e2e8f0}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder,textarea::-moz-placeholder{color:#a0aec0}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#a0aec0}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#a0aec0}input::placeholder,textarea::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.border{border-width:1px}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.flex-col{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.flex-grow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.flex-shrink{-ms-flex-negative:1;flex-shrink:1}.font-semibold{font-weight:600}.text-sm{font-size:.875rem}.my-0{margin-top:0;margin-bottom:0}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.mt-4{margin-top:1rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.mt-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mt-8{margin-top:2rem}.ml-auto{margin-left:auto}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.relative{position:relative}.resize{resize:both}.uppercase{text-transform:uppercase}.no-underline{text-decoration:none}.tracking-widest{letter-spacing:.1em}.transform{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y))}.transition{-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@-webkit-keyframes pulse{50%{opacity:.5}}@keyframes pulse{50%{opacity:.5}}@-webkit-keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@media (min-width:768px){.md\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.md\:flex-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.md\:flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.md\:mr-2{margin-right:.5rem}.md\:ml-auto{margin-left:auto}.md\:py-0{padding-top:0;padding-bottom:0}.md\:px-4{padding-left:1rem;padding-right:1rem}.md\:w-1\/2{width:50%}}@media (min-width:1280px){.xl\:flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.xl\:w-auto{width:auto}.xl\:w-1\/3{width:33.333333%}}:root{--base-font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;--base-font-size-root:62.5%;--base-font-size:15px;--font-weight-light:400;--font-weight-bold:700;--gray-1:#faf5f9;--gray-2:#dbbbd5;--gray-3:rgba(0,0,0,0.45);--gray-4:#ebebeb;--gray-5:#f7f9fa;--gray-6:#fdfdfd;--gray-7:#f3f5f7;--blue-1:#2d64b3;--blue-2:#3d88f2;--blue-3:rgba(61,136,242,0.07);--blue-4:#1155cb;--black-1:rgba(0,0,0,0.75);--green-1:#1b9844;--logo-coral:#ee485d;--logo-teal:#00cdde;--logo-mint:#00e8c2;--logo-navy:#172350;--logo-green:#3db664;--logo-purple:#290b53;--logo-pink:#ff5d8c;--brand-color-1:var(--logo-coral);--brand-color-2:var(--logo-teal);--brand-color-3:var(--logo-mint);--brand-color-4:var(--logo-navy);--brand-color-5:var(--logo-green);--brand-color-6:var(--logo-purple);--brand-color-7:var(--logo-pink);--topbar-height:60px;--logo-max-height:36px;--global-content-max-width:100rem;--sidebar-width:240px;--sidebar-width-closed:63px;--sidebar-bg-color:var(--gray-6);--sidebarOpenWidth:180px;--sidebarCollapsedWidth:55px;--subnavWidth:210px;--subnavHorizontalMargin:1rem;--sidebarBackground:var(--white);--headerHeight:var(--topbar-height);--transition:cubic-bezier(1.0,0.5,0.8,1.0);--transitionTiming:0.1s;--core-theme-color:#290b53;--core-theme-color-light:rgba(41,11,83,0.75);--core-theme-color-lighter:rgba(41,11,83,0.08);--core-theme-color-dark:#000;--core-theme-color-darker:#000;--KButtonPrimaryBase:var(--core-theme-color);--KButtonPrimaryHover:var(--core-theme-color-light);--KButtonPrimaryActive:var(--core-theme-color-light);--KRadioPrimary:var(--core-theme-color);--KInputFocus:var(--core-theme-color);--SidebarIconColor:var(--core-theme-color);--SidebarLinkColor:var(--core-theme-color-darker);--SidebarLinkBGColor:var(--core-theme-color-lighter);--SidebarTitleColor:var(--core-theme-color-light);--LinkColorBase:var(--core-theme-color);--LinkColorHover:var(--core-theme-color-light);--MetricsCardBGColorHover:var(--core-theme-color-lighter);--WizardTabBGColor:var(--core-theme-color);--WizardTabTextColor:#fff;--KTabsActiveColor:var(--core-theme-color);--DataOverviewTableLinkColor:var(--core-theme-color);--MeshSelectorTitleColor:var(--core-theme-color-light);--MeshSelectorInputTextColor:var(--core-theme-color);--MeshSelectorInputBorderColor:var(--core-theme-color-lighter);--MeshSelectorInputBorderColorFocus:var(--core-theme-color-light);--LoaderProgressBarBG:var(--core-theme-color-light);--KEmptyStateContentWidth:85%}.kutil-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.kutil-img-full{width:100%}.kutil-img-fluid,.kutil-img-full{max-width:100%;height:auto}.kutil-clear-text{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale}.kutil-quotify{quotes:"“" "”" "‘" "’"}.kutil-quotify:before{content:open-quote}.kutil-quotify:after{content:close-quote}.kutil-sticky{position:-webkit-sticky;position:sticky;top:0}.kutil-sticky:after,.kutil-sticky:before{content:"";display:table}.arrow-link{text-decoration:none;color:var(--blue-4)}.arrow-link,.k-button{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.k-button{font-weight:400!important}.arrow-link:after,.k-button:after{display:inline-block;content:"›";margin-left:5px}.capitalize{display:inline-block;text-transform:capitalize}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-uppercase{text-transform:uppercase}.text-italic{font-style:italic}.font-normal{font-weight:400}.font-light{font-weight:100}.font-semibold{font-weight:500}.font-bold{font-weight:700}.badge{display:inline-block;padding:.25rem .4rem;font-size:75%;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.top-border{border-top:1px solid var(--black-10)}.bottom-border{border-bottom:1px solid var(--black-10)}.text-muted{color:var(--black-45)!important}.text-danger{color:var(--red-500)!important}.h-100{height:100%}.h-screen{min-height:100vh}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Thin.ad538a69.woff2) format("woff2"),url(../fonts/Roboto-Thin.03fb3a93.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-ThinItalic.5b4a33e1.woff2) format("woff2"),url(../fonts/Roboto-ThinItalic.4ced2a97.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Light.d26871e8.woff2) format("woff2"),url(../fonts/Roboto-Light.c8405cfa.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-LightItalic.e8eaae90.woff2) format("woff2"),url(../fonts/Roboto-LightItalic.f6dd13d5.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Regular.73f0a88b.woff2) format("woff2"),url(../fonts/Roboto-Regular.878ad715.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Italic.4357beb8.woff2) format("woff2"),url(../fonts/Roboto-Italic.6521f388.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Medium.90d16760.woff2) format("woff2"),url(../fonts/Roboto-Medium.7b225d4d.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-MediumItalic.13ec0eb5.woff2) format("woff2"),url(../fonts/Roboto-MediumItalic.5df7f053.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Bold.b52fac2b.woff2) format("woff2"),url(../fonts/Roboto-Bold.eb43b4c3.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-BoldItalic.94008e69.woff2) format("woff2"),url(../fonts/Roboto-BoldItalic.563c4bd6.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Black.59eb3601.woff2) format("woff2"),url(../fonts/Roboto-Black.8f766bb9.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-BlackItalic.f75569f8.woff2) format("woff2"),url(../fonts/Roboto-BlackItalic.83b2c7d0.woff) format("woff");font-weight:900;font-style:italic}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Regular.a48ac416.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Medium.5a45b286.ttf) format("truetype");font-weight:500;font-style:normal}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Bold.c0c4a337.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:Material Icons;font-style:normal;font-weight:400;src:url(../fonts/MaterialIcons-Regular.e79bfd88.eot);src:local("Material Icons"),local("MaterialIcons-Regular"),url(../fonts/MaterialIcons-Regular.570eb838.woff2) format("woff2"),url(../fonts/MaterialIcons-Regular.012cf6a1.woff) format("woff"),url(../fonts/MaterialIcons-Regular.a37b0c01.ttf) format("truetype")}body{padding-top:var(--topbar-height);font-family:var(--base-font-family)}.title-3x{font-size:var(--type-xxxl)}.title-2x{font-size:var(--type-xxl)}.title-1x{font-size:var(--type-xl)}a:link,a:visited{color:var(--LinkColorBase);text-decoration:underline}a:active,a:focus,a:hover{color:var(--LinkColorHover)}select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:3px;border:1px solid rgba(23,130,207,.35);font-size:16px;color:#1155cb;line-height:20px;padding:10px 16px 10px 13px;background-color:#fff;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMSAxbDQgNCA0LTQiIHN0cm9rZT0iIzE3ODJDRiIgc3Ryb2tlLXdpZHRoPSIxLjUiIGZpbGw9Im5vbmUiLz48L3N2Zz4=);background-position:calc(100% - 13px) 50%;background-repeat:no-repeat}.k-button,[type=button],button{-webkit-transition:none!important;transition:none!important}.code-sample{font-family:var(--font-family-mono)}.form-container{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;padding-right:15px;padding-left:15px;margin:0 auto}@media (max-width:1200px){.form-container{-webkit-box-flex:0;-ms-flex:0 0 70%;flex:0 0 70%;max-width:70%}}@media (max-width:860px){.form-container{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}}.vue-form-generator .form-control{border:1px solid rgba(0,0,0,.12);-webkit-box-shadow:none;box-shadow:none;color:rgba(0,0,0,.7)}.form-group,.vue-form-generator .form-group{margin-bottom:1.5rem}.form-group:last-child,.vue-form-generator .form-group:last-child{margin-bottom:2rem}.vue-form-generator .field-advanced{margin-top:-.5rem;margin-bottom:.5rem}.vue-form-generator .field-advanced .form-group:last-child{margin-bottom:1rem}.top-border{padding-top:1.5rem;border-top:1px solid rgba(0,0,0,.08)}.bottom-border{padding-bottom:1.5rem;border-bottom:1px solid rgba(0,0,0,.08)}.form-control{font-size:15px;color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.12);border-radius:3px;border-width:1px}.form-control:focus{outline:none;border:1px solid #80caff}.form-control:disabled{background-color:#f7f7f7;opacity:.75}.form-control.has-error{border:1px solid #ff8280}.vue-form-generator .form-group.hide-label>label{display:none}.vue-form-generator .form-group label{font-weight:500}.form-group label{width:100%}.form-group label small{float:right;font-size:14px;font-style:italic;font-weight:400;color:rgba(0,0,0,.5)}.form-group.required>label:after{display:none}.form-group.optional>label,.form-group.semi-optional>label{position:relative;width:100%}.form-group.optional>label:after,.form-group.semi-optional>label:after{position:absolute;display:block;top:0;right:0;font-size:14px;font-style:italic;font-weight:400;color:rgba(0,0,0,.5)}.form-group.optional>label:after{content:"Optional"}.form-group.semi-optional>label:after{content:"Semi-Optional"}.vue-form-generator span.help .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiI+PHBhdGggZmlsbD0iIzAwODZFNiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNiAxMUE1IDUgMCAxMTYuMDAxLjk5OSA1IDUgMCAwMTYgMTFNNiAwYTYgNiAwIDEwMCAxMkE2IDYgMCAwMDYgMG0wIDNhMiAyIDAgMDAtMiAyaDFhMSAxIDAgMTExIDEgMSAxIDAgMDAtMSAxaDFhMiAyIDAgMTAwLTR6TTUgOWgyVjhINXYxeiIvPjwvc3ZnPg==);width:.75rem;height:.75rem}.vue-form-generator span.help .helpText{left:-108px;width:224px;padding:.5rem .75rem;color:rgba(0,0,0,.75);font-weight:400;font-size:14px;text-align:left;border:1px solid #d6d6d6;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 0 4px 0 rgba(0,0,0,.12);box-shadow:0 0 4px 0 rgba(0,0,0,.12);z-index:900}.vue-form-generator span.help .helpText:after,.vue-form-generator span.help .helpText:before{position:absolute;top:100%;left:50%;height:0;width:0;border:solid transparent;pointer-events:none;content:" "}.vue-form-generator span.help .helpText:before{border-top-color:#d6d6d6;border-width:13px;margin-left:-13px}.vue-form-generator span.help .helpText:after{border-top-color:#fff;border-width:12px;margin-left:-12px}.hint{font-size:small;margin-top:5px;margin-bottom:10px;opacity:.6}.option-field{padding-left:1.5rem;width:100%}.option-field .form-group:last-child{margin-bottom:0}.custom-control-indicator{background-color:rgba(0,0,0,.12)}.custom-control-input:checked~.custom-control-indicator{background-color:#3295fc}.custom-control-input:focus~.custom-control-indicator{-webkit-box-shadow:0 0 0 1px #fff,0 0 0 3px #3295fc;box-shadow:0 0 0 1px #fff,0 0 0 3px #3295fc}.form-group label{font-size:14px;font-weight:500;color:#262626;margin:0 0 8px 0}.form-check-input,.form-control .list-row input[type=checkbox],.form-group .field-wrap input[type=checkbox]{appearance:none;-moz-appearance:none;-webkit-appearance:none;position:relative;vertical-align:middle;display:inline-block;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-check-input:focus,.form-control .list-row input[type=checkbox]:focus,.form-group .field-wrap input[type=checkbox]:focus{outline:none}.form-check-input:before,.form-control .list-row input[type=checkbox]:before,.form-group .field-wrap input[type=checkbox]:before{content:"";display:inline-block;height:16px;width:16px;border:1px solid #bfbfbf;border-radius:2px;margin-right:5px;background:#fff}.form-check-input:checked:before,.form-control .list-row input[type=checkbox]:checked:before,.form-group .field-wrap input[type=checkbox]:checked:before{background-color:#3295fc;border-color:#3295fc}.form-check-input:checked:after,.form-control .list-row input[type=checkbox]:checked:after,.form-group .field-wrap input[type=checkbox]:checked:after{content:"";position:absolute;top:4px;left:4px;display:inline-block;height:6px;width:9px;color:#fff;border-left:2px solid;border-bottom:2px solid;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.form-check-input::-ms-check,.form-control .list-row input[type=checkbox]::-ms-check,.form-group .field-wrap input[type=checkbox]::-ms-check{display:inline-block;height:16px;width:16px;border:1px solid #bfbfbf;border-radius:2px;margin-right:5px}.form-check-input:checked::-ms-check,.form-control .list-row input[type=checkbox]:checked::-ms-check,.form-group .field-wrap input[type=checkbox]:checked::-ms-check{color:#fff;background-color:#3295fc}.form-group.required input[type=checkbox],.form-group [required=required]{-webkit-box-shadow:none;box-shadow:none}.form-control input[type=checkbox],.form-control label{vertical-align:middle;line-height:1rem}.form-inline .form-check-input{margin-top:.25rem}.vue-form-generator .form-group.field-checkbox label{margin-top:-5px}.vue-form-generator .field-switch .field-wrap input[type=checkbox]{position:absolute}.vue-form-generator .field-switch .field-wrap label{width:42px;height:20px;margin:0}.vue-form-generator .field-switch input:checked~.label{background:#2196f3;-webkit-box-shadow:none;box-shadow:none}.vue-form-generator .field-switch .label{background:#ccc}.vue-form-generator .field-switch .label:after,.vue-form-generator .field-switch .label:before{color:rgba(0,0,0,.7);text-shadow:none;margin-left:42px;font-size:14px;left:18px;font-weight:400;text-transform:none;font-family:Roboto;width:-webkit-max-content;width:-moz-max-content;width:max-content}.vue-form-generator .field-switch .handle{width:17px;height:17px}.vue-form-generator .field-switch input:checked~.handle{left:calc(100% - 18px)}.vue-form-generator .field-switch .handle:before{background:none;-webkit-box-shadow:none;box-shadow:none}.entity-status{letter-spacing:0;line-height:20px;color:var(--green-400)}.entity-status,.entity-total-updates{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.entity-total-updates{gap:2px;pointer-events:auto!important}.entity-status.is-offline{color:var(--red-600)}.entity-status.is-degraded{color:#ff8040}.entity-status.is-degraded .entity-status__dot{background-color:#ff8040}.entity-status.is-offline .entity-status__dot{background-color:var(--red-600)}.entity-status__dot{display:inline-block;width:8px;height:8px;border-radius:100%;margin-right:6px;background-color:var(--green-400);-ms-flex-negative:0;flex-shrink:0}.kong-icon--centered{display:block;margin:0 auto 10px auto;text-align:center}@media screen and (min-width:1024px){.k-card--small{max-width:65%}}.empty-state-content p{width:100%;max-width:var(--KEmptyStateContentWidth)!important}.empty-state-wrapper{padding:2rem 0!important}.k-tabs .tab-container{outline:0!important}.k-popover{z-index:1031!important}.k-popover .k-badge{display:inline}.help-icon{--i:22px;margin:0 8px}.help-icon,.help-icon a{display:inline-block;width:var(--i)}.help-icon a{height:var(--i);line-height:var(--i);border-radius:100%;color:#fff;text-decoration:none;text-align:center;font-size:12px;background-color:var(--gray-2);cursor:pointer}.custom-control-icon{display:inline-block;margin-right:5px;font-size:var(--type-lg);line-height:0;max-height:18px}.external-link-btn{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:var(--spacing-xs) var(--spacing-sm);font-family:var(--font-family-sans);font-size:1rem;font-weight:400;line-height:1.25;text-decoration:none;vertical-align:middle;border:1px solid transparent;border-radius:3px;cursor:pointer;color:#fff!important;background-color:var(--KButtonPrimaryBase);text-decoration:none!important}.external-link-btn:after{display:inline-block;content:"\203A";margin-left:5px}.external-link-btn:hover{background-color:#0089eb}.main-content{padding:44px;-webkit-transition:var(--transitionTiming) margin var(--transition);transition:var(--transitionTiming) margin var(--transition)}.page{max-width:76rem;margin:0 auto}.main-content-container{max-width:var(--global-content-max-width);margin:0 auto}.welcome{max-width:640px;margin-left:auto;margin-right:auto}.fade-enter-active,.fade-leave-active{-webkit-transition:opacity 0 linear;transition:opacity 0 linear}.fade-enter,.fade-leave-to{opacity:0}
\ No newline at end of file
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}details{display:block}summary{display:list-item}[hidden],template{display:none}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e2e8f0}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder,textarea::-moz-placeholder{color:#a0aec0}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#a0aec0}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#a0aec0}input::placeholder,textarea::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.border{border-width:1px}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.flex-col{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.flex-grow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.flex-shrink{-ms-flex-negative:1;flex-shrink:1}.font-semibold{font-weight:600}.text-sm{font-size:.875rem}.my-0{margin-top:0;margin-bottom:0}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.mt-4{margin-top:1rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.mt-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mt-8{margin-top:2rem}.ml-auto{margin-left:auto}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.relative{position:relative}.resize{resize:both}.uppercase{text-transform:uppercase}.no-underline{text-decoration:none}.tracking-widest{letter-spacing:.1em}.transform{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y))}.transition{-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@-webkit-keyframes pulse{50%{opacity:.5}}@keyframes pulse{50%{opacity:.5}}@-webkit-keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@media (min-width:768px){.md\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.md\:flex-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.md\:flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.md\:mr-2{margin-right:.5rem}.md\:ml-auto{margin-left:auto}.md\:py-0{padding-top:0;padding-bottom:0}.md\:px-4{padding-left:1rem;padding-right:1rem}.md\:w-1\/2{width:50%}}@media (min-width:1280px){.xl\:flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.xl\:w-auto{width:auto}.xl\:w-1\/3{width:33.333333%}}:root{--base-font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;--base-font-size-root:62.5%;--base-font-size:15px;--font-weight-light:400;--font-weight-bold:700;--gray-1:#faf5f9;--gray-2:#dbbbd5;--gray-3:rgba(0,0,0,0.45);--gray-4:#ebebeb;--gray-5:#f7f9fa;--gray-6:#fdfdfd;--gray-7:#f3f5f7;--blue-1:#2d64b3;--blue-2:#3d88f2;--blue-3:rgba(61,136,242,0.07);--blue-4:#1155cb;--black-1:rgba(0,0,0,0.75);--green-1:#1b9844;--logo-coral:#ee485d;--logo-teal:#00cdde;--logo-mint:#00e8c2;--logo-navy:#172350;--logo-green:#3db664;--logo-purple:#290b53;--logo-pink:#ff5d8c;--brand-color-1:var(--logo-coral);--brand-color-2:var(--logo-teal);--brand-color-3:var(--logo-mint);--brand-color-4:var(--logo-navy);--brand-color-5:var(--logo-green);--brand-color-6:var(--logo-purple);--brand-color-7:var(--logo-pink);--topbar-height:60px;--logo-max-height:36px;--global-content-max-width:100rem;--sidebar-width:240px;--sidebar-width-closed:63px;--sidebar-bg-color:var(--gray-6);--sidebarOpenWidth:180px;--sidebarCollapsedWidth:55px;--subnavWidth:210px;--subnavHorizontalMargin:1rem;--sidebarBackground:var(--white);--headerHeight:var(--topbar-height);--transition:cubic-bezier(1.0,0.5,0.8,1.0);--transitionTiming:0.1s;--core-theme-color:#290b53;--core-theme-color-light:rgba(41,11,83,0.75);--core-theme-color-lighter:rgba(41,11,83,0.08);--core-theme-color-dark:#000;--core-theme-color-darker:#000;--KButtonPrimaryBase:var(--core-theme-color);--KButtonPrimaryHover:var(--core-theme-color-light);--KButtonPrimaryActive:var(--core-theme-color-light);--KRadioPrimary:var(--core-theme-color);--KInputFocus:var(--core-theme-color);--SidebarIconColor:var(--core-theme-color);--SidebarLinkColor:var(--core-theme-color-darker);--SidebarLinkBGColor:var(--core-theme-color-lighter);--SidebarTitleColor:var(--core-theme-color-light);--LinkColorBase:var(--core-theme-color);--LinkColorHover:var(--core-theme-color-light);--MetricsCardBGColorHover:var(--core-theme-color-lighter);--WizardTabBGColor:var(--core-theme-color);--WizardTabTextColor:#fff;--KTabsActiveColor:var(--core-theme-color);--DataOverviewTableLinkColor:var(--core-theme-color);--MeshSelectorTitleColor:var(--core-theme-color-light);--MeshSelectorInputTextColor:var(--core-theme-color);--MeshSelectorInputBorderColor:var(--core-theme-color-lighter);--MeshSelectorInputBorderColorFocus:var(--core-theme-color-light);--LoaderProgressBarBG:var(--core-theme-color-light);--KEmptyStateContentWidth:85%}.kutil-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.kutil-img-full{width:100%}.kutil-img-fluid,.kutil-img-full{max-width:100%;height:auto}.kutil-clear-text{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale}.kutil-quotify{quotes:"“" "”" "‘" "’"}.kutil-quotify:before{content:open-quote}.kutil-quotify:after{content:close-quote}.kutil-sticky{position:-webkit-sticky;position:sticky;top:0}.kutil-sticky:after,.kutil-sticky:before{content:"";display:table}.arrow-link{text-decoration:none;color:var(--blue-4)}.arrow-link,.k-button{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.k-button{font-weight:400!important}.arrow-link:after,.k-button:after{display:inline-block;content:"›";margin-left:5px}.capitalize{display:inline-block;text-transform:capitalize}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-uppercase{text-transform:uppercase}.text-italic{font-style:italic}.font-normal{font-weight:400}.font-light{font-weight:100}.font-semibold{font-weight:500}.font-bold{font-weight:700}.badge{display:inline-block;padding:.25rem .4rem;font-size:75%;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.top-border{border-top:1px solid var(--black-10)}.bottom-border{border-bottom:1px solid var(--black-10)}.text-muted{color:var(--black-45)!important}.text-danger{color:var(--red-500)!important}.h-100{height:100%}.h-screen{min-height:100vh}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Thin.ad538a69.woff2) format("woff2"),url(../fonts/Roboto-Thin.03fb3a93.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-ThinItalic.5b4a33e1.woff2) format("woff2"),url(../fonts/Roboto-ThinItalic.4ced2a97.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Light.d26871e8.woff2) format("woff2"),url(../fonts/Roboto-Light.c8405cfa.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-LightItalic.e8eaae90.woff2) format("woff2"),url(../fonts/Roboto-LightItalic.f6dd13d5.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Regular.73f0a88b.woff2) format("woff2"),url(../fonts/Roboto-Regular.878ad715.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Italic.4357beb8.woff2) format("woff2"),url(../fonts/Roboto-Italic.6521f388.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Medium.90d16760.woff2) format("woff2"),url(../fonts/Roboto-Medium.7b225d4d.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-MediumItalic.13ec0eb5.woff2) format("woff2"),url(../fonts/Roboto-MediumItalic.5df7f053.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Bold.b52fac2b.woff2) format("woff2"),url(../fonts/Roboto-Bold.eb43b4c3.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-BoldItalic.94008e69.woff2) format("woff2"),url(../fonts/Roboto-BoldItalic.563c4bd6.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(../fonts/Roboto-Black.59eb3601.woff2) format("woff2"),url(../fonts/Roboto-Black.8f766bb9.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(../fonts/Roboto-BlackItalic.f75569f8.woff2) format("woff2"),url(../fonts/Roboto-BlackItalic.83b2c7d0.woff) format("woff");font-weight:900;font-style:italic}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Regular.a48ac416.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Medium.5a45b286.ttf) format("truetype");font-weight:500;font-style:normal}@font-face{font-family:Roboto Mono;src:url(../fonts/RobotoMono-Bold.c0c4a337.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:Material Icons;font-style:normal;font-weight:400;src:url(../fonts/MaterialIcons-Regular.e79bfd88.eot);src:local("Material Icons"),local("MaterialIcons-Regular"),url(../fonts/MaterialIcons-Regular.570eb838.woff2) format("woff2"),url(../fonts/MaterialIcons-Regular.012cf6a1.woff) format("woff"),url(../fonts/MaterialIcons-Regular.a37b0c01.ttf) format("truetype")}body{padding-top:var(--topbar-height);font-family:var(--base-font-family)}[type=button],[type=reset],[type=submit],button{-webkit-appearance:none}.title-3x{font-size:var(--type-xxxl)}.title-2x{font-size:var(--type-xxl)}.title-1x{font-size:var(--type-xl)}a:link,a:visited{color:var(--LinkColorBase);text-decoration:underline}a:active,a:focus,a:hover{color:var(--LinkColorHover)}select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:3px;border:1px solid rgba(23,130,207,.35);font-size:16px;color:#1155cb;line-height:20px;padding:10px 16px 10px 13px;background-color:#fff;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMSAxbDQgNCA0LTQiIHN0cm9rZT0iIzE3ODJDRiIgc3Ryb2tlLXdpZHRoPSIxLjUiIGZpbGw9Im5vbmUiLz48L3N2Zz4=);background-position:calc(100% - 13px) 50%;background-repeat:no-repeat}.k-button,[type=button],button{-webkit-transition:none!important;transition:none!important}.code-sample{font-family:var(--font-family-mono)}.form-container{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;padding-right:15px;padding-left:15px;margin:0 auto}@media (max-width:1200px){.form-container{-webkit-box-flex:0;-ms-flex:0 0 70%;flex:0 0 70%;max-width:70%}}@media (max-width:860px){.form-container{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}}.vue-form-generator .form-control{border:1px solid rgba(0,0,0,.12);-webkit-box-shadow:none;box-shadow:none;color:rgba(0,0,0,.7)}.form-group,.vue-form-generator .form-group{margin-bottom:1.5rem}.form-group:last-child,.vue-form-generator .form-group:last-child{margin-bottom:2rem}.vue-form-generator .field-advanced{margin-top:-.5rem;margin-bottom:.5rem}.vue-form-generator .field-advanced .form-group:last-child{margin-bottom:1rem}.top-border{padding-top:1.5rem;border-top:1px solid rgba(0,0,0,.08)}.bottom-border{padding-bottom:1.5rem;border-bottom:1px solid rgba(0,0,0,.08)}.form-control{font-size:15px;color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.12);border-radius:3px;border-width:1px}.form-control:focus{outline:none;border:1px solid #80caff}.form-control:disabled{background-color:#f7f7f7;opacity:.75}.form-control.has-error{border:1px solid #ff8280}.vue-form-generator .form-group.hide-label>label{display:none}.vue-form-generator .form-group label{font-weight:500}.form-group label{width:100%}.form-group label small{float:right;font-size:14px;font-style:italic;font-weight:400;color:rgba(0,0,0,.5)}.form-group.required>label:after{display:none}.form-group.optional>label,.form-group.semi-optional>label{position:relative;width:100%}.form-group.optional>label:after,.form-group.semi-optional>label:after{position:absolute;display:block;top:0;right:0;font-size:14px;font-style:italic;font-weight:400;color:rgba(0,0,0,.5)}.form-group.optional>label:after{content:"Optional"}.form-group.semi-optional>label:after{content:"Semi-Optional"}.vue-form-generator span.help .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiI+PHBhdGggZmlsbD0iIzAwODZFNiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNiAxMUE1IDUgMCAxMTYuMDAxLjk5OSA1IDUgMCAwMTYgMTFNNiAwYTYgNiAwIDEwMCAxMkE2IDYgMCAwMDYgMG0wIDNhMiAyIDAgMDAtMiAyaDFhMSAxIDAgMTExIDEgMSAxIDAgMDAtMSAxaDFhMiAyIDAgMTAwLTR6TTUgOWgyVjhINXYxeiIvPjwvc3ZnPg==);width:.75rem;height:.75rem}.vue-form-generator span.help .helpText{left:-108px;width:224px;padding:.5rem .75rem;color:rgba(0,0,0,.75);font-weight:400;font-size:14px;text-align:left;border:1px solid #d6d6d6;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 0 4px 0 rgba(0,0,0,.12);box-shadow:0 0 4px 0 rgba(0,0,0,.12);z-index:900}.vue-form-generator span.help .helpText:after,.vue-form-generator span.help .helpText:before{position:absolute;top:100%;left:50%;height:0;width:0;border:solid transparent;pointer-events:none;content:" "}.vue-form-generator span.help .helpText:before{border-top-color:#d6d6d6;border-width:13px;margin-left:-13px}.vue-form-generator span.help .helpText:after{border-top-color:#fff;border-width:12px;margin-left:-12px}.hint{font-size:small;margin-top:5px;margin-bottom:10px;opacity:.6}.option-field{padding-left:1.5rem;width:100%}.option-field .form-group:last-child{margin-bottom:0}.custom-control-indicator{background-color:rgba(0,0,0,.12)}.custom-control-input:checked~.custom-control-indicator{background-color:#3295fc}.custom-control-input:focus~.custom-control-indicator{-webkit-box-shadow:0 0 0 1px #fff,0 0 0 3px #3295fc;box-shadow:0 0 0 1px #fff,0 0 0 3px #3295fc}.form-group label{font-size:14px;font-weight:500;color:#262626;margin:0 0 8px 0}.form-check-input,.form-control .list-row input[type=checkbox],.form-group .field-wrap input[type=checkbox]{appearance:none;-moz-appearance:none;-webkit-appearance:none;position:relative;vertical-align:middle;display:inline-block;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-check-input:focus,.form-control .list-row input[type=checkbox]:focus,.form-group .field-wrap input[type=checkbox]:focus{outline:none}.form-check-input:before,.form-control .list-row input[type=checkbox]:before,.form-group .field-wrap input[type=checkbox]:before{content:"";display:inline-block;height:16px;width:16px;border:1px solid #bfbfbf;border-radius:2px;margin-right:5px;background:#fff}.form-check-input:checked:before,.form-control .list-row input[type=checkbox]:checked:before,.form-group .field-wrap input[type=checkbox]:checked:before{background-color:#3295fc;border-color:#3295fc}.form-check-input:checked:after,.form-control .list-row input[type=checkbox]:checked:after,.form-group .field-wrap input[type=checkbox]:checked:after{content:"";position:absolute;top:4px;left:4px;display:inline-block;height:6px;width:9px;color:#fff;border-left:2px solid;border-bottom:2px solid;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.form-check-input::-ms-check,.form-control .list-row input[type=checkbox]::-ms-check,.form-group .field-wrap input[type=checkbox]::-ms-check{display:inline-block;height:16px;width:16px;border:1px solid #bfbfbf;border-radius:2px;margin-right:5px}.form-check-input:checked::-ms-check,.form-control .list-row input[type=checkbox]:checked::-ms-check,.form-group .field-wrap input[type=checkbox]:checked::-ms-check{color:#fff;background-color:#3295fc}.form-group.required input[type=checkbox],.form-group [required=required]{-webkit-box-shadow:none;box-shadow:none}.form-control input[type=checkbox],.form-control label{vertical-align:middle;line-height:1rem}.form-inline .form-check-input{margin-top:.25rem}.vue-form-generator .form-group.field-checkbox label{margin-top:-5px}.vue-form-generator .field-switch .field-wrap input[type=checkbox]{position:absolute}.vue-form-generator .field-switch .field-wrap label{width:42px;height:20px;margin:0}.vue-form-generator .field-switch input:checked~.label{background:#2196f3;-webkit-box-shadow:none;box-shadow:none}.vue-form-generator .field-switch .label{background:#ccc}.vue-form-generator .field-switch .label:after,.vue-form-generator .field-switch .label:before{color:rgba(0,0,0,.7);text-shadow:none;margin-left:42px;font-size:14px;left:18px;font-weight:400;text-transform:none;font-family:Roboto;width:-webkit-max-content;width:-moz-max-content;width:max-content}.vue-form-generator .field-switch .handle{width:17px;height:17px}.vue-form-generator .field-switch input:checked~.handle{left:calc(100% - 18px)}.vue-form-generator .field-switch .handle:before{background:none;-webkit-box-shadow:none;box-shadow:none}.entity-status{letter-spacing:0;line-height:20px;color:var(--green-400)}.entity-status,.entity-total-updates{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.entity-total-updates{gap:2px;pointer-events:auto!important}.entity-status.is-offline{color:var(--red-600)}.entity-status.is-degraded{color:#ff8040}.entity-status.is-degraded .entity-status__dot{background-color:#ff8040}.entity-status.is-offline .entity-status__dot{background-color:var(--red-600)}.entity-status__dot{display:inline-block;width:8px;height:8px;border-radius:100%;margin-right:6px;background-color:var(--green-400);-ms-flex-negative:0;flex-shrink:0}.kong-icon--centered{display:block;margin:0 auto 10px auto;text-align:center}@media screen and (min-width:1024px){.k-card--small{max-width:65%}}.empty-state-content p{width:100%;max-width:var(--KEmptyStateContentWidth)!important}.empty-state-wrapper{padding:2rem 0!important}.k-tabs .tab-container{outline:0!important}.k-popover{z-index:1031!important}.k-popover .k-badge{display:inline}.help-icon{--i:22px;margin:0 8px}.help-icon,.help-icon a{display:inline-block;width:var(--i)}.help-icon a{height:var(--i);line-height:var(--i);border-radius:100%;color:#fff;text-decoration:none;text-align:center;font-size:12px;background-color:var(--gray-2);cursor:pointer}.custom-control-icon{display:inline-block;margin-right:5px;font-size:var(--type-lg);line-height:0;max-height:18px}.external-link-btn{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:var(--spacing-xs) var(--spacing-sm);font-family:var(--font-family-sans);font-size:1rem;font-weight:400;line-height:1.25;text-decoration:none;vertical-align:middle;border:1px solid transparent;border-radius:3px;cursor:pointer;color:#fff!important;background-color:var(--KButtonPrimaryBase);text-decoration:none!important}.external-link-btn:after{display:inline-block;content:"\203A";margin-left:5px}.external-link-btn:hover{background-color:#0089eb}.main-content{padding:44px;-webkit-transition:var(--transitionTiming) margin var(--transition);transition:var(--transitionTiming) margin var(--transition)}.page{max-width:76rem;margin:0 auto}.main-content-container{max-width:var(--global-content-max-width);margin:0 auto}.welcome{max-width:640px;margin-left:auto;margin-right:auto}.fade-enter-active,.fade-leave-active{-webkit-transition:opacity 0 linear;transition:opacity 0 linear}.fade-enter,.fade-leave-to{opacity:0}
\ No newline at end of file
diff --git a/app/kuma-ui/pkg/resources/data/index.html b/app/kuma-ui/pkg/resources/data/index.html
index 3267b2b42..6a6d20546 100644
--- a/app/kuma-ui/pkg/resources/data/index.html
+++ b/app/kuma-ui/pkg/resources/data/index.html
@@ -1,1 +1,1 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.png"><title>Kuma Manager</title><link href="css/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~diagnostics~fault-injections~heal~d19abb4a.f64db730.css" rel="prefetch"><link href="css/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~fault-injections~health-checks~me~68bd0342.9a83e651.css" rel="prefetch"><link href="css/dataplanes~dataplanes-gateway~dataplanes-standard.82e28a0b.css" rel="prefetch"><link href="css/diagnostics.433e2612.css" rel="prefetch"><link href="css/global-overview.5d06a342.css" rel="prefetch"><link href="css/meshes.5b9b5f28.css" rel="prefetch"><link href="css/onboarding-complete.cf73973d.css" rel="prefetch"><link href="css/onboarding-get-started.d50882ac.css" rel="prefetch"><link href="css/shell.643cf4c5.css" rel="prefetch"><link href="css/traffic-permissions.cc702109.css" rel="prefetch"><link href="css/wizard-dataplane-kubernetes.e438dd69.css" rel="prefetch"><link href="css/wizard-dataplane-kubernetes~wizard-dataplane-universal~wizard-mesh.23737d03.css" rel="prefetch"><link href="css/wizard-dataplane-universal.51a22abb.css" rel="prefetch"><link href="css/zoneingresses.d3f3cf9c.css" rel="prefetch"><link href="css/zones.7b616202.css" rel="prefetch"><link href="js/canvg.js?t=e4c83c5b" rel="prefetch"><link href="js/circuit-breakers.js?t=fa3af63d" rel="prefetch"><link href="js/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~diagnostics~fault-injections~heal~d19abb4a.js?t=0831e162" rel="prefetch"><link href="js/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~fault-injections~health-checks~me~68bd0342.js?t=9ba9f676" rel="prefetch"><link href="js/dataplanes-gateway.js?t=df8be9ce" rel="prefetch"><link href="js/dataplanes-standard.js?t=2f493ac5" rel="prefetch"><link href="js/dataplanes.js?t=7e478279" rel="prefetch"><link href="js/dataplanes~dataplanes-gateway~dataplanes-standard.js?t=a8437f8f" rel="prefetch"><link href="js/dataplanes~dataplanes-gateway~dataplanes-standard~zoneingresses~zones.js?t=f6b5f2af" rel="prefetch"><link href="js/diagnostics.js?t=4916ac1c" rel="prefetch"><link href="js/fault-injections.js?t=718a1372" rel="prefetch"><link href="js/global-overview.js?t=c73fce45" rel="prefetch"><link href="js/health-checks.js?t=0ff12f8b" rel="prefetch"><link href="js/meshes.js?t=2e9fd6b1" rel="prefetch"><link href="js/not-found.js?t=9f78186f" rel="prefetch"><link href="js/onboarding-complete.js?t=98dfbe1c" rel="prefetch"><link href="js/onboarding-get-started.js?t=d5b757dd" rel="prefetch"><link href="js/pdfmake.js?t=a875cb2a" rel="prefetch"><link href="js/proxy-templates.js?t=a0e8bf81" rel="prefetch"><link href="js/rate-limits.js?t=741ffe66" rel="prefetch"><link href="js/retries.js?t=9ac5e704" rel="prefetch"><link href="js/shell-empty.js?t=e6379069" rel="prefetch"><link href="js/shell.js?t=11e05f7c" rel="prefetch"><link href="js/timeouts.js?t=d636d748" rel="prefetch"><link href="js/traffic-logs.js?t=6cf0824e" rel="prefetch"><link href="js/traffic-permissions.js?t=f04be247" rel="prefetch"><link href="js/traffic-routes.js?t=12d06b41" rel="prefetch"><link href="js/traffic-traces.js?t=99649b60" rel="prefetch"><link href="js/wizard-dataplane-kubernetes.js?t=69bffe1d" rel="prefetch"><link href="js/wizard-dataplane-kubernetes~wizard-dataplane-universal~wizard-mesh.js?t=e43514ac" rel="prefetch"><link href="js/wizard-dataplane-universal.js?t=34b6b2ce" rel="prefetch"><link href="js/wizard-mesh.js?t=0a9c33b5" rel="prefetch"><link href="js/xlsx.js?t=cc99b27a" rel="prefetch"><link href="js/zoneingresses.js?t=a765e0fc" rel="prefetch"><link href="js/zones.js?t=f14fd7ec" rel="prefetch"><link href="css/app.ba88165d.css" rel="preload" as="style"><link href="css/chunk-vendors.13589a7d.css" rel="preload" as="style"><link href="js/app.542d30f3.js" rel="preload" as="script"><link href="js/chunk-vendors.js?t=434568fe" rel="preload" as="script"><link href="css/chunk-vendors.13589a7d.css" rel="stylesheet"><link href="css/app.ba88165d.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but Kuma Manager doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.js?t=434568fe"></script><script src="js/app.542d30f3.js"></script></body></html>
\ No newline at end of file
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.png"><title>Kuma Manager</title><link href="css/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~diagnostics~fault-injections~heal~d19abb4a.f64db730.css" rel="prefetch"><link href="css/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~fault-injections~health-checks~me~68bd0342.9a83e651.css" rel="prefetch"><link href="css/dataplanes~dataplanes-gateway~dataplanes-standard.82e28a0b.css" rel="prefetch"><link href="css/diagnostics.433e2612.css" rel="prefetch"><link href="css/global-overview.5d06a342.css" rel="prefetch"><link href="css/meshes.5b9b5f28.css" rel="prefetch"><link href="css/onboarding-complete.cf73973d.css" rel="prefetch"><link href="css/onboarding-get-started.d50882ac.css" rel="prefetch"><link href="css/shell.643cf4c5.css" rel="prefetch"><link href="css/traffic-permissions.cc702109.css" rel="prefetch"><link href="css/wizard-dataplane-kubernetes.e438dd69.css" rel="prefetch"><link href="css/wizard-dataplane-kubernetes~wizard-dataplane-universal~wizard-mesh.23737d03.css" rel="prefetch"><link href="css/wizard-dataplane-universal.51a22abb.css" rel="prefetch"><link href="css/zoneingresses.d3f3cf9c.css" rel="prefetch"><link href="css/zones.7b616202.css" rel="prefetch"><link href="js/canvg.js?t=e4c83c5b" rel="prefetch"><link href="js/circuit-breakers.js?t=fa3af63d" rel="prefetch"><link href="js/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~diagnostics~fault-injections~heal~d19abb4a.js?t=0831e162" rel="prefetch"><link href="js/circuit-breakers~dataplanes~dataplanes-gateway~dataplanes-standard~fault-injections~health-checks~me~68bd0342.js?t=9ba9f676" rel="prefetch"><link href="js/dataplanes-gateway.js?t=df8be9ce" rel="prefetch"><link href="js/dataplanes-standard.js?t=2f493ac5" rel="prefetch"><link href="js/dataplanes.js?t=7e478279" rel="prefetch"><link href="js/dataplanes~dataplanes-gateway~dataplanes-standard.js?t=a8437f8f" rel="prefetch"><link href="js/dataplanes~dataplanes-gateway~dataplanes-standard~zoneingresses~zones.js?t=f6b5f2af" rel="prefetch"><link href="js/diagnostics.js?t=4916ac1c" rel="prefetch"><link href="js/fault-injections.js?t=718a1372" rel="prefetch"><link href="js/global-overview.js?t=c73fce45" rel="prefetch"><link href="js/health-checks.js?t=0ff12f8b" rel="prefetch"><link href="js/meshes.js?t=2e9fd6b1" rel="prefetch"><link href="js/not-found.js?t=9f78186f" rel="prefetch"><link href="js/onboarding-complete.js?t=98dfbe1c" rel="prefetch"><link href="js/onboarding-get-started.js?t=d5b757dd" rel="prefetch"><link href="js/pdfmake.js?t=a875cb2a" rel="prefetch"><link href="js/proxy-templates.js?t=a0e8bf81" rel="prefetch"><link href="js/rate-limits.js?t=741ffe66" rel="prefetch"><link href="js/retries.js?t=9ac5e704" rel="prefetch"><link href="js/shell-empty.js?t=e6379069" rel="prefetch"><link href="js/shell.js?t=11e05f7c" rel="prefetch"><link href="js/timeouts.js?t=d636d748" rel="prefetch"><link href="js/traffic-logs.js?t=6cf0824e" rel="prefetch"><link href="js/traffic-permissions.js?t=f04be247" rel="prefetch"><link href="js/traffic-routes.js?t=12d06b41" rel="prefetch"><link href="js/traffic-traces.js?t=99649b60" rel="prefetch"><link href="js/wizard-dataplane-kubernetes.js?t=69bffe1d" rel="prefetch"><link href="js/wizard-dataplane-kubernetes~wizard-dataplane-universal~wizard-mesh.js?t=e43514ac" rel="prefetch"><link href="js/wizard-dataplane-universal.js?t=34b6b2ce" rel="prefetch"><link href="js/wizard-mesh.js?t=0a9c33b5" rel="prefetch"><link href="js/xlsx.js?t=cc99b27a" rel="prefetch"><link href="js/zoneingresses.js?t=a765e0fc" rel="prefetch"><link href="js/zones.js?t=f14fd7ec" rel="prefetch"><link href="css/app.e3a402b2.css" rel="preload" as="style"><link href="css/chunk-vendors.13589a7d.css" rel="preload" as="style"><link href="js/app.542d30f3.js" rel="preload" as="script"><link href="js/chunk-vendors.js?t=434568fe" rel="preload" as="script"><link href="css/chunk-vendors.13589a7d.css" rel="stylesheet"><link href="css/app.e3a402b2.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but Kuma Manager doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.js?t=434568fe"></script><script src="js/app.542d30f3.js"></script></body></html>
\ No newline at end of file
diff --git a/app/kumactl/cmd/root.go b/app/kumactl/cmd/root.go
index c215b02c7..81ad8a01e 100644
--- a/app/kumactl/cmd/root.go
+++ b/app/kumactl/cmd/root.go
@@ -74,10 +74,15 @@ func NewRootCmd(root *kumactl_cmd.RootContext) *cobra.Command {
 			if err != nil {
 				kumactlLog.Error(err, "Unable to get index client")
 			} else {
-				kumaBuildVersion, _ = client.GetVersion(context.Background())
+				kumaBuildVersion, err = client.GetVersion(context.Background())
+				if err != nil {
+					kumactlLog.Error(err, "Unable to retrieve server version")
+				}
 			}
 
-			if kumaBuildVersion != nil && (kumaBuildVersion.Version != kuma_version.Build.Version || kumaBuildVersion.Tagline != kuma_version.Product) {
+			if kumaBuildVersion == nil {
+				cmd.PrintErr("WARNING: Unable to confirm the server supports this kumactl version\n")
+			} else if kumaBuildVersion.Version != kuma_version.Build.Version || kumaBuildVersion.Tagline != kuma_version.Product {
 				cmd.PrintErr("WARNING: You are using kumactl version " + kuma_version.Build.Version + " for " + kuma_version.Product + ", but the server returned version: " + kumaBuildVersion.Tagline + " " + kumaBuildVersion.Version + "\n")
 			}
 			return nil
diff --git a/go.mod b/go.mod
index d4949ade1..730a02515 100644
--- a/go.mod
+++ b/go.mod
@@ -25,8 +25,8 @@ require (
 	github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69
 	github.com/iancoleman/orderedmap v0.2.0
 	github.com/kelseyhightower/envconfig v1.4.0
-	github.com/kumahq/kuma/api v0.0.0-00010101000000-000000000000
 	github.com/kumahq/kuma/pkg/transparentproxy/istio v0.0.0-00010101000000-000000000000
+	github.com/kumahq/protoc-gen-kumadoc v0.1.7
 	github.com/lib/pq v1.10.2
 	github.com/miekg/dns v1.1.42
 	github.com/onsi/ginkgo v1.16.4
@@ -65,8 +65,6 @@ require (
 )
 
 replace (
-	github.com/kumahq/kuma/api => ./api
 	github.com/kumahq/kuma/pkg/transparentproxy/istio => ./pkg/transparentproxy/istio
-
 	github.com/prometheus/prometheus => ./vendored/github.com/prometheus/prometheus
 )
diff --git a/go.sum b/go.sum
index bacb98fd1..02b4ddd85 100644
--- a/go.sum
+++ b/go.sum
@@ -1862,7 +1862,6 @@ 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.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
diff --git a/mk/build.mk b/mk/build.mk
index d65dc477e..a677ce4a3 100644
--- a/mk/build.mk
+++ b/mk/build.mk
@@ -32,6 +32,10 @@ COREDNS_PLUGIN_CFG_PATH ?= $(TOP)/tools/builds/coredns/templates/plugin.cfg
 # List of binaries that we have release build rules for.
 BUILD_RELEASE_BINARIES := kuma-cp kuma-dp kumactl kuma-prometheus-sd coredns
 
+# Setting this variable to any value other than 'N', enables the experimental Kuma
+# gateway plugin. Experimental means "for experiments", NOT "for production".
+BUILD_WITH_EXPERIMENTAL_GATEWAY ?= N
+
 .PHONY: build
 build: build/release build/test
 
@@ -55,7 +59,11 @@ build/test/linux-amd64:
 
 .PHONY: build/kuma-cp
 build/kuma-cp: ## Dev: Build `Control Plane` binary
+ifeq ($(BUILD_WITH_EXPERIMENTAL_GATEWAY),N)
 	$(GO_BUILD) -o ${BUILD_ARTIFACTS_DIR}/kuma-cp/kuma-cp ./app/kuma-cp
+else
+	$(GO_BUILD) -tags gateway -o ${BUILD_ARTIFACTS_DIR}/kuma-cp/kuma-cp ./app/kuma-cp
+endif
 
 .PHONY: build/kuma-dp
 build/kuma-dp: ## Dev: Build `kuma-dp` binary
diff --git a/pkg/core/managers/apis/dataplane/dataplane_manager.go b/pkg/core/managers/apis/dataplane/dataplane_manager.go
index e490ca5fd..fe42de4d9 100644
--- a/pkg/core/managers/apis/dataplane/dataplane_manager.go
+++ b/pkg/core/managers/apis/dataplane/dataplane_manager.go
@@ -85,7 +85,7 @@ func (m *dataplaneManager) setInboundsClusterTag(dp *core_mesh.DataplaneResource
 }
 
 func (m *dataplaneManager) setGatewayClusterTag(dp *core_mesh.DataplaneResource) {
-	if m.zone == "" || dp.Spec.Networking == nil || dp.Spec.Networking.Gateway == nil {
+	if m.zone == "" || dp.Spec.GetNetworking().GetGateway() == nil {
 		return
 	}
 	if dp.Spec.Networking.Gateway.Tags == nil {
diff --git a/pkg/core/resources/apis/mesh/dataplane_overview_helpers.go b/pkg/core/resources/apis/mesh/dataplane_overview_helpers.go
index 4fc33ba41..ae43957c6 100644
--- a/pkg/core/resources/apis/mesh/dataplane_overview_helpers.go
+++ b/pkg/core/resources/apis/mesh/dataplane_overview_helpers.go
@@ -31,7 +31,7 @@ func (t *DataplaneOverviewResource) GetStatus() (Status, []string) {
 
 	allInboundsOffline := len(errs) == len(t.Spec.Dataplane.Networking.Inbound)
 	allInboundsOnline := len(errs) == 0
-	if t.Spec.Dataplane.IsGateway() {
+	if t.Spec.Dataplane.IsDelegatedGateway() {
 		allInboundsOffline = false
 		allInboundsOnline = true
 	}
diff --git a/pkg/core/resources/apis/mesh/dataplane_validator.go b/pkg/core/resources/apis/mesh/dataplane_validator.go
index ca11effbe..8bde3be1a 100644
--- a/pkg/core/resources/apis/mesh/dataplane_validator.go
+++ b/pkg/core/resources/apis/mesh/dataplane_validator.go
@@ -11,15 +11,60 @@ import (
 	"github.com/kumahq/kuma/pkg/core/validators"
 )
 
+// allowBuiltinGateways specifies whether the dataplanes of builtin
+// gateway type are allowed. This is controlled by the +gateway build
+// conditional.
+var allowBuiltinGateways = false
+
 func (d *DataplaneResource) Validate() error {
 	var err validators.ValidationError
-	if d.Spec.IsIngress() {
+
+	net := validators.RootedAt("networking")
+
+	switch {
+	case d.Spec.IsIngress():
 		err.Add(validateIngressNetworking(d.Spec.GetNetworking()))
-		err.Add(validateIngress(validators.RootedAt("networking").Field("ingress"), d.Spec.GetNetworking().GetIngress()))
-	} else {
+		err.Add(validateIngress(net.Field("ingress"), d.Spec.GetNetworking().GetIngress()))
+
+	case d.Spec.IsDelegatedGateway():
+		if len(d.Spec.GetNetworking().GetInbound()) > 0 {
+			err.AddViolationAt(net.Field("inbound"),
+				"inbound cannot be defined for delegated gateways")
+		}
+
+		err.AddErrorAt(net.Field("gateway"), validateGateway(d.Spec.GetNetworking().GetGateway()))
+		err.Add(validateNetworking(d.Spec.GetNetworking()))
+		err.Add(validateProbes(d.Spec.GetProbes()))
+
+	case d.Spec.IsBuiltinGateway():
+		if !allowBuiltinGateways {
+			err.AddViolationAt(net.Field("gateway"), "unsupported gateway type")
+			return err.OrNil()
+		}
+
+		if len(d.Spec.GetNetworking().GetInbound()) > 0 {
+			err.AddViolationAt(net.Field("inbound"), "inbound cannot be defined for builtin gateways")
+		}
+
+		if len(d.Spec.GetNetworking().GetOutbound()) > 0 {
+			err.AddViolationAt(net.Field("outbound"), "outbound cannot be defined for builtin gateways")
+		}
+
+		if d.Spec.GetProbes() != nil {
+			err.AddViolationAt(net.Field("probes"), "probes cannot be defined for builtin gateways")
+		}
+
+		err.AddErrorAt(net.Field("gateway"), validateGateway(d.Spec.GetNetworking().GetGateway()))
+		err.Add(validateNetworking(d.Spec.GetNetworking()))
+
+	default:
+		if len(d.Spec.GetNetworking().GetInbound()) == 0 {
+			err.AddViolationAt(net, "has to contain at least one inbound interface or gateway")
+		}
 		err.Add(validateNetworking(d.Spec.GetNetworking()))
 		err.Add(validateProbes(d.Spec.GetProbes()))
 	}
+
 	return err.OrNil()
 }
 
@@ -30,20 +75,14 @@ func (d *DataplaneResource) Validate() error {
 func validateNetworking(networking *mesh_proto.Dataplane_Networking) validators.ValidationError {
 	var err validators.ValidationError
 	path := validators.RootedAt("networking")
-	if len(networking.GetInbound()) == 0 && networking.Gateway == nil {
-		err.AddViolationAt(path, "has to contain at least one inbound interface or gateway")
-	}
-	if len(networking.GetInbound()) > 0 && networking.Gateway != nil {
-		err.AddViolationAt(path, "inbound cannot be defined both with gateway")
-	}
 	err.Add(validateAddress(path, networking.Address))
-	if networking.Gateway != nil {
-		result := validateGateway(networking.Gateway)
-		err.AddErrorAt(path.Field("gateway"), result)
-	}
 	for i, inbound := range networking.GetInbound() {
+		field := path.Field("inbound").Index(i)
 		result := validateInbound(inbound, networking.Address)
-		err.AddErrorAt(path.Field("inbound").Index(i), result)
+		err.AddErrorAt(field, result)
+		if _, exist := inbound.Tags[mesh_proto.ServiceTag]; !exist {
+			err.AddViolationAt(field.Field("tags").Key(mesh_proto.ServiceTag), `tag has to exist`)
+		}
 	}
 	for i, outbound := range networking.GetOutbound() {
 		result := validateOutbound(outbound)
@@ -179,9 +218,6 @@ func validateInbound(inbound *mesh_proto.Dataplane_Networking_Inbound, dpAddress
 			}
 		}
 	}
-	if _, exist := inbound.Tags[mesh_proto.ServiceTag]; !exist {
-		result.AddViolationAt(validators.RootedAt("tags").Key(mesh_proto.ServiceTag), `tag has to exist`)
-	}
 	if value, exist := inbound.Tags[mesh_proto.ProtocolTag]; exist {
 		if ParseProtocol(value) == ProtocolUnknown {
 			result.AddViolationAt(validators.RootedAt("tags").Key(mesh_proto.ProtocolTag), fmt.Sprintf("tag %q has an invalid value %q. %s", mesh_proto.ProtocolTag, value, AllowedValuesHint(SupportedProtocols.Strings()...)))
diff --git a/pkg/core/resources/apis/mesh/dataplane_validator_gateway.go b/pkg/core/resources/apis/mesh/dataplane_validator_gateway.go
new file mode 100644
index 000000000..fae7228a7
--- /dev/null
+++ b/pkg/core/resources/apis/mesh/dataplane_validator_gateway.go
@@ -0,0 +1,7 @@
+// +build gateway
+
+package mesh
+
+func init() {
+	allowBuiltinGateways = true
+}
diff --git a/pkg/kds/util/resource.go b/pkg/kds/util/resource.go
index e0359abbd..0d1c42bc1 100644
--- a/pkg/kds/util/resource.go
+++ b/pkg/kds/util/resource.go
@@ -66,7 +66,7 @@ func AddSuffixToNames(rs []model.Resource, suffix string) {
 
 func ZoneTag(r model.Resource) string {
 	dp := r.GetSpec().(*mesh_proto.Dataplane)
-	if dp.IsGateway() {
+	if dp.GetNetworking().GetGateway() != nil {
 		return dp.GetNetworking().GetGateway().GetTags()[mesh_proto.ZoneTag]
 	}
 	return dp.GetNetworking().GetInbound()[0].GetTags()[mesh_proto.ZoneTag]
diff --git a/pkg/plugins/runtime/k8s/controllers/pod_converter.go b/pkg/plugins/runtime/k8s/controllers/pod_converter.go
index 7cb713a89..ef34d7f2f 100644
--- a/pkg/plugins/runtime/k8s/controllers/pod_converter.go
+++ b/pkg/plugins/runtime/k8s/controllers/pod_converter.go
@@ -172,6 +172,7 @@ func GatewayFor(clusterName string, pod *kube_core.Pod, services []*kube_core.Se
 		return nil, err
 	}
 	return &mesh_proto.Dataplane_Networking_Gateway{
+		Type: mesh_proto.Dataplane_Networking_Gateway_DELEGATED,
 		Tags: interfaces[0].Tags, // InboundInterfacesFor() returns either a non-empty list or an error
 	}, nil
 }
diff --git a/pkg/xds/bootstrap/template_v3.go b/pkg/xds/bootstrap/template_v3.go
index 02435da2c..5545d6253 100644
--- a/pkg/xds/bootstrap/template_v3.go
+++ b/pkg/xds/bootstrap/template_v3.go
@@ -159,7 +159,10 @@ static_resources:
     upstream_connection_options:
       # configure a TCP keep-alive to detect and reconnect to the admin
       # server in the event of a TCP socket half open connection
-      tcp_keepalive: {}
+      tcp_keepalive:
+        keepalive_probes: 3
+        keepalive_time: 10
+        keepalive_interval: 10
     load_assignment:
       cluster_name: access_log_sink
       endpoints:
@@ -176,7 +179,10 @@ static_resources:
     upstream_connection_options:
       # configure a TCP keep-alive to detect and reconnect to the admin
       # server in the event of a TCP socket half open connection
-      tcp_keepalive: {}
+      tcp_keepalive:
+        keepalive_probes: 3
+        keepalive_time: 10
+        keepalive_interval: 10
     load_assignment:
       cluster_name: ads_cluster
       endpoints:
diff --git a/pkg/xds/server/callbacks/dataplane_status_tracker.go b/pkg/xds/server/callbacks/dataplane_status_tracker.go
index 181b91d93..9315665bf 100644
--- a/pkg/xds/server/callbacks/dataplane_status_tracker.go
+++ b/pkg/xds/server/callbacks/dataplane_status_tracker.go
@@ -16,7 +16,7 @@ import (
 	util_xds "github.com/kumahq/kuma/pkg/util/xds"
 )
 
-var statusTrackerLog = core.Log.WithName("xds").WithName("statusTracker")
+var statusTrackerLog = core.Log.WithName("xds").WithName("status-tracker")
 
 type DataplaneStatusTracker interface {
 	util_xds.Callbacks
diff --git a/pkg/xds/sync/dataplane_watchdog.go b/pkg/xds/sync/dataplane_watchdog.go
index 449100276..cd538c211 100644
--- a/pkg/xds/sync/dataplane_watchdog.go
+++ b/pkg/xds/sync/dataplane_watchdog.go
@@ -122,7 +122,10 @@ func (d *DataplaneWatchdog) syncDataplane() error {
 
 // syncIngress synces state of Ingress Dataplane. Notice that it does not use Mesh Hash yet because Ingress supports many Meshes.
 func (d *DataplaneWatchdog) syncIngress() error {
-	envoyCtx := d.xdsContextBuilder.buildContext(d.key)
+	envoyCtx, err := d.xdsContextBuilder.buildContext(d.key)
+	if err != nil {
+		return err
+	}
 	proxy, err := d.ingressProxyBuilder.build(d.key)
 	if err != nil {
 		return err
diff --git a/pkg/xds/sync/xds_context_builder.go b/pkg/xds/sync/xds_context_builder.go
index 37dee40ff..69baead94 100644
--- a/pkg/xds/sync/xds_context_builder.go
+++ b/pkg/xds/sync/xds_context_builder.go
@@ -3,6 +3,8 @@ package sync
 import (
 	"context"
 
+	"github.com/pkg/errors"
+
 	"github.com/kumahq/kuma/pkg/core/dns/lookup"
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	"github.com/kumahq/kuma/pkg/core/resources/manager"
@@ -40,7 +42,10 @@ func newXDSContextBuilder(
 
 func (c *xdsContextBuilder) buildMeshedContext(dpKey core_model.ResourceKey, meshHash string) (*xds_context.Context, error) {
 	ctx := context.Background()
-	xdsCtx := c.buildContext(dpKey)
+	xdsCtx, err := c.buildContext(dpKey)
+	if err != nil {
+		return nil, err
+	}
 
 	mesh := core_mesh.NewMeshResource()
 	if err := c.resManager.Get(ctx, mesh, core_store.GetByKey(dpKey.Mesh, core_model.NoMesh)); err != nil {
@@ -59,11 +64,15 @@ func (c *xdsContextBuilder) buildMeshedContext(dpKey core_model.ResourceKey, mes
 	return xdsCtx, nil
 }
 
-func (c *xdsContextBuilder) buildContext(dpKey core_model.ResourceKey) *xds_context.Context {
+func (c *xdsContextBuilder) buildContext(dpKey core_model.ResourceKey) (*xds_context.Context, error) {
+	connectionInfo := c.connectionInfoTracker.ConnectionInfo(dpKey)
+	if connectionInfo == nil {
+		return nil, errors.New("connection info is not found")
+	}
 	return &xds_context.Context{
 		ControlPlane:     c.cpContext,
-		ConnectionInfo:   *c.connectionInfoTracker.ConnectionInfo(dpKey), // todo handle nil
+		ConnectionInfo:   *connectionInfo,
 		Mesh:             xds_context.MeshContext{},
 		EnvoyAdminClient: c.envoyAdminClient,
-	}
+	}, nil
 }


Test patch:
diff --git a/api/mesh/v1alpha1/dataplane_helpers_test.go b/api/mesh/v1alpha1/dataplane_helpers_test.go
index 06374de1b..de5b90044 100644
--- a/api/mesh/v1alpha1/dataplane_helpers_test.go
+++ b/api/mesh/v1alpha1/dataplane_helpers_test.go
@@ -193,7 +193,7 @@ var _ = Describe("Dataplane_Networking_Outbound", func() {
 	}
 	DescribeTable("MatchTags()",
 		func(given testCase) {
-			//given
+			// given
 			outbound := Dataplane_Networking_Outbound{
 				Service: given.serviceTag,
 			}
@@ -362,7 +362,8 @@ var _ = Describe("Dataplane classification", func() {
 			dp := Dataplane{
 				Networking: &Dataplane_Networking{},
 			}
-			Expect(dp.IsGateway()).To(BeFalse())
+			Expect(dp.IsDelegatedGateway()).To(BeFalse())
+			Expect(dp.IsBuiltinGateway()).To(BeFalse())
 			Expect(dp.IsIngress()).To(BeFalse())
 		})
 	})
@@ -374,7 +375,38 @@ var _ = Describe("Dataplane classification", func() {
 					Gateway: &Dataplane_Networking_Gateway{},
 				},
 			}
-			Expect(gw.IsGateway()).To(BeTrue())
+			Expect(gw.IsDelegatedGateway()).To(BeTrue())
+			Expect(gw.IsBuiltinGateway()).To(BeFalse())
+			Expect(gw.IsIngress()).To(BeFalse())
+		})
+	})
+
+	Describe("with delegated gateway networking", func() {
+		It("should be a gateway", func() {
+			gw := Dataplane{
+				Networking: &Dataplane_Networking{
+					Gateway: &Dataplane_Networking_Gateway{
+						Type: Dataplane_Networking_Gateway_DELEGATED,
+					},
+				},
+			}
+			Expect(gw.IsDelegatedGateway()).To(BeTrue())
+			Expect(gw.IsBuiltinGateway()).To(BeFalse())
+			Expect(gw.IsIngress()).To(BeFalse())
+		})
+	})
+
+	Describe("with builtin gateway networking", func() {
+		It("should be a gateway", func() {
+			gw := Dataplane{
+				Networking: &Dataplane_Networking{
+					Gateway: &Dataplane_Networking_Gateway{
+						Type: Dataplane_Networking_Gateway_BUILTIN,
+					},
+				},
+			}
+			Expect(gw.IsDelegatedGateway()).To(BeFalse())
+			Expect(gw.IsBuiltinGateway()).To(BeTrue())
 			Expect(gw.IsIngress()).To(BeFalse())
 		})
 	})
@@ -386,7 +418,8 @@ var _ = Describe("Dataplane classification", func() {
 					Ingress: &Dataplane_Networking_Ingress{},
 				},
 			}
-			Expect(in.IsGateway()).To(BeFalse())
+			Expect(in.IsDelegatedGateway()).To(BeFalse())
+			Expect(in.IsBuiltinGateway()).To(BeFalse())
 			Expect(in.IsIngress()).To(BeTrue())
 		})
 	})
@@ -456,7 +489,7 @@ var _ = Describe("TagSelector", func() {
 				// when
 				match := TagSelector(given.tags).Matches(dpTags)
 
-				//then
+				// then
 				Expect(match).To(Equal(given.match))
 			},
 			Entry("should match 0 tags", testCase{
diff --git a/api/mesh/v1alpha1/dataplane_test.go b/api/mesh/v1alpha1/dataplane_test.go
index 5d6bde453..2329f8b7d 100644
--- a/api/mesh/v1alpha1/dataplane_test.go
+++ b/api/mesh/v1alpha1/dataplane_test.go
@@ -80,7 +80,7 @@ var _ = Describe("Dataplane", func() {
 				// given
 				var pretty bytes.Buffer
 				// when
-				json.Indent(&pretty, actual, "", "  ")
+				Expect(json.Indent(&pretty, actual, "", "  ")).To(Succeed())
 				// and
 				Expect(pretty.String()).To(Equal(given.expected))
 			},
diff --git a/app/kumactl/cmd/apply/apply_test.go b/app/kumactl/cmd/apply/apply_test.go
index 21747959d..653cd7276 100644
--- a/app/kumactl/cmd/apply/apply_test.go
+++ b/app/kumactl/cmd/apply/apply_test.go
@@ -16,8 +16,6 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 
@@ -31,6 +29,7 @@ import (
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	"github.com/kumahq/kuma/pkg/test/resources/model"
 	test_store "github.com/kumahq/kuma/pkg/test/store"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl apply", func() {
@@ -44,7 +43,7 @@ var _ = Describe("kumactl apply", func() {
 				NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 					return store, nil
 				},
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 		store = core_store.NewPaginationStore(memory_resources.NewStore())
diff --git a/app/kumactl/cmd/completion/completion_test.go b/app/kumactl/cmd/completion/completion_test.go
index b9da826fd..a216e8511 100644
--- a/app/kumactl/cmd/completion/completion_test.go
+++ b/app/kumactl/cmd/completion/completion_test.go
@@ -8,7 +8,8 @@ import (
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
+
 	. "github.com/kumahq/kuma/pkg/test/matchers"
 )
 
@@ -30,7 +31,7 @@ var _ = Describe("kumactl completion", func() {
 	DescribeTable("should generate completion code",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"completion"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/config/config_control_planes_add_test.go b/app/kumactl/cmd/config/config_control_planes_add_test.go
index bbcbc4ad5..bc040c98e 100644
--- a/app/kumactl/cmd/config/config_control_planes_add_test.go
+++ b/app/kumactl/cmd/config/config_control_planes_add_test.go
@@ -14,12 +14,10 @@ import (
 	"time"
 	"unicode"
 
-	"github.com/kumahq/kuma/pkg/version"
-
 	"github.com/kumahq/kuma/app/kumactl/pkg/config"
 	"github.com/kumahq/kuma/pkg/api-server/types"
-
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
+	"github.com/kumahq/kuma/pkg/version"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
@@ -47,7 +45,7 @@ var _ = Describe("kumactl config control-planes add", func() {
 	var outbuf *bytes.Buffer
 
 	BeforeEach(func() {
-		rootCmd = cmd.DefaultRootCmd()
+		rootCmd = test.DefaultTestingRootCmd()
 
 		// Different versions of cobra might emit errors to stdout
 		// or stderr. It's too fragile to depend on precidely what
@@ -70,7 +68,7 @@ var _ = Describe("kumactl config control-planes add", func() {
 			// then
 			Expect(err.Error()).To(MatchRegexp(requiredFlagNotSet("name")))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: required flag(s) "address", "name" not set
+			Expect(outbuf.String()).To(ContainSubstring(`Error: required flag(s) "address", "name" not set
 `))
 		})
 
@@ -84,7 +82,7 @@ var _ = Describe("kumactl config control-planes add", func() {
 			// then
 			Expect(err.Error()).To(MatchRegexp(requiredFlagNotSet("address")))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: required flag(s) "address" not set
+			Expect(outbuf.String()).To(ContainSubstring(`Error: required flag(s) "address" not set
 `))
 		})
 
diff --git a/app/kumactl/cmd/config/config_control_planes_list_test.go b/app/kumactl/cmd/config/config_control_planes_list_test.go
index d4a37fde9..65a52dbaa 100644
--- a/app/kumactl/cmd/config/config_control_planes_list_test.go
+++ b/app/kumactl/cmd/config/config_control_planes_list_test.go
@@ -6,7 +6,7 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
@@ -16,7 +16,7 @@ var _ = Describe("kumactl config control-planes list", func() {
 
 	It("should display Control Planes from a given configuration file", func() {
 		// setup
-		rootCmd := cmd.DefaultRootCmd()
+		rootCmd := test.DefaultTestingRootCmd()
 		buf := &bytes.Buffer{}
 		rootCmd.SetOut(buf)
 
diff --git a/app/kumactl/cmd/config/config_control_planes_remove_test.go b/app/kumactl/cmd/config/config_control_planes_remove_test.go
index ddda1f4c4..05a731c80 100644
--- a/app/kumactl/cmd/config/config_control_planes_remove_test.go
+++ b/app/kumactl/cmd/config/config_control_planes_remove_test.go
@@ -8,7 +8,7 @@ import (
 	"strings"
 	"unicode"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
@@ -36,7 +36,7 @@ var _ = Describe("kumactl config control-planes remove", func() {
 	var outbuf *bytes.Buffer
 
 	BeforeEach(func() {
-		rootCmd = cmd.DefaultRootCmd()
+		rootCmd = test.DefaultTestingRootCmd()
 
 		// Different versions of cobra might emit errors to stdout
 		// or stderr. It's too fragile to depend on precidely what
@@ -59,7 +59,7 @@ var _ = Describe("kumactl config control-planes remove", func() {
 			// then
 			Expect(err.Error()).To(MatchRegexp(requiredFlagNotSet("name")))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: required flag(s) "name" not set
+			Expect(outbuf.String()).To(ContainSubstring(`Error: required flag(s) "name" not set
 `))
 		})
 
@@ -73,7 +73,7 @@ var _ = Describe("kumactl config control-planes remove", func() {
 			// then
 			Expect(err).To(MatchError(`there is no Control Plane with name "example"`))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: there is no Control Plane with name "example"
+			Expect(outbuf.String()).To(ContainSubstring(`Error: there is no Control Plane with name "example"
 `))
 		})
 	})
diff --git a/app/kumactl/cmd/config/config_control_planes_switch_test.go b/app/kumactl/cmd/config/config_control_planes_switch_test.go
index afdd002b3..0b23dd92a 100644
--- a/app/kumactl/cmd/config/config_control_planes_switch_test.go
+++ b/app/kumactl/cmd/config/config_control_planes_switch_test.go
@@ -8,13 +8,13 @@ import (
 	"strings"
 	"unicode"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
 	"github.com/spf13/cobra"
+
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl config control-planes use", func() {
@@ -36,17 +36,16 @@ var _ = Describe("kumactl config control-planes use", func() {
 	var outbuf *bytes.Buffer
 
 	BeforeEach(func() {
-		rootCmd = cmd.DefaultRootCmd()
+		rootCmd = test.DefaultTestingRootCmd()
 
 		// Different versions of cobra might emit errors to stdout
-		// or stderr. It's too fragile to depend on precidely what
+		// or stderr. It's too fragile to depend on precisely what
 		// it does, and that's not something that needs to be tested
 		// within Kuma anyway. So we just combine all the output
 		// and validate the aggregate.
 		outbuf = &bytes.Buffer{}
 		rootCmd.SetOut(outbuf)
 		rootCmd.SetErr(outbuf)
-
 	})
 
 	Describe("error cases", func() {
@@ -60,8 +59,7 @@ var _ = Describe("kumactl config control-planes use", func() {
 			// then
 			Expect(err.Error()).To(MatchRegexp(requiredFlagNotSet("name")))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: required flag(s) "name" not set
-`))
+			Expect(outbuf.String()).To(ContainSubstring(`Error: required flag(s) "name" not set`))
 		})
 
 		It("should fail to switch to unknown Control Plane", func() {
@@ -74,8 +72,7 @@ var _ = Describe("kumactl config control-planes use", func() {
 			// then
 			Expect(err).To(MatchError(`there is no Control Plane with name "example"`))
 			// and
-			Expect(outbuf.String()).To(Equal(`Error: there is no Control Plane with name "example"
-`))
+			Expect(outbuf.String()).To(ContainSubstring(`Error: there is no Control Plane with name "example"`))
 		})
 	})
 
diff --git a/app/kumactl/cmd/config/config_view_test.go b/app/kumactl/cmd/config/config_view_test.go
index 46b6136c5..f8bbec4b7 100644
--- a/app/kumactl/cmd/config/config_view_test.go
+++ b/app/kumactl/cmd/config/config_view_test.go
@@ -5,7 +5,7 @@ import (
 	"io/ioutil"
 	"path/filepath"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
@@ -15,7 +15,7 @@ var _ = Describe("kumactl config view", func() {
 
 	It("should display configuration from a given file", func() {
 		// setup
-		rootCmd := cmd.DefaultRootCmd()
+		rootCmd := test.DefaultTestingRootCmd()
 		buf := &bytes.Buffer{}
 		rootCmd.SetOut(buf)
 
diff --git a/app/kumactl/cmd/delete/delete_meshes_test.go b/app/kumactl/cmd/delete/delete_meshes_test.go
index 219d88a95..e1cda298a 100644
--- a/app/kumactl/cmd/delete/delete_meshes_test.go
+++ b/app/kumactl/cmd/delete/delete_meshes_test.go
@@ -18,6 +18,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl delete mesh", func() {
@@ -46,6 +47,7 @@ var _ = Describe("kumactl delete mesh", func() {
 		BeforeEach(func() {
 			// setup
 			rootCtx = kumactl_cmd.DefaultRootContext()
+			rootCtx.Runtime.NewAPIServerClient = test.GetMockNewAPIServerClient()
 			rootCtx.Runtime.NewResourceStore = func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 				return store, nil
 			}
diff --git a/app/kumactl/cmd/delete/delete_test.go b/app/kumactl/cmd/delete/delete_test.go
index f276e0273..cc03059ba 100644
--- a/app/kumactl/cmd/delete/delete_test.go
+++ b/app/kumactl/cmd/delete/delete_test.go
@@ -20,6 +20,7 @@ import (
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl delete ", func() {
@@ -32,6 +33,7 @@ var _ = Describe("kumactl delete ", func() {
 		BeforeEach(func() {
 			// setup
 			rootCtx = kumactl_cmd.DefaultRootContext()
+			rootCtx.Runtime.NewAPIServerClient = test.GetMockNewAPIServerClient()
 			rootCtx.Runtime.NewResourceStore = func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 				return store, nil
 			}
diff --git a/app/kumactl/cmd/generate/generate_certificate_test.go b/app/kumactl/cmd/generate/generate_certificate_test.go
index 449831c34..68b50cfe2 100644
--- a/app/kumactl/cmd/generate/generate_certificate_test.go
+++ b/app/kumactl/cmd/generate/generate_certificate_test.go
@@ -9,9 +9,9 @@ import (
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
 	"github.com/kumahq/kuma/app/kumactl/cmd/generate"
 	"github.com/kumahq/kuma/pkg/tls"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl generate tls-certificate", func() {
@@ -57,7 +57,7 @@ var _ = Describe("kumactl generate tls-certificate", func() {
 
 		It("should generate client certificate", func() {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs([]string{"generate", "tls-certificate",
 				"--key-file", keyFile.Name(),
 				"--cert-file", certFile.Name(),
@@ -91,7 +91,7 @@ Cert was saved in: %s
 
 		It("should not allow to specify control plane hostname", func() {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs([]string{"generate", "tls-certificate",
 				"--key-file", keyFile.Name(),
 				"--cert-file", certFile.Name(),
@@ -125,7 +125,7 @@ Cert was saved in: %s
 
 		It("should generate server certificate", func() {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs([]string{"generate", "tls-certificate",
 				"--key-file", keyFile.Name(),
 				"--cert-file", certFile.Name(),
@@ -161,7 +161,7 @@ Cert was saved in: %s
 
 		It("should validate that cp-hostname is present", func() {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs([]string{"generate", "tls-certificate",
 				"--key-file", keyFile.Name(),
 				"--cert-file", certFile.Name(),
diff --git a/app/kumactl/cmd/generate/generate_dataplane_token_test.go b/app/kumactl/cmd/generate/generate_dataplane_token_test.go
index dd867d787..51a9b5ff1 100644
--- a/app/kumactl/cmd/generate/generate_dataplane_token_test.go
+++ b/app/kumactl/cmd/generate/generate_dataplane_token_test.go
@@ -10,13 +10,12 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	"github.com/kumahq/kuma/app/kumactl/pkg/tokens"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type staticDataplaneTokenGenerator struct {
@@ -45,7 +44,7 @@ var _ = Describe("kumactl generate dataplane-token", func() {
 				NewDataplaneTokenClient: func(*config_proto.ControlPlaneCoordinates_ApiServer) (tokens.DataplaneTokenClient, error) {
 					return generator, nil
 				},
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 
diff --git a/app/kumactl/cmd/generate/generate_zoneingress_token_test.go b/app/kumactl/cmd/generate/generate_zoneingress_token_test.go
index 4513eb8f1..e1c2d1716 100644
--- a/app/kumactl/cmd/generate/generate_zoneingress_token_test.go
+++ b/app/kumactl/cmd/generate/generate_zoneingress_token_test.go
@@ -10,12 +10,11 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	"github.com/kumahq/kuma/app/kumactl/pkg/tokens"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type staticZoneIngressTokenGenerator struct {
@@ -45,7 +44,7 @@ var _ = Describe("kumactl generate zone-ingress-token", func() {
 				NewZoneIngressTokenClient: func(*config_proto.ControlPlaneCoordinates_ApiServer) (tokens.ZoneIngressTokenClient, error) {
 					return generator, nil
 				},
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 
diff --git a/app/kumactl/cmd/get/get_circuit_breakers_test.go b/app/kumactl/cmd/get/get_circuit_breakers_test.go
index d737a5f13..ad07aca26 100644
--- a/app/kumactl/cmd/get/get_circuit_breakers_test.go
+++ b/app/kumactl/cmd/get/get_circuit_breakers_test.go
@@ -8,6 +8,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/kumahq/kuma/pkg/util/test"
+
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -16,8 +18,6 @@ import (
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	kuma_mesh "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -129,7 +129,7 @@ var _ = Describe("kumactl get circuit-breakers", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_dataplanes_test.go b/app/kumactl/cmd/get/get_dataplanes_test.go
index 1e9db5cf7..c7bf196ab 100644
--- a/app/kumactl/cmd/get/get_dataplanes_test.go
+++ b/app/kumactl/cmd/get/get_dataplanes_test.go
@@ -8,9 +8,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -19,14 +16,15 @@ import (
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
+	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
 	mesh_core "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
-
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get dataplanes", func() {
@@ -104,7 +102,7 @@ var _ = Describe("kumactl get dataplanes", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_external_services_test.go b/app/kumactl/cmd/get/get_external_services_test.go
index 06ae9b643..69c308d70 100644
--- a/app/kumactl/cmd/get/get_external_services_test.go
+++ b/app/kumactl/cmd/get/get_external_services_test.go
@@ -8,9 +8,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -19,14 +16,15 @@ import (
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
+	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
 	mesh_core "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
-
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get external-services", func() {
@@ -84,7 +82,7 @@ var _ = Describe("kumactl get external-services", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_fault_injections_test.go b/app/kumactl/cmd/get/get_fault_injections_test.go
index 058e306b7..5f04919df 100644
--- a/app/kumactl/cmd/get/get_fault_injections_test.go
+++ b/app/kumactl/cmd/get/get_fault_injections_test.go
@@ -16,8 +16,6 @@ import (
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -27,6 +25,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get fault-injections", func() {
@@ -123,7 +122,7 @@ var _ = Describe("kumactl get fault-injections", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_global_secrets_test.go b/app/kumactl/cmd/get/get_global_secrets_test.go
index a28f65e2c..330ef95ab 100644
--- a/app/kumactl/cmd/get/get_global_secrets_test.go
+++ b/app/kumactl/cmd/get/get_global_secrets_test.go
@@ -8,24 +8,22 @@ import (
 
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 	"github.com/spf13/cobra"
 
 	system_proto "github.com/kumahq/kuma/api/system/v1alpha1"
-	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
-	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
-	. "github.com/kumahq/kuma/pkg/test/matchers"
-
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
+	. "github.com/kumahq/kuma/pkg/test/matchers"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get global-secrets", func() {
@@ -74,7 +72,7 @@ var _ = Describe("kumactl get global-secrets", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_healthchecks_test.go b/app/kumactl/cmd/get/get_healthchecks_test.go
index c76fad58b..86098b730 100644
--- a/app/kumactl/cmd/get/get_healthchecks_test.go
+++ b/app/kumactl/cmd/get/get_healthchecks_test.go
@@ -13,8 +13,6 @@ import (
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
@@ -25,8 +23,8 @@ import (
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
-
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get healthchecks", func() {
@@ -73,7 +71,7 @@ var _ = Describe("kumactl get healthchecks", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_meshes_test.go b/app/kumactl/cmd/get/get_meshes_test.go
index 168f0a93c..2194972bb 100644
--- a/app/kumactl/cmd/get/get_meshes_test.go
+++ b/app/kumactl/cmd/get/get_meshes_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -26,6 +24,7 @@ import (
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
 	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get meshes", func() {
@@ -144,7 +143,7 @@ var _ = Describe("kumactl get meshes", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_proxytemplates_test.go b/app/kumactl/cmd/get/get_proxytemplates_test.go
index ce1a75020..fca45f6e8 100644
--- a/app/kumactl/cmd/get/get_proxytemplates_test.go
+++ b/app/kumactl/cmd/get/get_proxytemplates_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,6 +23,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get proxytemplates", func() {
@@ -72,7 +71,7 @@ var _ = Describe("kumactl get proxytemplates", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_ratelimits_test.go b/app/kumactl/cmd/get/get_ratelimits_test.go
index 5b16bfa5f..d20b37525 100644
--- a/app/kumactl/cmd/get/get_ratelimits_test.go
+++ b/app/kumactl/cmd/get/get_ratelimits_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,6 +23,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get rate-limits", func() {
@@ -95,7 +94,7 @@ var _ = Describe("kumactl get rate-limits", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_retries_test.go b/app/kumactl/cmd/get/get_retries_test.go
index 253193aed..af4a31238 100644
--- a/app/kumactl/cmd/get/get_retries_test.go
+++ b/app/kumactl/cmd/get/get_retries_test.go
@@ -13,8 +13,6 @@ import (
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
@@ -26,6 +24,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get retries", func() {
@@ -76,7 +75,7 @@ var _ = Describe("kumactl get retries", func() {
 					) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_secrets_test.go b/app/kumactl/cmd/get/get_secrets_test.go
index 06dc242e0..3892c4ff0 100644
--- a/app/kumactl/cmd/get/get_secrets_test.go
+++ b/app/kumactl/cmd/get/get_secrets_test.go
@@ -10,8 +10,6 @@ import (
 
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -28,6 +26,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get secrets", func() {
@@ -76,7 +75,7 @@ var _ = Describe("kumactl get secrets", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_traffic_logs_test.go b/app/kumactl/cmd/get/get_traffic_logs_test.go
index 5a5533b0b..1741d5cde 100644
--- a/app/kumactl/cmd/get/get_traffic_logs_test.go
+++ b/app/kumactl/cmd/get/get_traffic_logs_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,6 +23,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get traffic-logs", func() {
@@ -101,7 +100,7 @@ var _ = Describe("kumactl get traffic-logs", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_traffic_routes_test.go b/app/kumactl/cmd/get/get_traffic_routes_test.go
index 439374e2c..f6917b9a1 100644
--- a/app/kumactl/cmd/get/get_traffic_routes_test.go
+++ b/app/kumactl/cmd/get/get_traffic_routes_test.go
@@ -13,8 +13,6 @@ import (
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
@@ -25,8 +23,8 @@ import (
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
-
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get traffic-routes", func() {
@@ -74,7 +72,7 @@ var _ = Describe("kumactl get traffic-routes", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_traffic_traces_test.go b/app/kumactl/cmd/get/get_traffic_traces_test.go
index 3db17fe2f..827055306 100644
--- a/app/kumactl/cmd/get/get_traffic_traces_test.go
+++ b/app/kumactl/cmd/get/get_traffic_traces_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,6 +23,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get traffic-traces", func() {
@@ -85,7 +84,7 @@ var _ = Describe("kumactl get traffic-traces", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_trafficpermissions_test.go b/app/kumactl/cmd/get/get_trafficpermissions_test.go
index 75658459b..e3ffb9cb6 100644
--- a/app/kumactl/cmd/get/get_trafficpermissions_test.go
+++ b/app/kumactl/cmd/get/get_trafficpermissions_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,6 +23,7 @@ import (
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get traffic-permissions", func() {
@@ -95,7 +94,7 @@ var _ = Describe("kumactl get traffic-permissions", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_zone-ingresses_test.go b/app/kumactl/cmd/get/get_zone-ingresses_test.go
index b9c6ff7d5..742a835b0 100644
--- a/app/kumactl/cmd/get/get_zone-ingresses_test.go
+++ b/app/kumactl/cmd/get/get_zone-ingresses_test.go
@@ -15,16 +15,15 @@ import (
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
-
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get zone-ingresses", func() {
@@ -84,7 +83,7 @@ var _ = Describe("kumactl get zone-ingresses", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/get/get_zones_test.go b/app/kumactl/cmd/get/get_zones_test.go
index 7cf1e994e..2c4bf5de8 100644
--- a/app/kumactl/cmd/get/get_zones_test.go
+++ b/app/kumactl/cmd/get/get_zones_test.go
@@ -8,23 +8,22 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/api/system/v1alpha1"
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
+	"github.com/kumahq/kuma/api/system/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl get zones", func() {
@@ -59,7 +58,7 @@ var _ = Describe("kumactl get zones", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/inspect/inspect_dataplanes_test.go b/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
index c375ba4ed..f118826fc 100644
--- a/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
+++ b/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
@@ -8,13 +8,8 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/pkg/core/resources/model"
-
 	"google.golang.org/protobuf/types/known/timestamppb"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
-	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
@@ -22,14 +17,16 @@ import (
 
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
+	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
 	mesh_core "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
 	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type testDataplaneOverviewClient struct {
@@ -405,7 +402,7 @@ var _ = Describe("kumactl inspect dataplanes", func() {
 					NewDataplaneOverviewClient: func(*config_proto.ControlPlaneCoordinates_ApiServer) (resources.DataplaneOverviewClient, error) {
 						return testClient, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/inspect/inspect_meshes_test.go b/app/kumactl/cmd/inspect/inspect_meshes_test.go
index fd1453607..33bab9bf9 100644
--- a/app/kumactl/cmd/inspect/inspect_meshes_test.go
+++ b/app/kumactl/cmd/inspect/inspect_meshes_test.go
@@ -7,16 +7,12 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/pkg/test/matchers"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -25,7 +21,9 @@ import (
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
 	memory_resources "github.com/kumahq/kuma/pkg/plugins/resources/memory"
+	"github.com/kumahq/kuma/pkg/test/matchers"
 	"github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl inspect meshes", func() {
@@ -92,7 +90,7 @@ var _ = Describe("kumactl inspect meshes", func() {
 					NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) {
 						return store, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/inspect/inspect_services_test.go b/app/kumactl/cmd/inspect/inspect_services_test.go
index 6a9ae984e..b32282c44 100644
--- a/app/kumactl/cmd/inspect/inspect_services_test.go
+++ b/app/kumactl/cmd/inspect/inspect_services_test.go
@@ -14,8 +14,6 @@ import (
 	gomega_types "github.com/onsi/gomega/types"
 	"github.com/spf13/cobra"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
@@ -24,6 +22,7 @@ import (
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/test/resources/model"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type testServiceOverviewClient struct {
@@ -92,7 +91,7 @@ var _ = Describe("kumactl inspect services", func() {
 						overviews: serviceOverviewResources,
 					}, nil
 				},
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 
diff --git a/app/kumactl/cmd/inspect/inspect_zoneingresses_test.go b/app/kumactl/cmd/inspect/inspect_zoneingresses_test.go
index b838d2682..f5290fb70 100644
--- a/app/kumactl/cmd/inspect/inspect_zoneingresses_test.go
+++ b/app/kumactl/cmd/inspect/inspect_zoneingresses_test.go
@@ -7,25 +7,24 @@ import (
 	"strings"
 	"time"
 
+	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
+
 	"github.com/spf13/cobra"
 
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	"github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/test/matchers"
-
-	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
-	. "github.com/onsi/ginkgo"
-
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
 	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type testZoneIngressOverviewClient struct {
@@ -262,7 +261,7 @@ var _ = Describe("kumactl inspect zone-ingresses", func() {
 					NewZoneIngressOverviewClient: func(*config_proto.ControlPlaneCoordinates_ApiServer) (resources.ZoneIngressOverviewClient, error) {
 						return testClient, nil
 					},
-					NewAPIServerClient: resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/inspect/inspect_zones_test.go b/app/kumactl/cmd/inspect/inspect_zones_test.go
index 1037ce2ac..c120f8f3a 100644
--- a/app/kumactl/cmd/inspect/inspect_zones_test.go
+++ b/app/kumactl/cmd/inspect/inspect_zones_test.go
@@ -7,31 +7,26 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kumahq/kuma/pkg/test/matchers"
-
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	system_proto "github.com/kumahq/kuma/api/system/v1alpha1"
-	system_core "github.com/kumahq/kuma/pkg/core/resources/apis/system"
-
-	"github.com/kumahq/kuma/pkg/core/resources/model"
-
-	"github.com/kumahq/kuma/app/kumactl/cmd"
-
-	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 	gomega_types "github.com/onsi/gomega/types"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
 	"github.com/spf13/cobra"
 
+	system_proto "github.com/kumahq/kuma/api/system/v1alpha1"
+	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	"github.com/kumahq/kuma/app/kumactl/pkg/resources"
 	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	system_core "github.com/kumahq/kuma/pkg/core/resources/apis/system"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
+	"github.com/kumahq/kuma/pkg/test/matchers"
 	test_model "github.com/kumahq/kuma/pkg/test/resources/model"
 	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 type testZoneOverviewClient struct {
@@ -241,7 +236,7 @@ var _ = Describe("kumactl inspect zones", func() {
 					NewZoneOverviewClient: func(*config_proto.ControlPlaneCoordinates_ApiServer) (resources.ZoneOverviewClient, error) {
 						return testClient, nil
 					},
-					NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+					NewAPIServerClient: test.GetMockNewAPIServerClient(),
 				},
 			}
 
diff --git a/app/kumactl/cmd/install/install_control_plane_test.go b/app/kumactl/cmd/install/install_control_plane_test.go
index 6ececd769..bb25fdc4d 100644
--- a/app/kumactl/cmd/install/install_control_plane_test.go
+++ b/app/kumactl/cmd/install/install_control_plane_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	"github.com/kumahq/kuma/pkg/tls"
+	"github.com/kumahq/kuma/pkg/util/test"
 	kuma_version "github.com/kumahq/kuma/pkg/version"
 )
 
@@ -50,6 +51,7 @@ var _ = Describe("kumactl install control-plane", func() {
 		func(given testCase) {
 			// setup - override some values to have stable YAMLs regardless of changes in versions and autogenerated values
 			rootCtx := kumactl_cmd.DefaultRootContext()
+			rootCtx.Runtime.NewAPIServerClient = test.GetMockNewAPIServerClient()
 			rootCtx.InstallCpContext.Args.ControlPlane_image_tag = "0.0.1"
 			rootCtx.InstallCpContext.Args.DataPlane_image_tag = "0.0.1"
 			rootCtx.InstallCpContext.Args.DataPlane_initImage_tag = "0.0.1"
@@ -155,7 +157,7 @@ var _ = Describe("kumactl install control-plane", func() {
 	DescribeTable("should fail to install control plane",
 		func(given errTestCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "control-plane"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_crds_test.go b/app/kumactl/cmd/install/install_crds_test.go
index efd7e30fa..2f76bc3fc 100644
--- a/app/kumactl/cmd/install/install_crds_test.go
+++ b/app/kumactl/cmd/install/install_crds_test.go
@@ -8,7 +8,7 @@ import (
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl install crds", func() {
@@ -28,7 +28,7 @@ var _ = Describe("kumactl install crds", func() {
 	DescribeTable("should generate Kubernetes CRD resources",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "crds"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_demo_test.go b/app/kumactl/cmd/install/install_demo_test.go
index 08ab01777..18dbd9529 100644
--- a/app/kumactl/cmd/install/install_demo_test.go
+++ b/app/kumactl/cmd/install/install_demo_test.go
@@ -4,13 +4,12 @@ import (
 	"bytes"
 	"path/filepath"
 
-	kuma_version "github.com/kumahq/kuma/pkg/version"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
+	kuma_version "github.com/kumahq/kuma/pkg/version"
 )
 
 var _ = Describe("kumactl install demo", func() {
@@ -40,7 +39,7 @@ var _ = Describe("kumactl install demo", func() {
 	DescribeTable("should generate Kubernetes resources",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "demo"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_gateway_test.go b/app/kumactl/cmd/install/install_gateway_test.go
index 95537e5a1..413ba9411 100644
--- a/app/kumactl/cmd/install/install_gateway_test.go
+++ b/app/kumactl/cmd/install/install_gateway_test.go
@@ -4,13 +4,12 @@ import (
 	"bytes"
 	"path/filepath"
 
-	kuma_version "github.com/kumahq/kuma/pkg/version"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
+	kuma_version "github.com/kumahq/kuma/pkg/version"
 )
 
 var _ = Describe("kumactl install gateway", func() {
@@ -40,7 +39,7 @@ var _ = Describe("kumactl install gateway", func() {
 	DescribeTable("should generate Kubernetes resources",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "gateway"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_logging_test.go b/app/kumactl/cmd/install/install_logging_test.go
index 0e22c92a5..47e06e2d2 100644
--- a/app/kumactl/cmd/install/install_logging_test.go
+++ b/app/kumactl/cmd/install/install_logging_test.go
@@ -4,13 +4,12 @@ import (
 	"bytes"
 	"path/filepath"
 
-	kuma_version "github.com/kumahq/kuma/pkg/version"
-
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
+	kuma_version "github.com/kumahq/kuma/pkg/version"
 )
 
 var _ = Describe("kumactl install logging", func() {
@@ -40,7 +39,7 @@ var _ = Describe("kumactl install logging", func() {
 	DescribeTable("should generate Kubernetes resources",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "logging"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_metrics_test.go b/app/kumactl/cmd/install/install_metrics_test.go
index 0e989d63c..ed15f3016 100644
--- a/app/kumactl/cmd/install/install_metrics_test.go
+++ b/app/kumactl/cmd/install/install_metrics_test.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 	kuma_version "github.com/kumahq/kuma/pkg/version"
 )
 
@@ -41,6 +42,7 @@ var _ = Describe("kumactl install metrics", func() {
 		func(given testCase) {
 			// given
 			rootCtx := kumactl_cmd.DefaultRootContext()
+			rootCtx.Runtime.NewAPIServerClient = test.GetMockNewAPIServerClient()
 			rootCtx.InstallMetricsContext.TemplateArgs.KumaPrometheusSdVersion = "0.0.1"
 			rootCmd := cmd.NewRootCmd(rootCtx)
 			rootCmd.SetArgs(append([]string{"install", "metrics"}, given.extraArgs...))
diff --git a/app/kumactl/cmd/install/install_tracing_test.go b/app/kumactl/cmd/install/install_tracing_test.go
index 4f19ac064..068e579a4 100644
--- a/app/kumactl/cmd/install/install_tracing_test.go
+++ b/app/kumactl/cmd/install/install_tracing_test.go
@@ -8,7 +8,7 @@ import (
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl install tracing", func() {
@@ -29,7 +29,7 @@ var _ = Describe("kumactl install tracing", func() {
 	DescribeTable("should generate Kubernetes resources",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "tracing"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/install/install_transparent_proxy_test.go b/app/kumactl/cmd/install/install_transparent_proxy_test.go
index 37735a41e..5b6a704ee 100644
--- a/app/kumactl/cmd/install/install_transparent_proxy_test.go
+++ b/app/kumactl/cmd/install/install_transparent_proxy_test.go
@@ -11,7 +11,7 @@ import (
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl install tracing", func() {
@@ -32,7 +32,7 @@ var _ = Describe("kumactl install tracing", func() {
 	DescribeTable("should install transparent proxy",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "transparent-proxy", "--dry-run"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
@@ -98,7 +98,7 @@ var _ = Describe("kumactl install tracing", func() {
 	DescribeTable("should return error",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"install", "transparent-proxy", "--dry-run"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/app/kumactl/cmd/root_test.go b/app/kumactl/cmd/root_test.go
index f243e6119..bdec76465 100644
--- a/app/kumactl/cmd/root_test.go
+++ b/app/kumactl/cmd/root_test.go
@@ -7,11 +7,10 @@ import (
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 
-	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
-
 	"github.com/kumahq/kuma/app/kumactl/cmd"
 	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
 	"github.com/kumahq/kuma/app/kumactl/pkg/config"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl root cmd", func() {
@@ -35,7 +34,7 @@ var _ = Describe("kumactl root cmd", func() {
 		// given
 		rootCtx := &kumactl_cmd.RootContext{
 			Runtime: kumactl_cmd.RootRuntime{
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 		rootCmd := cmd.NewRootCmd(rootCtx)
@@ -68,7 +67,7 @@ currentContext: local
 		// given
 		rootCtx := &kumactl_cmd.RootContext{
 			Runtime: kumactl_cmd.RootRuntime{
-				NewAPIServerClient: kumactl_resources.NewAPIServerClient,
+				NewAPIServerClient: test.GetMockNewAPIServerClient(),
 			},
 		}
 		rootCmd := cmd.NewRootCmd(rootCtx)
diff --git a/app/kumactl/cmd/uninstall/uninstall_transparent_proxy_test.go b/app/kumactl/cmd/uninstall/uninstall_transparent_proxy_test.go
index aee7011d8..71002eba7 100644
--- a/app/kumactl/cmd/uninstall/uninstall_transparent_proxy_test.go
+++ b/app/kumactl/cmd/uninstall/uninstall_transparent_proxy_test.go
@@ -10,7 +10,7 @@ import (
 	. "github.com/onsi/ginkgo/extensions/table"
 	. "github.com/onsi/gomega"
 
-	"github.com/kumahq/kuma/app/kumactl/cmd"
+	"github.com/kumahq/kuma/pkg/util/test"
 )
 
 var _ = Describe("kumactl install tracing", func() {
@@ -31,7 +31,7 @@ var _ = Describe("kumactl install tracing", func() {
 	DescribeTable("should install transparent proxy",
 		func(given testCase) {
 			// given
-			rootCmd := cmd.DefaultRootCmd()
+			rootCmd := test.DefaultTestingRootCmd()
 			rootCmd.SetArgs(append([]string{"uninstall", "transparent-proxy", "--dry-run"}, given.extraArgs...))
 			rootCmd.SetOut(stdout)
 			rootCmd.SetErr(stderr)
diff --git a/mk/test.mk b/mk/test.mk
index da12588a2..40be95468 100644
--- a/mk/test.mk
+++ b/mk/test.mk
@@ -36,7 +36,7 @@ coverage: ${COVERAGE_PROFILE}
 
 .PHONY: test/kuma
 test/kuma: # Dev: Run tests for the module github.com/kumahq/kuma
-	$(GO_TEST) $(GO_TEST_OPTS) -race -covermode=atomic -coverpkg=./... -coverprofile="$(COVERAGE_PROFILE)" $(PKG_LIST)
+	$(GO_TEST) $(GO_TEST_OPTS) --tags=gateway -race -covermode=atomic -coverpkg=./... -coverprofile="$(COVERAGE_PROFILE)" $(PKG_LIST)
 
 .PHONY: test/api
 test/api: \
@@ -71,6 +71,6 @@ ${COVERAGE_INTEGRATION_PROFILE}:
 
 .PHONY: integration
 integration: ${COVERAGE_INTEGRATION_PROFILE} ## Dev: Run integration tests
-	tools/test/run-integration-tests.sh '$(GO_TEST) -race -covermode=atomic -tags=integration -count=1 -coverpkg=./... -coverprofile=$(COVERAGE_INTEGRATION_PROFILE) $(PKG_LIST)'
+	tools/test/run-integration-tests.sh '$(GO_TEST) -tags=integration,gateway -race -covermode=atomic -count=1 -coverpkg=./... -coverprofile=$(COVERAGE_INTEGRATION_PROFILE) $(PKG_LIST)'
 	GOFLAGS='${GOFLAGS}' go tool cover -html="$(COVERAGE_INTEGRATION_PROFILE)" -o "$(COVERAGE_INTEGRATION_REPORT_HTML)"
 
diff --git a/pkg/core/resources/apis/mesh/dataplane_validator_test.go b/pkg/core/resources/apis/mesh/dataplane_validator_test.go
index c2a000781..8190e7090 100644
--- a/pkg/core/resources/apis/mesh/dataplane_validator_test.go
+++ b/pkg/core/resources/apis/mesh/dataplane_validator_test.go
@@ -361,8 +361,88 @@ var _ = Describe("Dataplane", func() {
                       service: redis`,
 			expected: `
                 violations:
-                - field: networking
-                  message: inbound cannot be defined both with gateway`,
+                - field: networking.inbound
+                  message: inbound cannot be defined for delegated gateways`,
+		}),
+		Entry("networking: builtin gateway must not have inbounds", testCase{
+			dataplane: `
+                type: Dataplane
+                name: dp-1
+                mesh: default
+                networking:
+                  address: 192.168.0.1
+                  gateway:
+                    type: BUILTIN
+                    tags:
+                      kuma.io/service: kong
+                  inbound:
+                    - port: 3333
+                      service: redis
+                      tags:
+                        kuma.io/service: kong`,
+			expected: `
+                violations:
+                - field: networking.inbound
+                  message: inbound cannot be defined for builtin gateways`,
+		}),
+		Entry("networking: builtin gateway must not have outbounds", testCase{
+			dataplane: `
+                type: Dataplane
+                name: dp-1
+                mesh: default
+                networking:
+                  address: 192.168.0.1
+                  gateway:
+                    type: BUILTIN
+                    tags:
+                      kuma.io/service: kong
+                  outbound:
+                    - port: 3333
+                      service: redis
+                      tags:
+                        kuma.io/service: kong`,
+			expected: `
+                violations:
+                - field: networking.outbound
+                  message: outbound cannot be defined for builtin gateways`,
+		}),
+		Entry("networking: builtin gateway must not have probes", testCase{
+			dataplane: `
+                type: Dataplane
+                name: dp-1
+                mesh: default
+                networking:
+                  address: 192.168.0.1
+                  gateway:
+                    type: BUILTIN
+                    tags:
+                      kuma.io/service: kong
+                probes:
+                  port: 0
+                  endpoints:
+                   - inboundPort: 8088
+                     inboundPath: /healthz
+                     path: /8080/healthz`,
+			expected: `
+                violations:
+                - field: networking.probes
+                  message: probes cannot be defined for builtin gateways`,
+		}),
+		Entry("networking: builtin gateway must have a service tag", testCase{
+			dataplane: `
+                type: Dataplane
+                name: dp-1
+                mesh: default
+                networking:
+                  address: 192.168.0.1
+                  gateway:
+                    type: BUILTIN
+                    tags:
+                      foo: bar`,
+			expected: `
+                violations:
+                - field: networking.gateway.tags["kuma.io/service"]
+                  message: tag has to exist`,
 		}),
 		Entry("networking.inbound: port of the range", testCase{
 			dataplane: `
diff --git a/pkg/util/test/mock_api_client.go b/pkg/util/test/mock_api_client.go
new file mode 100644
index 000000000..a8a6afe63
--- /dev/null
+++ b/pkg/util/test/mock_api_client.go
@@ -0,0 +1,43 @@
+package test
+
+import (
+	"context"
+
+	"github.com/spf13/cobra"
+
+	kumactl_cmd "github.com/kumahq/kuma/app/kumactl/cmd"
+	kumactl_pkg_cmd "github.com/kumahq/kuma/app/kumactl/pkg/cmd"
+	kumactl_resources "github.com/kumahq/kuma/app/kumactl/pkg/resources"
+	"github.com/kumahq/kuma/pkg/api-server/types"
+	config_proto "github.com/kumahq/kuma/pkg/config/app/kumactl/v1alpha1"
+	kuma_version "github.com/kumahq/kuma/pkg/version"
+)
+
+type MockAPIServerClient struct {
+	Version types.IndexResponse
+}
+
+func (m *MockAPIServerClient) GetVersion(ctx context.Context) (*types.IndexResponse, error) {
+	return &m.Version, nil
+}
+
+func GetMockNewAPIServerClient() func(*config_proto.ControlPlaneCoordinates_ApiServer) (kumactl_resources.ApiServerClient, error) {
+	return func(*config_proto.ControlPlaneCoordinates_ApiServer) (kumactl_resources.ApiServerClient, error) {
+		return &MockAPIServerClient{
+			Version: types.IndexResponse{
+				Hostname: "localhost",
+				Tagline:  kuma_version.Product,
+				Version:  kuma_version.Build.Version,
+			},
+		}, nil
+	}
+}
+
+// DefaultTestingRootCmd returns the DefaultRootCmd with server API mocked to return
+// current version. Useful for tests which don't actually require the server but need to
+// avoid extraneous warnings.
+func DefaultTestingRootCmd() *cobra.Command {
+	ctx := kumactl_pkg_cmd.DefaultRootContext()
+	ctx.Runtime.NewAPIServerClient = GetMockNewAPIServerClient()
+	return kumactl_cmd.NewRootCmd(ctx)
+}
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
index 4c8916154..6dabf1534 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
@@ -80,7 +80,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -108,7 +111,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
index 2bdce08e3..707448b90 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
@@ -87,7 +87,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -115,7 +118,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
index 14b3eaddc..7a1036e33 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
@@ -80,7 +80,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -108,7 +111,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml b/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
index ceee99e20..22acd0280 100644
--- a/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.custom-config-minimal-request.golden.yaml
@@ -60,7 +60,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 2s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -88,7 +91,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
index 6fd8d99b4..d49543873 100644
--- a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
@@ -94,7 +94,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 2s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -122,7 +125,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
index 6324d5b8f..7950d50ff 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config-minimal-request.golden.yaml
@@ -53,7 +53,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -81,7 +84,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
index 746680dc8..653a9a6b0 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
@@ -69,7 +69,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -97,7 +100,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.golden.yaml
index f33298006..6e3875e8e 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.golden.yaml
@@ -67,7 +67,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -95,7 +98,10 @@ staticResources:
         sni: localhost
     type: STRICT_DNS
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.ipv6.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.ipv6.golden.yaml
index 8c9403bf9..f869d6bac 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.ipv6.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config.kubernetes.ipv6.golden.yaml
@@ -67,7 +67,10 @@ staticResources:
     name: access_log_sink
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
   - connectTimeout: 1s
     http2ProtocolOptions: {}
     loadAssignment:
@@ -95,7 +98,10 @@ staticResources:
         sni: fd00:a123::1
     type: STATIC
     upstreamConnectionOptions:
-      tcpKeepalive: {}
+      tcpKeepalive:
+        keepaliveInterval: 10
+        keepaliveProbes: 3
+        keepaliveTime: 10
 statsConfig:
   statsTags:
   - regex: ^grpc\.((.+)\.)