Repository: kumahq/kuma
Pull request #1104 (2020-10-23 05:47:36)

chore(*) improve DP insights API filtering
### Summary

Improve the API to have better filtering for dataplane insights, such that this request will now work ->
`curl http://localhost:5681/dataplanes+insights?gateway=false&ingress=false`

tharun208: @nickolaev, Also we need to add the filter option for `ingress` data planes in the cli.
nickolaev: > @nickolaev, Also we need to add the filter option for `ingress` data planes in the cli.

Please give an example of the CLI command.
tharun208: > > @nickolaev, Also we need to add the filter option for `ingress` data planes in the cli.
> 
> Please give an example of the CLI command.

we are already having an option in CLI to filter `gateway` dataplanes - `kumactl inspect dataplanes --gateway`.

Patch:
diff --git a/api/go.sum b/api/go.sum
index 05b1b536e..5006a5470 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -1,16 +1,22 @@
 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/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-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533 h1:8wZizuKuZVu5COB7EsBYxBQz8nRcXXn5d4Gt91eJLvU=
 github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.5 h1:lRJIqDD8yjV1YyPRqecMdytjDLs2fTXq363aCib5xPU=
 github.com/envoyproxy/go-control-plane v0.9.5/go.mod h1:OXl5to++W0ctG+EHWTFUjiypVxC/Y4VLc/KFU+al13s=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9 h1:mU3oOAYTK9ZRKMj//H1EWk1vWbkYeWKBPYKMnIwcs/A=
 github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 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/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=
@@ -28,6 +34,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
@@ -82,11 +89,13 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
 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/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA=
 google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
@@ -100,8 +109,10 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
 google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
diff --git a/api/mesh/v1alpha1/dataplane.pb.go b/api/mesh/v1alpha1/dataplane.pb.go
index 7be619315..23c460cc8 100644
--- a/api/mesh/v1alpha1/dataplane.pb.go
+++ b/api/mesh/v1alpha1/dataplane.pb.go
@@ -90,7 +90,6 @@ type Dataplane_Networking struct {
 	// Ingress if not nil, dataplane will be work in the Ingress mode
 	Ingress *Dataplane_Networking_Ingress `protobuf:"bytes,6,opt,name=ingress,proto3" json:"ingress,omitempty"`
 	// Public IP on which the dataplane is accessible in the network.
-	// Host names and DNS are not allowed.
 	Address string `protobuf:"bytes,5,opt,name=address,proto3" json:"address,omitempty"`
 	// Gateway describes configuration of gateway of the dataplane.
 	Gateway *Dataplane_Networking_Gateway `protobuf:"bytes,3,opt,name=gateway,proto3" json:"gateway,omitempty"`
@@ -177,10 +176,14 @@ func (m *Dataplane_Networking) GetTransparentProxying() *Dataplane_Networking_Tr
 // prohibited). Every inbound interface matches with services that reside in
 // that cluster.
 type Dataplane_Networking_Ingress struct {
-	AvailableServices    []*Dataplane_Networking_Ingress_AvailableService `protobuf:"bytes,1,rep,name=availableServices,proto3" json:"availableServices,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}                                         `json:"-"`
-	XXX_unrecognized     []byte                                           `json:"-"`
-	XXX_sizecache        int32                                            `json:"-"`
+	AvailableServices []*Dataplane_Networking_Ingress_AvailableService `protobuf:"bytes,1,rep,name=availableServices,proto3" json:"availableServices,omitempty"`
+	// PublicAddress defines IP or DNS name on which Ingress is accessible to other Kuma clusters.
+	PublicAddress string `protobuf:"bytes,2,opt,name=publicAddress,proto3" json:"publicAddress,omitempty"`
+	// PublicPort defines port on which Ingress is accessible to other Kuma clusters.
+	PublicPort           uint32   `protobuf:"varint,3,opt,name=publicPort,proto3" json:"publicPort,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
 func (m *Dataplane_Networking_Ingress) Reset()         { *m = Dataplane_Networking_Ingress{} }
@@ -215,6 +218,20 @@ func (m *Dataplane_Networking_Ingress) GetAvailableServices() []*Dataplane_Netwo
 	return nil
 }
 
+func (m *Dataplane_Networking_Ingress) GetPublicAddress() string {
+	if m != nil {
+		return m.PublicAddress
+	}
+	return ""
+}
+
+func (m *Dataplane_Networking_Ingress) GetPublicPort() uint32 {
+	if m != nil {
+		return m.PublicPort
+	}
+	return 0
+}
+
 // AvailableService contains tags that represent unique subset of
 // endpoints
 type Dataplane_Networking_Ingress_AvailableService struct {
@@ -658,53 +675,55 @@ func init() {
 func init() { proto.RegisterFile("mesh/v1alpha1/dataplane.proto", fileDescriptor_7608682fd5ea84a4) }
 
 var fileDescriptor_7608682fd5ea84a4 = []byte{
-	// 760 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdd, 0x6a, 0x13, 0x41,
-	0x14, 0x66, 0x92, 0xcd, 0xcf, 0x9e, 0x1a, 0xa9, 0xd3, 0x58, 0xc3, 0xaa, 0x90, 0x16, 0x91, 0x20,
-	0xb8, 0xb5, 0x2a, 0x28, 0xb5, 0x22, 0x59, 0x2c, 0xfe, 0x94, 0xda, 0x30, 0xf6, 0x42, 0xbc, 0x09,
-	0x93, 0xec, 0x90, 0x2c, 0x49, 0x77, 0x97, 0xdd, 0x49, 0x6a, 0xde, 0xa3, 0x57, 0xe2, 0x93, 0xf8,
-	0x0a, 0x5e, 0xf8, 0x00, 0x82, 0x77, 0xbe, 0x44, 0x6f, 0x2a, 0x3b, 0x3f, 0x9b, 0x6d, 0x5a, 0x4a,
-	0x52, 0xf1, 0x6e, 0xf6, 0xcc, 0xf9, 0xbe, 0xf3, 0xf7, 0xcd, 0x49, 0xe0, 0xee, 0x21, 0x8b, 0xfb,
-	0x1b, 0xe3, 0x4d, 0x3a, 0x0c, 0xfb, 0x74, 0x73, 0xc3, 0xa5, 0x9c, 0x86, 0x43, 0xea, 0x33, 0x3b,
-	0x8c, 0x02, 0x1e, 0x60, 0x3c, 0x18, 0x1d, 0x52, 0x3b, 0xf1, 0xb1, 0xb5, 0x8f, 0x75, 0xfb, 0x2c,
-	0xe4, 0x90, 0xf1, 0xc8, 0xeb, 0xc6, 0x12, 0x60, 0xdd, 0x1a, 0xd3, 0xa1, 0xe7, 0x52, 0xce, 0x36,
-	0xf4, 0x41, 0x5e, 0xac, 0x7f, 0x5f, 0x06, 0xf3, 0xb5, 0x66, 0xc7, 0x6f, 0x01, 0x7c, 0xc6, 0x8f,
-	0x82, 0x68, 0xe0, 0xf9, 0xbd, 0x1a, 0xaa, 0xa3, 0xc6, 0xd2, 0xe3, 0x86, 0x7d, 0x3e, 0x98, 0x9d,
-	0x42, 0xec, 0x0f, 0xa9, 0x3f, 0xc9, 0x60, 0xf1, 0x36, 0x94, 0x54, 0x06, 0xb5, 0x9c, 0xa0, 0x59,
-	0xbf, 0x88, 0x66, 0x4f, 0xba, 0x38, 0xb4, 0x3b, 0x60, 0xbe, 0x4b, 0x34, 0x04, 0x6f, 0x43, 0x31,
-	0x8c, 0x82, 0x0e, 0x8b, 0x6b, 0x79, 0x01, 0xbe, 0x77, 0x79, 0x0e, 0x2d, 0xe1, 0x4b, 0x14, 0xc6,
-	0x3a, 0xae, 0x00, 0x4c, 0xd3, 0xc2, 0xef, 0xa1, 0xe4, 0xf9, 0xbd, 0x88, 0xc5, 0x71, 0xad, 0x28,
-	0xd8, 0x1e, 0xcd, 0x5b, 0x91, 0xfd, 0x4e, 0xe2, 0x88, 0x26, 0xc0, 0x35, 0x28, 0x51, 0xd7, 0x15,
-	0x5c, 0x85, 0x3a, 0x6a, 0x98, 0x44, 0x7f, 0x26, 0x51, 0x7a, 0x94, 0xb3, 0x23, 0x3a, 0x51, 0x39,
-	0xcf, 0x1f, 0xe5, 0x8d, 0xc4, 0x11, 0x4d, 0x20, 0x33, 0xee, 0x04, 0x23, 0xdf, 0xad, 0xa1, 0x7a,
-	0x7e, 0xc1, 0x8c, 0x05, 0x8e, 0x68, 0x02, 0xbc, 0x07, 0xe5, 0x60, 0xc4, 0x25, 0x59, 0x4e, 0x90,
-	0x6d, 0xce, 0x4d, 0xb6, 0xaf, 0x80, 0x24, 0xa5, 0xc0, 0x01, 0x54, 0x79, 0x44, 0xfd, 0x38, 0xa4,
-	0x11, 0xf3, 0x79, 0x3b, 0x8c, 0x82, 0x2f, 0x93, 0x44, 0x2b, 0x86, 0xa8, 0x79, 0x7b, 0x6e, 0xea,
-	0x83, 0x29, 0x49, 0x4b, 0x71, 0x90, 0x15, 0x7e, 0xde, 0x68, 0xfd, 0xca, 0x41, 0x49, 0x8d, 0x01,
-	0x07, 0x70, 0x83, 0x8e, 0xa9, 0x37, 0xa4, 0x9d, 0x21, 0xfb, 0xc8, 0xa2, 0xb1, 0xd7, 0x65, 0xb1,
-	0xea, 0x50, 0x73, 0xd1, 0x99, 0xda, 0xcd, 0x19, 0x26, 0x72, 0x9e, 0xdb, 0xfa, 0x8d, 0x60, 0x79,
-	0xd6, 0x0f, 0xb7, 0xc1, 0xe0, 0xb4, 0xa7, 0x03, 0xef, 0xfe, 0x73, 0x60, 0xfb, 0x80, 0xf6, 0xe2,
-	0x1d, 0x9f, 0x47, 0x13, 0x22, 0x88, 0xf1, 0x1d, 0x30, 0x3d, 0x3f, 0xe6, 0xd4, 0x4f, 0xca, 0x4b,
-	0x5e, 0x4f, 0x85, 0x4c, 0x0d, 0x18, 0x83, 0x91, 0x04, 0x13, 0x2a, 0x33, 0x89, 0x38, 0x5b, 0xcf,
-	0xc0, 0x4c, 0x49, 0xf0, 0x32, 0xe4, 0x07, 0x6c, 0x22, 0x5e, 0xaf, 0x49, 0x92, 0x23, 0xae, 0x42,
-	0x61, 0x4c, 0x87, 0x23, 0x26, 0xc8, 0x4c, 0x22, 0x3f, 0xb6, 0x72, 0xcf, 0x91, 0x75, 0x2c, 0xba,
-	0x2b, 0x47, 0x8b, 0xc1, 0x08, 0x83, 0x88, 0x0b, 0xe2, 0x0a, 0x11, 0x67, 0x5c, 0x87, 0xa5, 0x58,
-	0x66, 0xd9, 0x4a, 0xae, 0x0c, 0x71, 0x95, 0x35, 0xe1, 0xfb, 0x70, 0x5d, 0x7d, 0x36, 0xd5, 0xc3,
-	0x28, 0x8a, 0x20, 0x33, 0xd6, 0x4b, 0x5e, 0xce, 0x27, 0xd5, 0x4f, 0xa9, 0xce, 0xad, 0x45, 0xa5,
-	0x3e, 0x6d, 0x9f, 0x53, 0x3e, 0x71, 0x0a, 0x5f, 0x51, 0xae, 0x8c, 0x64, 0x23, 0xaf, 0xde, 0x96,
-	0x3f, 0x08, 0xca, 0x5a, 0xfc, 0xd9, 0xcc, 0xf3, 0x67, 0x33, 0xd7, 0x1d, 0x33, 0x32, 0x1d, 0x5b,
-	0x83, 0x92, 0xaa, 0x5c, 0xd2, 0x3a, 0xa5, 0x13, 0xc7, 0x88, 0x72, 0x7d, 0x44, 0xb4, 0x1d, 0xef,
-	0xab, 0x82, 0x0b, 0xa2, 0xe0, 0x17, 0x0b, 0x3f, 0xc7, 0x59, 0xc1, 0x5c, 0xbd, 0xce, 0x6f, 0x08,
-	0x4a, 0x6a, 0xfb, 0xa4, 0x63, 0x40, 0x0b, 0x8e, 0x41, 0xe1, 0xff, 0xc7, 0x18, 0x7e, 0x20, 0x58,
-	0xb9, 0x60, 0x51, 0xe0, 0x97, 0x70, 0x33, 0x62, 0xae, 0x17, 0xb1, 0x2e, 0x6f, 0x27, 0x4d, 0x6f,
-	0x4f, 0xb7, 0x25, 0x6a, 0x54, 0x1c, 0xf3, 0xc4, 0x29, 0x3e, 0x30, 0x6a, 0xa7, 0xa7, 0x79, 0xb2,
-	0xa2, 0xfd, 0x12, 0xad, 0x6a, 0xa1, 0xbf, 0x82, 0xd5, 0xb3, 0xf0, 0xcc, 0x82, 0x9c, 0xc1, 0x57,
-	0xb3, 0xf8, 0x54, 0x11, 0x4f, 0x61, 0x55, 0xc1, 0x69, 0xb7, 0xcb, 0xe2, 0xb8, 0x1d, 0xeb, 0x65,
-	0x94, 0xaf, 0xe7, 0x1b, 0x26, 0xa9, 0xca, 0xdb, 0xa6, 0xb8, 0x4c, 0x97, 0xc9, 0x4f, 0x04, 0x45,
-	0xf9, 0x4b, 0x95, 0x0a, 0x07, 0x65, 0x84, 0xb3, 0x0b, 0x26, 0xf3, 0xdd, 0x30, 0xf0, 0x7c, 0xae,
-	0xdf, 0xc2, 0xc3, 0x79, 0x7e, 0xf6, 0xec, 0x1d, 0x85, 0x22, 0x53, 0xbc, 0xe5, 0x42, 0x59, 0x9b,
-	0xf1, 0x1a, 0x5c, 0x53, 0xfd, 0x69, 0x67, 0x82, 0x2e, 0x29, 0x5b, 0x4b, 0x8a, 0x76, 0xea, 0x42,
-	0x79, 0x5f, 0x4d, 0x22, 0x75, 0xa1, 0xbc, 0x2f, 0x52, 0x4e, 0xae, 0xd4, 0xda, 0x49, 0xce, 0x0e,
-	0x7c, 0x2e, 0xeb, 0xb4, 0x3a, 0x45, 0xf1, 0x7f, 0xe2, 0xc9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff,
-	0xc3, 0xf9, 0xa5, 0xbd, 0xba, 0x08, 0x00, 0x00,
+	// 789 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4b, 0x6b, 0xeb, 0x46,
+	0x14, 0x66, 0x24, 0xf9, 0xa1, 0x93, 0xba, 0x24, 0x13, 0x37, 0x35, 0xea, 0x03, 0x27, 0x84, 0x62,
+	0x0a, 0x55, 0x9a, 0xb6, 0xd0, 0x92, 0xa6, 0x14, 0x8b, 0x86, 0x3e, 0x42, 0x1a, 0x33, 0xcd, 0xa2,
+	0x74, 0x63, 0xc6, 0xd6, 0x60, 0x0b, 0x3b, 0x92, 0x90, 0xc6, 0x4e, 0xbd, 0xeb, 0x8f, 0xe8, 0xaa,
+	0x74, 0x73, 0x7f, 0xcf, 0x5d, 0xdc, 0xfd, 0x5d, 0xdc, 0xdd, 0xfd, 0x13, 0xd9, 0xe4, 0xa2, 0x79,
+	0x48, 0xb2, 0x13, 0x82, 0x9d, 0xcb, 0xdd, 0x8d, 0xce, 0x9c, 0xef, 0x9b, 0x6f, 0xbe, 0x73, 0xe6,
+	0xd8, 0xf0, 0xc9, 0x35, 0x4b, 0xc7, 0x47, 0xf3, 0x63, 0x3a, 0x8d, 0xc7, 0xf4, 0xf8, 0xc8, 0xa7,
+	0x9c, 0xc6, 0x53, 0x1a, 0x32, 0x37, 0x4e, 0x22, 0x1e, 0x61, 0x3c, 0x99, 0x5d, 0x53, 0x37, 0xcb,
+	0x71, 0x75, 0x8e, 0xf3, 0xd1, 0x32, 0xe4, 0x9a, 0xf1, 0x24, 0x18, 0xa6, 0x12, 0xe0, 0x7c, 0x38,
+	0xa7, 0xd3, 0xc0, 0xa7, 0x9c, 0x1d, 0xe9, 0x85, 0xdc, 0x38, 0xf8, 0x67, 0x07, 0xec, 0x9f, 0x34,
+	0x3b, 0xfe, 0x05, 0x20, 0x64, 0xfc, 0x26, 0x4a, 0x26, 0x41, 0x38, 0x6a, 0xa1, 0x36, 0xea, 0x6c,
+	0x7d, 0xd5, 0x71, 0xef, 0x1f, 0xe6, 0xe6, 0x10, 0xf7, 0xf7, 0x3c, 0x9f, 0x94, 0xb0, 0xf8, 0x14,
+	0x6a, 0x4a, 0x41, 0xcb, 0x10, 0x34, 0x07, 0x0f, 0xd1, 0x5c, 0xc8, 0x14, 0x8f, 0x0e, 0x27, 0x2c,
+	0xf4, 0x89, 0x86, 0xe0, 0x53, 0xa8, 0xc6, 0x49, 0x34, 0x60, 0x69, 0xcb, 0x14, 0xe0, 0xc3, 0xc7,
+	0x35, 0xf4, 0x44, 0x2e, 0x51, 0x18, 0xe7, 0x65, 0x03, 0xa0, 0x90, 0x85, 0x7f, 0x83, 0x5a, 0x10,
+	0x8e, 0x12, 0x96, 0xa6, 0xad, 0xaa, 0x60, 0xfb, 0x72, 0xdd, 0x1b, 0xb9, 0xbf, 0x4a, 0x1c, 0xd1,
+	0x04, 0xb8, 0x05, 0x35, 0xea, 0xfb, 0x82, 0xab, 0xd2, 0x46, 0x1d, 0x9b, 0xe8, 0xcf, 0xec, 0x94,
+	0x11, 0xe5, 0xec, 0x86, 0x2e, 0x94, 0xe6, 0xf5, 0x4f, 0xf9, 0x59, 0xe2, 0x88, 0x26, 0x90, 0x8a,
+	0x07, 0xd1, 0x2c, 0xf4, 0x5b, 0xa8, 0x6d, 0x6e, 0xa8, 0x58, 0xe0, 0x88, 0x26, 0xc0, 0x17, 0x50,
+	0x8f, 0x66, 0x5c, 0x92, 0x19, 0x82, 0xec, 0x78, 0x6d, 0xb2, 0x4b, 0x05, 0x24, 0x39, 0x05, 0x8e,
+	0xa0, 0xc9, 0x13, 0x1a, 0xa6, 0x31, 0x4d, 0x58, 0xc8, 0xfb, 0x71, 0x12, 0xfd, 0xbd, 0xc8, 0x7a,
+	0xc5, 0x12, 0x77, 0x3e, 0x5d, 0x9b, 0xfa, 0xaa, 0x20, 0xe9, 0x29, 0x0e, 0xb2, 0xcb, 0xef, 0x07,
+	0x9d, 0x67, 0x26, 0xd4, 0x54, 0x19, 0x70, 0x04, 0x3b, 0x74, 0x4e, 0x83, 0x29, 0x1d, 0x4c, 0xd9,
+	0x1f, 0x2c, 0x99, 0x07, 0x43, 0x96, 0x2a, 0x87, 0xba, 0x9b, 0xd6, 0xd4, 0xed, 0xae, 0x30, 0x91,
+	0xfb, 0xdc, 0xf8, 0x10, 0x1a, 0xf1, 0x6c, 0x30, 0x0d, 0x86, 0x5d, 0x55, 0x74, 0x43, 0x14, 0x7d,
+	0x39, 0x88, 0x3f, 0x05, 0x90, 0x81, 0x5e, 0x94, 0x70, 0x51, 0xfd, 0x06, 0x29, 0x45, 0x9c, 0x57,
+	0x08, 0xb6, 0x57, 0x4f, 0xc3, 0x7d, 0xb0, 0x38, 0x1d, 0x69, 0xf9, 0xe7, 0x6f, 0x2d, 0xdf, 0xbd,
+	0xa2, 0xa3, 0xf4, 0x2c, 0xe4, 0xc9, 0x82, 0x08, 0x62, 0xfc, 0x31, 0xd8, 0x41, 0x98, 0x72, 0x1a,
+	0x66, 0x26, 0x19, 0x42, 0x54, 0x11, 0xc0, 0x18, 0xac, 0xec, 0x30, 0xa1, 0xd6, 0x26, 0x62, 0xed,
+	0x7c, 0x0b, 0x76, 0x4e, 0x82, 0xb7, 0xc1, 0x9c, 0xb0, 0x85, 0x98, 0x01, 0x36, 0xc9, 0x96, 0xb8,
+	0x09, 0x95, 0x39, 0x9d, 0xce, 0x98, 0x32, 0x41, 0x7e, 0x9c, 0x18, 0xdf, 0x21, 0xe7, 0x5f, 0x23,
+	0xab, 0x91, 0x6c, 0x10, 0x0c, 0x56, 0x5c, 0xd8, 0x20, 0xd6, 0xb8, 0x0d, 0x5b, 0xa9, 0x54, 0x29,
+	0x1c, 0xb2, 0xc4, 0x56, 0x39, 0x84, 0x3f, 0x83, 0xf7, 0xd5, 0xa7, 0x76, 0xba, 0x2a, 0x0e, 0x59,
+	0x89, 0x3e, 0xf2, 0xfe, 0xfe, 0x54, 0x7e, 0xca, 0x1e, 0x3f, 0xd9, 0xf4, 0xc1, 0x14, 0xf6, 0x79,
+	0xf5, 0x5b, 0xaf, 0xf2, 0x1f, 0x32, 0xea, 0x48, 0x1a, 0xf9, 0x74, 0x5b, 0x5e, 0x23, 0xa8, 0xeb,
+	0x27, 0x54, 0x56, 0x6e, 0x2e, 0x2b, 0xd7, 0x8e, 0x59, 0x25, 0xc7, 0xf6, 0xa1, 0xa6, 0x6e, 0x2e,
+	0x69, 0xbd, 0xda, 0xad, 0x67, 0x25, 0xc6, 0x18, 0x11, 0x1d, 0xc7, 0x97, 0xea, 0xc2, 0x15, 0x71,
+	0xe1, 0xef, 0x37, 0x7e, 0xd4, 0xab, 0x0d, 0xf3, 0xf4, 0x7b, 0xfe, 0x8f, 0xa0, 0xa6, 0x66, 0x58,
+	0x5e, 0x06, 0xb4, 0x61, 0x19, 0x14, 0xfe, 0x5d, 0x94, 0xe1, 0x39, 0x82, 0xdd, 0x07, 0xc6, 0x0d,
+	0xfe, 0x01, 0x3e, 0x48, 0x98, 0x1f, 0x24, 0x6c, 0xc8, 0xfb, 0x99, 0xe9, 0xfd, 0x62, 0xe6, 0xa2,
+	0x4e, 0xc3, 0xb3, 0x6f, 0xbd, 0xea, 0xe7, 0x56, 0xeb, 0xee, 0xce, 0x24, 0xbb, 0x3a, 0x2f, 0xeb,
+	0x55, 0xdd, 0xe8, 0x3f, 0xc2, 0xde, 0x32, 0xbc, 0x34, 0x66, 0x57, 0xf0, 0xcd, 0x32, 0x3e, 0xef,
+	0x88, 0x6f, 0x60, 0x4f, 0xc1, 0xe9, 0x70, 0xc8, 0xd2, 0xb4, 0x9f, 0xea, 0x91, 0x66, 0xb6, 0xcd,
+	0x8e, 0x4d, 0x9a, 0x72, 0xb7, 0x2b, 0x36, 0xf5, 0x48, 0x72, 0x5e, 0x20, 0xa8, 0xca, 0xdf, 0xbb,
+	0xbc, 0x71, 0x50, 0xa9, 0x71, 0xce, 0xc1, 0x66, 0xa1, 0x1f, 0x47, 0x41, 0xc8, 0xf5, 0x5b, 0xf8,
+	0x62, 0x9d, 0x1f, 0x4f, 0xf7, 0x4c, 0xa1, 0x48, 0x81, 0x77, 0x7c, 0xa8, 0xeb, 0x30, 0xde, 0x87,
+	0xf7, 0x94, 0x3f, 0xfd, 0xd2, 0xa1, 0x5b, 0x2a, 0xd6, 0x93, 0x4d, 0x5b, 0xa4, 0x50, 0x3e, 0x56,
+	0x95, 0xc8, 0x53, 0x28, 0x1f, 0x0b, 0xc9, 0xd9, 0x96, 0x1a, 0x3b, 0xd9, 0xda, 0x83, 0xbf, 0xea,
+	0x5a, 0xd6, 0xa0, 0x2a, 0xfe, 0x95, 0x7c, 0xfd, 0x26, 0x00, 0x00, 0xff, 0xff, 0x35, 0x1f, 0x84,
+	0x1b, 0x00, 0x09, 0x00, 0x00,
 }
diff --git a/api/mesh/v1alpha1/dataplane.pb.validate.go b/api/mesh/v1alpha1/dataplane.pb.validate.go
index 36804ecc8..df4ba5598 100644
--- a/api/mesh/v1alpha1/dataplane.pb.validate.go
+++ b/api/mesh/v1alpha1/dataplane.pb.validate.go
@@ -364,6 +364,10 @@ func (m *Dataplane_Networking_Ingress) Validate() error {
 
 	}
 
+	// no validation rules for PublicAddress
+
+	// no validation rules for PublicPort
+
 	return nil
 }
 
diff --git a/api/mesh/v1alpha1/dataplane.proto b/api/mesh/v1alpha1/dataplane.proto
index 96034ef2d..0b49c1e51 100644
--- a/api/mesh/v1alpha1/dataplane.proto
+++ b/api/mesh/v1alpha1/dataplane.proto
@@ -30,13 +30,19 @@ message Dataplane {
         string mesh = 3;
       }
       repeated AvailableService availableServices = 1;
+
+      // PublicAddress defines IP or DNS name on which Ingress is accessible to
+      // other Kuma clusters.
+      string publicAddress = 2;
+      // PublicPort defines port on which Ingress is accessible to other Kuma
+      // clusters.
+      uint32 publicPort = 3;
     }
 
     // Ingress if not nil, dataplane will be work in the Ingress mode
     Ingress ingress = 6;
 
     // Public IP on which the dataplane is accessible in the network.
-    // Host names and DNS are not allowed.
     string address = 5;
 
     // Inbound describes a service implemented by the dataplane.
diff --git a/api/mesh/v1alpha1/dataplane_helpers.go b/api/mesh/v1alpha1/dataplane_helpers.go
index 30cc0876d..6ad399f60 100644
--- a/api/mesh/v1alpha1/dataplane_helpers.go
+++ b/api/mesh/v1alpha1/dataplane_helpers.go
@@ -338,6 +338,13 @@ func (d *Dataplane) IsIngress() bool {
 	return d.Networking.Ingress != nil
 }
 
+func (d *Dataplane) HasPublicAddress() bool {
+	if d.Networking.Ingress == nil {
+		return false
+	}
+	return d.Networking.Ingress.PublicAddress != "" && d.Networking.Ingress.PublicPort != 0
+}
+
 func (d *Dataplane) HasAvailableServices() bool {
 	if !d.IsIngress() {
 		return false
diff --git a/api/system/v1alpha1/zone.pb.go b/api/system/v1alpha1/zone.pb.go
index 5e6d54b88..8cf14f42e 100644
--- a/api/system/v1alpha1/zone.pb.go
+++ b/api/system/v1alpha1/zone.pb.go
@@ -23,10 +23,9 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
 // Zone defines the Zone configuration used at the Global Control Plane
 // within a distributed deployment
 type Zone struct {
-	Ingress              *Zone_Ingress `protobuf:"bytes,2,opt,name=ingress,proto3" json:"ingress,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}      `json:"-"`
-	XXX_unrecognized     []byte        `json:"-"`
-	XXX_sizecache        int32         `json:"-"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
 func (m *Zone) Reset()         { *m = Zone{} }
@@ -54,70 +53,18 @@ func (m *Zone) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_Zone proto.InternalMessageInfo
 
-func (m *Zone) GetIngress() *Zone_Ingress {
-	if m != nil {
-		return m.Ingress
-	}
-	return nil
-}
-
-// Configure the Zone's Ingress
-type Zone_Ingress struct {
-	// The public load balancer address of the Zone Ingress
-	Address              string   `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Zone_Ingress) Reset()         { *m = Zone_Ingress{} }
-func (m *Zone_Ingress) String() string { return proto.CompactTextString(m) }
-func (*Zone_Ingress) ProtoMessage()    {}
-func (*Zone_Ingress) Descriptor() ([]byte, []int) {
-	return fileDescriptor_0b77e158d4963c0f, []int{0, 0}
-}
-
-func (m *Zone_Ingress) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Zone_Ingress.Unmarshal(m, b)
-}
-func (m *Zone_Ingress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Zone_Ingress.Marshal(b, m, deterministic)
-}
-func (m *Zone_Ingress) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Zone_Ingress.Merge(m, src)
-}
-func (m *Zone_Ingress) XXX_Size() int {
-	return xxx_messageInfo_Zone_Ingress.Size(m)
-}
-func (m *Zone_Ingress) XXX_DiscardUnknown() {
-	xxx_messageInfo_Zone_Ingress.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Zone_Ingress proto.InternalMessageInfo
-
-func (m *Zone_Ingress) GetAddress() string {
-	if m != nil {
-		return m.Address
-	}
-	return ""
-}
-
 func init() {
 	proto.RegisterType((*Zone)(nil), "kuma.system.v1alpha1.Zone")
-	proto.RegisterType((*Zone_Ingress)(nil), "kuma.system.v1alpha1.Zone.Ingress")
 }
 
 func init() { proto.RegisterFile("system/v1alpha1/zone.proto", fileDescriptor_0b77e158d4963c0f) }
 
 var fileDescriptor_0b77e158d4963c0f = []byte{
-	// 138 bytes of a gzipped FileDescriptorProto
+	// 83 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2a, 0xae, 0x2c, 0x2e,
 	0x49, 0xcd, 0xd5, 0x2f, 0x33, 0x4c, 0xcc, 0x29, 0xc8, 0x48, 0x34, 0xd4, 0xaf, 0xca, 0xcf, 0x4b,
 	0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xc9, 0x2e, 0xcd, 0x4d, 0xd4, 0x83, 0x28, 0xd0,
-	0x83, 0x29, 0x50, 0xca, 0xe4, 0x62, 0x89, 0xca, 0xcf, 0x4b, 0x15, 0xb2, 0xe1, 0x62, 0xcf, 0xcc,
-	0x4b, 0x2f, 0x4a, 0x2d, 0x2e, 0x96, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x36, 0x52, 0xd2, 0xc3, 0xa6,
-	0x5e, 0x0f, 0xa4, 0x58, 0xcf, 0x13, 0xa2, 0x32, 0x08, 0xa6, 0x45, 0x4a, 0x99, 0x8b, 0x1d, 0x2a,
-	0x26, 0x24, 0xc1, 0xc5, 0x9e, 0x98, 0x92, 0x02, 0x36, 0x88, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08,
-	0xc6, 0x75, 0xe2, 0x8a, 0xe2, 0x80, 0x19, 0x93, 0xc4, 0x06, 0x76, 0x93, 0x31, 0x20, 0x00, 0x00,
-	0xff, 0xff, 0x46, 0x49, 0xd4, 0x98, 0xb1, 0x00, 0x00, 0x00,
+	0x83, 0x29, 0x50, 0x62, 0xe3, 0x62, 0x89, 0xca, 0xcf, 0x4b, 0x75, 0xe2, 0x8a, 0xe2, 0x80, 0x89,
+	0x25, 0xb1, 0x81, 0x35, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xd6, 0x08, 0x45, 0x4e,
+	0x00, 0x00, 0x00,
 }
diff --git a/api/system/v1alpha1/zone.pb.validate.go b/api/system/v1alpha1/zone.pb.validate.go
index 38448f3d9..9917a365c 100644
--- a/api/system/v1alpha1/zone.pb.validate.go
+++ b/api/system/v1alpha1/zone.pb.validate.go
@@ -43,16 +43,6 @@ func (m *Zone) Validate() error {
 		return nil
 	}
 
-	if v, ok := interface{}(m.GetIngress()).(interface{ Validate() error }); ok {
-		if err := v.Validate(); err != nil {
-			return ZoneValidationError{
-				field:  "Ingress",
-				reason: "embedded message failed validation",
-				cause:  err,
-			}
-		}
-	}
-
 	return nil
 }
 
@@ -109,70 +99,3 @@ var _ interface {
 	Cause() error
 	ErrorName() string
 } = ZoneValidationError{}
-
-// Validate checks the field values on Zone_Ingress with the rules defined in
-// the proto definition for this message. If any rules are violated, an error
-// is returned.
-func (m *Zone_Ingress) Validate() error {
-	if m == nil {
-		return nil
-	}
-
-	// no validation rules for Address
-
-	return nil
-}
-
-// Zone_IngressValidationError is the validation error returned by
-// Zone_Ingress.Validate if the designated constraints aren't met.
-type Zone_IngressValidationError struct {
-	field  string
-	reason string
-	cause  error
-	key    bool
-}
-
-// Field function returns field value.
-func (e Zone_IngressValidationError) Field() string { return e.field }
-
-// Reason function returns reason value.
-func (e Zone_IngressValidationError) Reason() string { return e.reason }
-
-// Cause function returns cause value.
-func (e Zone_IngressValidationError) Cause() error { return e.cause }
-
-// Key function returns key value.
-func (e Zone_IngressValidationError) Key() bool { return e.key }
-
-// ErrorName returns error name.
-func (e Zone_IngressValidationError) ErrorName() string { return "Zone_IngressValidationError" }
-
-// Error satisfies the builtin error interface
-func (e Zone_IngressValidationError) Error() string {
-	cause := ""
-	if e.cause != nil {
-		cause = fmt.Sprintf(" | caused by: %v", e.cause)
-	}
-
-	key := ""
-	if e.key {
-		key = "key for "
-	}
-
-	return fmt.Sprintf(
-		"invalid %sZone_Ingress.%s: %s%s",
-		key,
-		e.field,
-		e.reason,
-		cause)
-}
-
-var _ error = Zone_IngressValidationError{}
-
-var _ interface {
-	Field() string
-	Reason() string
-	Key() bool
-	Cause() error
-	ErrorName() string
-} = Zone_IngressValidationError{}
diff --git a/api/system/v1alpha1/zone.proto b/api/system/v1alpha1/zone.proto
index 3737756f0..22c35eeb4 100644
--- a/api/system/v1alpha1/zone.proto
+++ b/api/system/v1alpha1/zone.proto
@@ -6,13 +6,4 @@ option go_package = "v1alpha1";
 
 // Zone defines the Zone configuration used at the Global Control Plane
 // within a distributed deployment
-message Zone {
-
-  // Configure the Zone's Ingress
-  message Ingress {
-    // The public load balancer address of the Zone Ingress
-    string address = 1;
-  }
-
-  Ingress ingress = 2;
-}
+message Zone {}
diff --git a/app/kumactl/cmd/get/get_zones.go b/app/kumactl/cmd/get/get_zones.go
index 59227dffb..f6a0f6ff3 100644
--- a/app/kumactl/cmd/get/get_zones.go
+++ b/app/kumactl/cmd/get/get_zones.go
@@ -51,7 +51,7 @@ func newGetZonesCmd(pctx *listContext) *cobra.Command {
 
 func printZones(rootTime time.Time, zones *system.ZoneResourceList, out io.Writer) error {
 	data := printers.Table{
-		Headers: []string{"NAME", "INGRESS", "AGE"},
+		Headers: []string{"NAME", "AGE"},
 		NextRow: func() func() []string {
 			i := 0
 			return func() []string {
@@ -63,7 +63,6 @@ func printZones(rootTime time.Time, zones *system.ZoneResourceList, out io.Write
 
 				return []string{
 					zone.GetMeta().GetName(), // NAME
-					zone.Spec.GetIngress().GetAddress(),
 					table.TimeSince(zone.GetMeta().GetModificationTime(), rootTime), // AGE
 				}
 			}
diff --git a/app/kumactl/cmd/inspect/inspect_dataplanes.go b/app/kumactl/cmd/inspect/inspect_dataplanes.go
index e8e589167..cfd1d2c5c 100644
--- a/app/kumactl/cmd/inspect/inspect_dataplanes.go
+++ b/app/kumactl/cmd/inspect/inspect_dataplanes.go
@@ -24,6 +24,7 @@ type inspectDataplanesContext struct {
 	args struct {
 		tags    map[string]string
 		gateway bool
+		ingress bool
 	}
 }
 
@@ -40,7 +41,7 @@ func newInspectDataplanesCmd(pctx *inspectContext) *cobra.Command {
 			if err != nil {
 				return errors.Wrap(err, "failed to create a dataplane client")
 			}
-			overviews, err := client.List(context.Background(), pctx.CurrentMesh(), ctx.args.tags, ctx.args.gateway)
+			overviews, err := client.List(context.Background(), pctx.CurrentMesh(), ctx.args.tags, ctx.args.gateway, ctx.args.ingress)
 			if err != nil {
 				return err
 			}
@@ -59,6 +60,7 @@ func newInspectDataplanesCmd(pctx *inspectContext) *cobra.Command {
 	}
 	cmd.PersistentFlags().StringToStringVarP(&ctx.args.tags, "tag", "", map[string]string{}, "filter by tag in format of key=value. You can provide many tags")
 	cmd.PersistentFlags().BoolVarP(&ctx.args.gateway, "gateway", "", false, "filter gateway dataplanes")
+	cmd.PersistentFlags().BoolVarP(&ctx.args.ingress, "ingress", "", false, "filter ingress dataplanes")
 	return cmd
 }
 
diff --git a/app/kumactl/cmd/inspect/inspect_zones.go b/app/kumactl/cmd/inspect/inspect_zones.go
index e8f831db3..10175829b 100644
--- a/app/kumactl/cmd/inspect/inspect_zones.go
+++ b/app/kumactl/cmd/inspect/inspect_zones.go
@@ -50,7 +50,7 @@ func newInspectZonesCmd(ctx *inspectContext) *cobra.Command {
 
 func printZoneOverviews(now time.Time, zoneOverviews *system.ZoneOverviewResourceList, out io.Writer) error {
 	data := printers.Table{
-		Headers: []string{"MESH", "NAME", "INGRESS", "STATUS", "LAST CONNECTED AGO", "LAST UPDATED AGO", "TOTAL UPDATES", "TOTAL ERRORS"},
+		Headers: []string{"MESH", "NAME", "STATUS", "LAST CONNECTED AGO", "LAST UPDATED AGO", "TOTAL UPDATES", "TOTAL ERRORS"},
 		NextRow: func() func() []string {
 			i := 0
 			return func() []string {
@@ -59,7 +59,6 @@ func printZoneOverviews(now time.Time, zoneOverviews *system.ZoneOverviewResourc
 					return nil
 				}
 				meta := zoneOverviews.Items[i].Meta
-				zone := zoneOverviews.Items[i].Spec.Zone
 				zoneInsight := zoneOverviews.Items[i].Spec.ZoneInsight
 
 				lastSubscription, lastConnected := zoneInsight.GetLatestSubscription()
@@ -78,7 +77,6 @@ func printZoneOverviews(now time.Time, zoneOverviews *system.ZoneOverviewResourc
 				return []string{
 					meta.GetMesh(),                       // MESH
 					meta.GetName(),                       // NAME,
-					zone.Ingress.Address,                 // INGRESS
 					onlineStatus,                         // STATUS
 					table.Ago(lastConnected, now),        // LAST CONNECTED AGO
 					table.Ago(lastUpdated, now),          // LAST UPDATED AGO
diff --git a/app/kumactl/pkg/install/k8s/control-plane/helmtemplates_vfsdata.go b/app/kumactl/pkg/install/k8s/control-plane/helmtemplates_vfsdata.go
index 583a361a3..37bb06ade 100644
--- a/app/kumactl/pkg/install/k8s/control-plane/helmtemplates_vfsdata.go
+++ b/app/kumactl/pkg/install/k8s/control-plane/helmtemplates_vfsdata.go
@@ -21,7 +21,7 @@ var HelmTemplates = func() http.FileSystem {
 	fs := vfsgen۰FS{
 		"/": &vfsgen۰DirInfo{
 			name:    "/",
-			modTime: time.Date(2020, 11, 2, 8, 36, 26, 110673901, time.UTC),
+			modTime: time.Date(2020, 11, 2, 9, 41, 54, 746009812, time.UTC),
 		},
 		"/.helmignore": &vfsgen۰CompressedFileInfo{
 			name:             ".helmignore",
@@ -39,7 +39,7 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/README.md": &vfsgen۰CompressedFileInfo{
 			name:             "README.md",
-			modTime:          time.Date(2020, 11, 2, 8, 36, 26, 110714732, time.UTC),
+			modTime:          time.Date(2020, 11, 2, 9, 41, 54, 743570992, time.UTC),
 			uncompressedSize: 13218,
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xcc\x5b\x5b\x73\xdb\xb6\x12\x7e\xe7\xaf\xd8\x13\x3f\x34\xe9\xb1\xa8\xf4\x3a\x9d\xbc\xb9\xf6\xf4\xd4\xd3\x1e\x8f\x27\x4e\xdb\x07\xc7\x13\x42\xc0\x8a\x42\x04\x02\x2c\x16\x94\xa3\x56\xfd\xef\x67\x16\x24\x25\xdb\xba\x58\x17\xaa\xa7\x7e\x09\x23\x02\xbb\xf8\xb0\x1f\x16\x8b\x5d\xf0\xf6\x5f\xb7\x77\xb7\xe3\xaa\x10\x3d\xe3\x72\x77\xd7\x3c\x57\xde\xdc\x25\xc9\x09\xf0\x7f\x92\xe4\xdd\x08\xe3\x13\xc8\x91\xf0\x01\xa8\x2a\x4b\xe7\x03\x81\x30\x06\xc2\x08\x61\x88\x22\x54\x1e\x09\x84\x55\xe0\xca\xa0\x9d\x25\x28\xbd\x9b\x68\x85\x0a\x06\x53\xc8\xb8\xb7\x0c\x06\xb4\xa5\xc0\xbd\xa4\xb3\xc1\x3b\xd3\x2b\x8d\xb0\x98\xa5\x51\xc3\x13\xe1\x3f\xa2\x29\x60\xf2\xd5\xbf\xd3\x24\x39\x39\x81\x5f\x85\xa9\x90\x92\x64\x06\xd7\xc2\x8b\x02\x03\x7a\xd8\xfa\x6f\x06\x17\x48\xd2\xeb\x38\x32\x38\xd6\x1f\x6b\x19\x8a\xca\x84\x3d\xba\x26\xb3\xde\x1e\x7f\x7b\x75\xfa\x3b\xb5\xcc\x92\x19\x64\xb9\x71\x03\x61\x52\x5d\x88\x1c\x53\x8f\xb9\xa6\xe0\xa7\xd9\x76\x33\xd9\x36\x87\xa1\xf3\x91\x6e\x3f\x31\x0d\xa3\x28\x3a\xdc\x5e\xd9\xd8\xd9\xbc\xa7\x9c\x1c\xa3\xef\x45\xde\xd7\xcf\xe9\x40\xdb\xe0\xc5\x34\xd5\x2e\x5b\x67\xaf\x27\xb8\x82\xc8\xb3\x1d\x18\x12\x44\x7e\x0c\x48\x8d\x16\xab\xcd\x29\xa8\x5a\x15\x41\x70\x70\xce\x4b\x2b\x3d\x2b\xcb\x5f\xd1\xd3\x86\x35\x10\x71\x95\x22\xc8\xd1\xcd\x94\x02\x16\x57\xa2\x40\x2a\x85\xc4\xec\x19\x8d\xd7\xdc\x27\xfa\x02\x8f\x06\x05\x21\xd8\xb6\x2b\xdc\xeb\x50\xbf\x8a\x40\x29\x0a\x06\x23\x06\x68\x76\xb6\x57\xf0\x15\x66\xb0\xd7\xfa\x82\xac\xf1\x39\xd7\xec\x72\x52\xe3\xf2\x9f\x71\x82\xe6\x19\x1e\xc6\x21\x9f\x5f\x83\x71\x39\x18\x6e\xff\x06\x9c\x45\x70\x43\x70\xc3\xe1\xfb\x99\xb6\x43\xf7\x7e\xa6\x70\x50\xe5\x07\xf1\x90\xe5\x74\x83\xab\x70\xea\xf9\x19\x5a\xe0\xe2\xe6\x34\xc7\x44\x41\x58\x25\x8c\xb3\xf8\x7e\xe6\xb1\x70\x01\xdf\xcf\x6a\x96\xef\x89\x6b\x21\x30\x3b\x10\xd7\x1f\xdb\xc8\x68\x70\x71\xdb\xc8\xbf\x63\xf9\x79\xab\xcd\x9e\x5d\x97\x70\x8d\x15\xfd\x27\xce\xf0\x99\x52\x1e\x89\xb2\xd5\x1a\x7f\x79\xfb\x33\x1b\xa8\x6e\x3a\xb7\x5e\xd7\xb8\xf6\xef\xba\x84\xcb\x3a\x85\x37\x68\x50\x06\xe7\xb3\xf5\x1a\xaf\x9c\x42\x68\xdb\x45\x8f\x38\x77\x14\xe7\xb5\x38\x88\xf2\xa0\x74\x8a\xf6\x5f\x5f\x7f\xc2\xb8\x1a\xa0\xb7\x18\x90\x52\xed\xfa\x8e\xde\x80\xd1\xb6\xfa\x74\xfa\xe4\x85\xf0\x72\xf4\x06\x44\xa1\xbe\xfd\x1a\xfe\xca\x56\xe0\xd2\xf6\x63\x1c\xeb\x0f\x42\x9b\xca\xe3\xb5\x33\x5a\x2e\x6d\x66\x33\x68\x5e\x43\x19\xdf\xb3\xe9\x18\x57\x51\x05\x11\xb4\xcd\xe1\x1e\x07\x23\xe7\xc6\xa0\x8b\xd2\x60\x81\x36\xd4\x61\xd2\x1c\xfb\x65\xa3\x05\xa4\x2b\x4a\x67\xd1\x86\xd5\xb8\x2e\x73\xeb\xfc\x1e\x1e\x71\x19\x17\xa1\x9f\x68\x89\x29\x2f\x9b\x0d\xf6\xba\xa9\x9b\xd5\xab\xab\x41\xb5\xc2\x5a\xff\x9c\xf5\xd5\xe2\x0a\xd3\x72\x1b\x5c\xdc\xec\x78\xb8\xce\x4d\x45\x01\xfd\xe5\x75\x77\xb8\x84\xb5\x8e\x49\xe5\xec\x0a\xd7\x31\x83\x33\xa5\x34\xbf\x14\x06\x1e\xb4\xe4\x90\xa0\xac\x02\x38\xbb\x0e\x68\x23\x7e\x4b\x5c\x7f\xfe\xd5\x99\xdf\xa8\xb7\x9b\xb7\x71\xf3\xb9\x99\x5a\x79\xb3\x8a\x97\xab\x79\x58\x3b\xc7\x5e\xdd\x17\xb8\xf3\x3f\x88\x87\xeb\x70\x3d\xe2\xe5\x6a\x1e\x76\x8f\xeb\x67\x27\xd4\xf7\xc2\x08\x2b\x77\x39\x45\xed\x84\x8b\xcf\x70\x0f\x70\x5d\x3b\x1f\xe9\x76\x3f\xd2\x72\xb4\x0a\x91\x26\xc0\x4f\xa5\x23\x54\x07\xe0\xfa\xe6\xdb\xef\xbe\x39\xb2\xbd\x1e\xad\xb7\x2d\xd7\xd7\x0a\xb8\xff\xb7\xf5\xd5\x9e\x0a\x52\x1a\xeb\xf2\xbf\x48\xa3\x73\x8f\x71\xd0\xd9\x23\x8d\xbf\x8d\x30\x8c\xd0\x83\xf3\x60\x5d\x60\x3c\xdc\x1e\x64\x6c\x6c\xf3\x08\xab\x11\x05\x2c\x65\xcf\x7d\xb9\xbb\x78\xde\x23\xb9\xca\x4b\xa4\x6c\xa3\xc6\x77\xec\xee\xbe\x23\x98\x37\x07\x2a\x51\xc6\xc0\xa3\xb3\xa0\xaa\x3d\x7f\xe9\xe1\x10\x3d\xc1\x40\x30\xa9\x9d\x8d\xb1\xf6\xce\xb8\x82\xa1\x34\x47\x8b\x5e\x98\x94\x50\x7a\x0c\x57\xcb\x3b\x34\xfb\x0d\x7e\x05\x61\x24\x42\xcc\xad\x08\xcd\x2c\x34\x94\x4a\x1f\x4e\x61\x8c\x53\x7e\x88\xe9\x19\x29\xe2\x23\x23\x2e\xbd\x0b\x28\xa3\x3d\xeb\x33\xa8\xed\xc9\x7a\x87\xe2\xb8\xa3\xa8\xac\x96\xe2\x41\xc6\xa4\xc1\x55\x8f\x86\x23\x16\x16\x47\x68\x86\x3d\xd2\xb9\xdd\xb8\x70\x37\xe3\x92\xe2\xfb\xca\x2a\xb3\xcc\x84\x19\x7c\x2f\x08\xbf\xfd\x1a\xd0\x4a\xa7\x50\xc1\xf9\x19\x48\xf4\x41\x0f\x79\x64\x08\x2f\x99\x86\xc4\x5b\x80\x20\xd0\x16\x9e\x99\xb9\x93\x1a\xfb\xab\xd5\xf6\xea\x0e\x97\x28\x35\xbb\x0b\xf4\xeb\x2c\xb6\xad\xbd\x56\x19\xe9\xec\xfa\x92\xc9\xf4\xe3\xbb\x77\xd7\x37\x5b\xf1\x50\x54\xc1\x49\x67\x87\x3a\xaf\x3c\x2a\x18\x7a\x57\xc0\xf2\xdc\xec\x86\x4b\x1a\x8d\x36\x9c\xa3\x0f\x74\xf3\x00\xe2\x1a\x5c\x46\x53\xe0\xcd\x2c\x2d\xb1\x78\x68\x3f\x6a\xda\x09\x0b\x42\x4a\x24\x02\xa1\x0a\x6d\x01\xad\x2a\x9d\xb6\x81\xb8\xd3\x32\xe8\x4e\xf7\x65\xc6\x35\x3f\x83\xad\xb3\xda\x9e\xf6\x92\xde\x11\xc1\xa6\x25\x75\x5c\x7b\x8d\x15\xd5\x7b\xce\x79\x34\xd7\xd6\xb8\x1a\x17\x51\xef\xd5\xf7\x82\xa0\x62\x0f\xc6\x7b\x80\xce\x2d\xfc\x74\x71\xd3\x9e\x43\xa9\x9e\x2f\xf8\x85\xdf\x33\xf8\xf3\x6b\x98\xa0\xaf\xcd\x3b\x47\xd9\xa9\xbd\xea\x6c\x5b\x59\x19\xb3\xfa\xe8\xf5\x24\xbf\x71\xc9\xcd\xaf\xe7\xad\x3b\x3e\x2f\x67\x97\xc3\x2b\x17\xae\x3d\x12\xda\x90\x75\x80\xeb\x99\xec\xe8\x02\x57\x6c\xbe\xc8\x8e\x76\x9f\xdf\x38\x65\xa3\x13\xec\x98\xfd\x59\x8f\xab\x74\xa4\x83\xf3\xcf\xd9\xab\xc5\xd5\x36\xef\xd8\x5e\x31\xc7\x2b\xcb\xac\x2b\x1e\x3e\x93\xf5\x7d\x8a\x2b\x88\xfc\x58\xf9\xa8\xae\xec\x85\x76\xf2\xab\xf0\xf4\x5c\xbe\xf7\x41\xdc\x8b\x76\xa2\xbd\xb3\x05\xda\x00\x13\xe1\xb5\x18\x98\xd6\xb3\xdf\x6b\x63\x60\x80\x50\x0a\x6a\x3c\x08\x6f\xd8\x8d\x3e\x28\x9f\x39\x52\x1f\x1c\xf7\x5a\x9d\xa2\xe5\xe1\xa8\x6c\xdb\x99\xbc\x6c\xea\x53\xd1\x6e\x31\x71\x7d\x7e\x75\x19\xab\x56\x28\x14\x6f\x47\xa5\x77\x9f\xa6\xa0\xad\x9e\xfb\xcb\x1d\x8f\x50\x91\x87\x43\x61\x68\x9f\xc0\x77\x8e\x4b\x8e\x58\xf3\xee\xb8\x6a\x34\xd0\x74\xdf\x26\x24\xfd\x7b\x71\x59\x0c\x17\xda\x67\x5b\x6b\xbc\x89\x9b\x17\xce\xad\xc4\x18\x95\xf6\x31\x79\x36\xed\x0e\x57\x1f\x83\xec\x4b\xab\xfb\x45\x65\x42\x45\x7d\x8b\x21\xdd\x66\xf2\xe7\xb8\x06\xda\xee\x8d\x6b\xa0\xad\xf0\xd3\xce\x61\x45\x5c\x13\xe1\xfb\x46\x0f\x22\xb6\x81\xb6\xd9\xce\x3c\x74\x76\x78\xb5\x29\x65\xb8\x01\x57\x1b\xe4\xd4\xa1\x42\x77\xf9\xfa\xb9\x9f\x6f\xc6\x97\xed\xc1\xc3\xad\xca\x43\x0f\x33\x7b\x57\x97\x47\xad\x11\x75\x52\x27\xe2\xf5\xb5\x4d\x5a\xfe\xd9\xfc\x3c\xa3\x3d\x20\x21\xdf\x75\x7e\xde\xea\x5d\x8a\xcb\x73\x7b\x1d\x33\x86\x6a\x70\x35\xe5\x64\xbd\xab\xd1\x96\x70\x6d\x0c\x9f\xd6\xe0\x3a\x46\x0c\xd5\xe0\x32\x6e\x30\x76\x13\x6d\xa6\xa2\xdf\x78\x5d\x5e\x6d\xd9\xae\xb8\xb6\x2a\x9a\xcf\xf3\x36\x0b\x6c\xc7\x8a\xa3\xb2\xd7\xe9\xeb\xf4\xcb\x7d\xf7\x2f\x25\x82\xd8\x21\x98\x5f\xe4\xa3\x38\xd6\xb8\x38\x5e\x4c\x7f\x68\x7c\xb8\x8c\xeb\x39\x36\xae\xc6\xd5\x35\x1f\x0f\x8d\xe7\x9f\xe2\x7a\x9e\x8d\xab\x70\x75\xcf\xc5\x0e\xed\x65\x75\xb8\xdc\x82\x8b\x4f\x70\x71\x70\x7b\x04\x32\x1e\x07\xd7\x26\x2e\x6e\xc0\xd5\x21\x19\x5b\x1e\xb2\xfc\xec\x30\x1e\xce\x71\x6d\xe6\xe2\x5a\x5c\x9d\x92\xf1\x50\x7b\x69\x9b\x7b\x24\xda\xe1\x0c\x36\x83\xcb\x21\x04\x5f\xe1\x29\xe8\x00\x0a\x4b\xe3\xa6\x04\x97\xb5\x9c\x18\x7d\xec\x98\x52\x5b\xa3\x25\x1e\x53\xf6\x3e\x57\xb6\xb8\x94\x17\xda\xbe\xd3\xc5\x36\xf7\x52\xb8\x59\x04\x50\x27\xd5\x9c\x51\x31\x2b\x8a\x7c\x7a\x8c\xa7\x64\x0a\xcd\x59\x59\xc8\xa0\x27\x31\xa1\x1d\xe5\x6b\x9b\x6f\x8f\xeb\xab\xd7\x74\xc0\x79\xb9\xc5\xb5\xd5\x55\x80\x0d\x75\xd8\xd6\x5e\x9d\xf2\xb0\x43\x5c\x1b\xaf\x02\x6c\xa8\xc3\x76\x8f\xeb\xb0\x3a\xec\x53\x5c\x8f\x4a\xae\x6b\x34\x3e\xae\xc3\xb6\x88\x3a\x28\xbe\x3e\xd2\xf2\xc5\xeb\xd7\xaf\xbf\xe8\xcc\x5e\x1b\xaf\x38\x2c\xe7\xa3\xd6\xd7\x61\x5b\xb8\xbb\x14\x5f\x3b\xcc\x47\xb5\xb8\x0a\xa4\xd1\xb6\xe7\xca\x58\x5b\x0d\xae\xb1\xd7\x85\x08\xa2\xce\x9a\xb5\x50\x06\x68\x9c\xcd\x23\xd0\x03\xec\xa5\xf6\xbf\xb7\x9c\x9c\x9c\xc0\x79\x45\xc1\x15\xf0\xb6\xa9\xa9\xc2\x05\x0e\x79\x4f\x62\x0b\x24\xc9\x59\x9b\x4d\x3b\x7f\x7b\x41\x20\x3c\x82\x71\x42\xa1\x82\x89\x16\xd1\x2a\xb7\x99\xf4\x8a\xb2\xbb\x97\xfc\xcf\xab\x45\x9a\x23\x85\x1f\x9c\x87\xc2\x79\x04\x85\x41\x68\x83\x0a\xf8\xfc\xeb\x8b\xda\xdd\x3b\xdb\x88\xb4\x2a\xde\x15\x3f\x4d\xca\xfa\xe6\xa9\xc7\x21\x7a\x9e\x91\x5b\x16\x1f\xaf\x91\x2b\x27\xab\x02\x6d\x4d\x8b\xbb\xdb\x11\x9a\xa2\x27\xbd\xba\xab\xef\x96\x5f\xa0\xc1\xa0\x6d\x9e\x24\x67\x04\xa5\xf0\xb1\x58\x75\xcb\x1d\x3f\x23\x30\xba\xd0\x0d\x9d\x16\x1d\x7b\x0f\x7f\x3d\xad\xc7\x11\xdd\xb8\x75\x81\x9d\xb8\x62\x89\xa8\xe0\x7e\x84\x35\xf5\x62\x84\x90\x35\x57\xdc\x35\xcd\x1b\xf0\xe0\x93\xa2\xa2\x47\xbd\x0a\x61\x2b\x61\xcc\x34\x85\xdf\xb8\x7f\x9c\xba\x87\x9d\x7e\x9a\x1f\x89\x9b\x9f\xea\x9b\xf8\x8b\x9a\x76\x74\x58\x22\xc0\x58\x5b\xc5\x3b\xc9\x3d\x1a\x73\x0a\xe4\x20\x8c\x34\x01\x8d\x5c\x65\x54\xc2\x0a\x9d\x45\x90\xc2\xe3\xb0\x62\x75\x49\xf2\xce\x81\x6a\x5a\xc5\xe4\x67\xc6\xa7\x6f\x19\x4c\xc6\xb3\xfd\xb9\xd5\x9f\xa0\x34\x22\xb0\x0d\xe8\x14\x7c\x65\xdf\x40\x92\x64\x59\x46\x23\x34\x26\x69\xda\x42\x8e\x01\xd8\x96\x30\x83\xdc\x63\x19\xbf\x1c\x48\xb5\x83\x19\x04\x0f\x3d\x82\x17\xf0\x02\x66\x20\xab\x00\x3d\x15\xff\xd3\x1b\x7e\x01\x33\xf8\x24\x7c\x4e\xd0\x0a\xa9\x81\xb1\x9c\x24\x39\x01\xde\x38\x79\x3c\x1f\x7f\x5f\xd6\xd2\x73\xf0\x91\x9c\x85\x19\x7c\xfc\x1d\x3e\x4b\x75\xc0\x82\x6e\xef\xd2\x02\x83\xe0\xc8\x2a\x6e\x63\x30\x03\x8a\x49\x8c\x97\xe9\x2c\x20\x85\x97\x2f\xd2\xcf\x79\x58\xef\xdf\xa7\xda\xbd\x78\xf5\xea\xb3\x4d\xfa\xb3\x2c\x8b\x34\xb9\x72\x01\xe7\x97\xa9\x41\xe1\x04\x8d\x2b\xd1\x53\xb2\xf8\x7a\xa1\x26\x78\x2c\x97\x69\x1b\xd0\x5b\x36\x23\x68\xbb\xf4\x01\x44\x76\xca\xb4\xf0\x38\x64\x7a\xc7\x4f\x28\x9c\x31\xee\x9e\x77\x7b\x5f\x19\x36\x68\x59\x9a\x69\xcd\x9f\x46\x13\xbf\xb3\x78\xcf\x8a\xc2\xfc\x8b\x8b\x37\x09\x7c\xce\xfa\x20\x2b\xc4\x18\xe7\x35\xec\x7e\xa3\xae\x3d\x9d\xf7\xc7\xdf\x51\xff\xf1\x37\x17\xb1\x9e\x37\xb5\x12\xe6\x8b\xa4\xc6\xc5\x8c\x5c\x1a\x2d\x04\x2c\xd8\xf2\x48\xac\x2f\x7e\xf6\xd1\xfe\x50\x33\x8d\x02\xf7\xad\x39\x53\x7a\xec\x65\xb5\x9c\xd2\x51\xe0\x67\x8f\xe0\x0a\x1d\xe6\x4b\xa2\xf4\x4e\x22\x11\x43\x5a\x35\x39\x00\x49\xb2\xf8\x0e\xe5\x0d\x8c\x42\x28\xe9\x4d\xbf\xdf\x30\xa9\x9f\x3c\xf8\x60\xe5\xf1\xdb\x5e\x59\x0d\x8c\x96\x3d\x41\x84\x81\x52\xfa\x2a\x15\x85\xf8\xc3\x59\x71\x4f\xa9\x74\x45\x7f\xde\xaf\x37\xf9\x32\x2d\x6d\x9e\x2c\x7c\xc1\x42\x10\xff\x94\xd2\xa8\xaf\x9c\xa4\x7e\xb4\xeb\x87\x01\x52\xf8\x50\x7a\x0e\xce\x24\x52\x5f\x46\x8f\xf7\xa1\x5d\x71\x1f\xd4\xc2\xe3\xf5\x93\xd5\x5e\x62\x8d\xf8\xe0\x4a\xdd\x6a\xa1\xfe\xc9\x83\x1e\x3d\x67\x59\x08\x25\xff\x0b\x00\x00\xff\xff\x6e\xe2\x64\x2e\xa2\x33\x00\x00"),
@@ -148,7 +148,7 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/templates": &vfsgen۰DirInfo{
 			name:    "templates",
-			modTime: time.Date(2020, 11, 2, 8, 36, 18, 432174935, time.UTC),
+			modTime: time.Date(2020, 11, 2, 9, 41, 54, 873542102, time.UTC),
 		},
 		"/templates/NOTES.txt": &vfsgen۰CompressedFileInfo{
 			name:             "NOTES.txt",
@@ -194,7 +194,7 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/templates/cp-deployment.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "cp-deployment.yaml",
-			modTime:          time.Date(2020, 11, 2, 8, 36, 18, 431495417, time.UTC),
+			modTime:          time.Date(2020, 11, 2, 9, 41, 54, 744557158, time.UTC),
 			uncompressedSize: 8690,
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xbc\x59\x4d\x6f\xdb\x3a\x16\xdd\xf7\x57\x10\x46\x17\xef\x01\x63\xb9\x69\x93\x4e\x21\xa0\x0b\xd5\x56\x53\x4d\x6c\xd9\x90\xe4\x00\x99\x8d\xc0\x48\x37\xb6\x60\x8a\x54\x49\xca\x6f\x3c\x69\xff\xfb\x80\x92\x9c\xd8\xb2\x3e\xed\xcc\xcb\x2a\xa1\xc8\x7b\xce\xb9\xbc\x3c\xfc\x08\x4e\xa2\x7b\xe0\x22\x62\x54\x47\x38\x49\xc4\x68\x7b\xf5\x6e\x13\xd1\x50\x47\x13\x48\x08\xdb\xc5\x40\xe5\xbb\x18\x24\x0e\xb1\xc4\xfa\x3b\x84\x28\x8e\x41\x47\xcf\xcf\x28\xa2\x01\x49\x43\x40\x83\x4d\x1a\x63\x4d\x35\x0f\x90\x86\x7e\xff\x1e\x06\x8c\x4a\xce\xc8\x30\x21\x98\x42\x31\x42\x24\x38\xc8\x87\x69\x0e\x10\xc0\x02\x34\x7b\xdf\x8c\x7e\xff\x7e\x87\x10\xc1\x8f\x40\x84\x42\x40\xe8\xf9\x79\x58\x0a\x9f\x7f\x55\x00\xbf\x10\x8d\x68\x08\x54\xa2\xeb\x7c\x20\x52\xbc\x75\xa4\xba\x95\xa0\x45\x02\x81\x0a\x28\x24\xc7\x12\x56\xbb\x3c\x38\x67\x84\x44\x74\xb5\x4c\x42\x2c\x21\x6f\x42\x28\xc6\xff\x71\x53\xbe\x02\x1d\x5d\xbd\xb6\x2c\x29\xde\xe2\x88\xe0\x47\x02\x3a\xfa\xa0\x02\x01\x81\x40\x32\x9e\x8f\x8a\xb1\x0c\xd6\xd3\x03\xda\x55\xc4\xf7\x43\xa6\x15\x02\x3e\xef\x05\xd4\x4b\x40\x48\x42\x9c\x90\x17\xa6\x87\x33\x91\x8d\xa3\x94\x49\x2c\x23\x46\x5f\x38\x20\x14\xac\x21\xd8\x88\x34\x1e\x05\x8c\x3e\x45\xab\xa3\xd9\xfa\x23\xe1\x11\x95\xe8\xbd\xe6\x15\x71\xb5\x6f\x58\xc0\x02\xcb\x35\x1a\x8c\x82\x64\x98\x0f\x89\x71\xa2\xed\x70\x4c\x06\x7f\x66\x84\xc5\x1a\x7f\xbc\xf9\x2c\xd2\xf8\x95\xf0\x01\x8a\x24\x62\x28\x20\xe0\x20\x45\x2f\xa8\xbf\xe0\x71\xcd\xd8\x46\x0c\x31\x0d\xf7\x01\x5a\x50\xc9\x51\xb6\xfb\xe6\xfb\xcb\x21\xfd\xfa\x8c\x23\xb4\x2f\x9c\xec\x77\xe0\xdb\x28\x00\x23\x08\x58\x4a\xa5\xdd\xbb\xfa\xf7\x34\xff\x8a\xe4\x1a\x69\xf7\x98\xa4\x20\xb4\xa2\xd3\x42\xf5\xd1\x28\x0b\xc1\x2d\x68\xbf\x32\x3c\x6c\x3d\x14\x8c\x24\x7b\xc0\x31\xa9\x13\xa6\xa0\x80\x86\xaf\x0d\x0a\x0a\x47\x14\xf8\x41\xda\x86\xc5\x2a\xae\xe2\xaa\x7e\xa2\x18\xaf\xaa\x64\x3e\x31\x1e\x63\x69\xa9\xaf\x03\xf4\x47\x18\x05\x12\x0d\xa2\xfc\xaf\x4a\x65\xd9\x37\x34\xe0\x8c\xc9\x01\x7a\xff\x27\xfa\x85\x7e\xa6\x4c\xc2\xe1\x34\x14\x60\x8b\x94\x90\x05\x23\x51\xb0\xcb\x4d\xa2\x36\x9a\x96\xbc\xf4\x3c\x0e\x03\x74\xab\x1f\xfc\xf9\x2a\xf2\x6e\x39\x33\x7c\xd3\xbe\xb7\x9c\xb9\x3d\x33\x6d\xef\xa8\x13\x42\x5b\x85\xa4\x2b\x81\x8f\xc0\x29\x48\x10\x83\xfa\x30\xae\x37\x77\x4c\xdf\x7b\x58\x98\x97\x47\xb9\x5b\x7e\x33\x1d\xdb\xf4\x4c\xd7\x77\x1f\x5c\xcf\x9c\xf9\xb6\x31\x33\xdd\x85\x31\xae\x09\x5e\x6d\x9e\x95\x39\x2d\x01\xde\x9a\xb6\xe9\x18\x53\xdf\x98\xdc\x9b\x8e\x67\xb9\xe6\xc4\xff\x31\x77\x3d\x85\x57\x0b\xd5\xad\xc0\xb5\x06\x47\x6f\x21\xe3\x4d\x5d\x7f\x6c\x3a\x9e\xff\xdd\x9a\xd6\xd0\x18\x6d\x31\x1f\xf1\x94\x8e\x0a\x77\x18\x65\x5c\x22\x96\x59\x4e\x00\x5c\xaa\x5f\xb4\x80\xcb\x6e\x68\x77\xe6\xc3\xc5\x60\x1b\xd8\x1d\x0d\xcf\x1c\xe8\x09\xc1\xcf\xea\x9a\x8d\x99\x4a\x21\x87\x98\x49\x18\x34\xa6\x65\xb6\x9c\x7a\xd6\x78\xba\x74\x3d\xd3\xf1\x1d\x73\x36\xf7\x4c\xff\x76\x3a\xff\x96\x4d\xdb\xc4\x31\x5d\xb7\xbe\x2a\xaa\x90\x37\xa1\xb8\x25\xec\x11\x13\x23\x0c\x39\x08\x51\x06\x3f\x31\x8a\x0a\x4e\xc6\xc2\xf2\x5d\xd3\xb9\xcf\x18\x19\x13\x7f\x6e\x4f\x1f\x6a\x0a\x5f\xf2\x14\x1a\x4a\xde\x59\xda\x9e\x35\x3b\x2a\x7a\x63\x32\xb3\x5c\xd7\x9a\xdb\x7b\x88\xc5\xdc\xa9\x5b\x9c\x37\xd7\xd7\x9f\x2e\x8c\x9e\x95\xda\xc4\x72\xce\x9c\xfc\x5e\xe0\x96\xfd\x2f\x73\xec\xcd\x1d\x7f\x6c\x5b\xbe\x69\x1b\xdf\xa6\xe6\xa4\x7d\xf6\x68\xa4\x01\x55\x87\x8d\xb0\xd3\xa2\x6e\xc2\x75\xad\x89\x39\x36\x1c\x7f\x3c\xb7\x3d\xc3\xb2\x4d\xc7\xb7\x66\xc6\x6d\xd7\xc5\xde\xc1\xe6\xd5\x19\xa4\x87\xc7\x97\xa8\xbf\xf0\xb4\x6c\xcb\xfb\x5b\x48\xd2\x28\xef\xda\x93\x68\xe3\xdc\x1a\x97\xdb\x57\x80\x9b\xdd\x6b\x62\x7e\x37\x96\x53\xcf\xf5\xdd\x3b\x6b\xe1\xcf\x4c\xf7\x87\x3f\x76\x4c\xc3\xb3\xe6\x76\x3f\x37\x08\xe1\x09\xa7\x44\x0a\x4d\x6c\xa2\x64\x06\x62\x3d\xe6\x90\x1d\x1b\x3b\xa5\x61\x36\x9f\x98\xfd\xf0\x32\xdf\xab\x09\x5d\x58\x66\xe5\xb8\xff\x32\x0a\xbd\x6d\xf2\xdf\x73\xbb\x27\xbd\x0c\xa6\x81\x5e\x85\x31\x36\xb1\x56\x1b\x03\x4e\x22\x17\xf8\x16\xb8\x96\xcf\xb6\xda\x0c\xbb\x9a\xeb\x0f\xcf\x5b\xb8\x17\x6d\x88\x38\x89\x86\x22\x83\x1f\x76\xdf\x1b\x2b\x19\x9c\xb9\x49\xd6\x11\xa8\xda\x2f\x2f\xca\x6e\x40\x22\xa0\x72\x0c\x5c\x0a\xb7\x77\xa2\x8d\xa5\xf7\xc3\x1f\x4f\x2d\xd3\xf6\xb2\x54\xbb\x67\xec\x08\x07\x4a\x73\x2e\x99\x58\x31\x7a\x0b\x99\x2f\x9b\x76\xbf\x52\x3a\x5a\x14\xc5\xa1\xe1\x6e\x72\x59\x45\x6d\x42\xd1\xbf\xa2\x9a\x88\x9c\x59\x58\x75\x3c\xde\xa8\xb0\x36\xa1\x70\xb2\xd3\xd9\x38\x9b\xcb\xb3\x32\x5e\xd8\x90\x12\xea\xcc\xe7\x9e\xda\x19\xce\x14\x5a\x14\x54\xd3\xfe\x50\xa9\x53\x35\x72\x4c\x57\x80\xde\x6f\x60\xf7\x0f\xf4\x3e\x03\x43\xfa\xd7\x6a\xe1\x40\xb7\xf7\x98\x8b\x3a\x85\xcf\xcf\x59\x18\xf4\x0b\xa5\x49\x02\xbc\xdc\xed\xd0\x5d\x0b\xa0\x4a\x2b\x6d\x63\x0a\x04\x62\x75\x7b\xad\x63\x59\x24\xa8\x89\x65\x11\x42\x33\xe9\xb6\x86\xe5\x77\xce\x62\xbd\xf4\x41\x5d\xea\x55\xe8\x3b\xd8\x39\xf0\x74\xfa\x15\x55\x20\xe4\x5e\x73\x0a\xa2\x7e\x36\xb0\x3b\xee\x7c\x07\xbb\x0e\xa9\xc0\x7c\x25\xca\x57\x56\x9e\xd2\x52\xcb\x70\x48\xd8\x6a\x48\x60\x0b\xe4\x6b\xdd\x76\x46\xd8\x6a\xaa\x3a\x9c\xa6\x6a\x58\x3c\xe8\x0c\x9f\x22\x02\x5f\x47\x20\x83\xd7\x7a\x3b\x79\xfb\x28\xde\x8b\xb2\x37\x98\x83\x38\x09\xe3\xf2\x84\xe8\xcb\xb3\xc2\x82\x71\xa9\xa3\x9b\xcf\x5f\xae\x5a\x7b\x7c\x6c\xe9\x71\x7d\xfd\xa9\x6a\xed\x52\x68\xba\x5b\xad\x32\xbf\xac\xb8\x5b\x9d\xe0\xff\xf3\x4b\x5b\x8f\x9b\x4f\xa5\xd9\x4d\x38\x93\x2c\x60\x44\x47\xcb\xc9\xa2\x6d\x3e\x49\xb4\x05\x0a\x42\x2c\x38\x7b\x84\xe3\x7c\xad\xa5\x4c\x6e\x41\x96\x4b\x2d\xc1\x72\xad\xa3\xd1\x1a\x30\x91\xeb\x5d\xf9\xe3\x3e\x6d\x1f\x0e\x3e\x70\xc0\x61\x74\x16\x88\x1a\xd9\x11\x42\xb0\x94\x07\x50\x9a\xf2\x26\x23\x7d\x19\x72\xea\xbe\x6d\x03\x7e\xed\xdf\xb3\x5e\x5f\xb3\xae\x3e\x56\x1e\xc9\x88\x80\xf6\x9b\x76\x4d\x35\x70\xf8\x99\x82\x28\x57\x31\x42\x41\x92\xea\xe8\xe6\xc3\x87\xb8\xd4\x1e\x43\xcc\xf8\x4e\x47\x1f\x6f\x3e\xcf\xa2\x6a\x2a\x7d\x10\xae\xba\x23\x54\x56\xd6\x96\x91\x34\x86\x19\x4b\xe9\xe9\x42\xcc\xad\x6a\x05\x14\x38\x26\xc3\xca\xeb\x2a\x42\xb1\x1a\xba\xc8\x0b\xa1\xd7\x4d\x37\xaf\xb8\x39\x25\x3b\x1d\xa9\x2b\x7e\x9d\x13\x77\x7b\x2d\x2a\xcc\xa8\x81\x5c\xb3\x41\x75\xa5\xf6\x96\x67\xf5\x8a\x83\xed\x19\xc9\x6d\x8f\xd2\x28\xa6\x72\x1b\xfd\x3f\x9c\x97\x6b\xce\xb6\x97\x09\x6e\x88\xf4\xb6\xa2\xfb\x9f\x9e\x2b\x0e\x97\x67\x68\x6d\x8f\xf2\xe6\x3a\x7b\x9e\x59\x2b\xce\x96\x67\xea\x6c\x8e\xd2\x5d\x67\x6e\x69\xe5\x7f\xe5\x34\x88\x2e\x1c\xae\x46\x6c\x07\x1f\xcc\x07\x1e\xdb\xe7\x6b\xb0\xfa\xb7\x82\x76\xf0\xaa\x3d\xe1\x6d\x08\xd5\xda\xea\x49\xb8\x8a\x42\xba\xd4\x05\xbb\x39\xe0\x25\x69\x6d\x63\x70\x91\xa8\x56\xe3\xeb\x6e\x7a\x6f\xa3\xb1\x95\xd0\x19\x72\xbb\x59\x5e\x37\xbb\xbb\x44\x65\x37\x1e\xe7\x09\xec\xe0\x75\xdd\x7c\xee\x42\x81\x1d\x78\x54\x08\x7c\x83\x43\x52\xde\x30\xc3\xc9\x31\xf5\x33\xe3\xfe\x2f\x00\x00\xff\xff\xad\xf9\xc4\x5d\xf2\x21\x00\x00"),
@@ -208,10 +208,10 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/templates/cp-rbac.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "cp-rbac.yaml",
-			modTime:          time.Date(2020, 11, 2, 8, 36, 18, 432029468, time.UTC),
-			uncompressedSize: 3622,
+			modTime:          time.Date(2020, 11, 2, 9, 41, 54, 873603499, time.UTC),
+			uncompressedSize: 3636,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xd4\x56\x4d\x6f\xdb\x38\x10\xbd\xfb\x57\x10\xde\xdb\x02\x52\xb0\xc0\x1e\x02\xdf\xda\x1e\x7a\x29\x8a\x22\x29\x72\xa7\xa9\x27\x6b\x6a\x6a\xa8\x92\x43\x27\x8d\xeb\xff\x5e\x50\x72\x2c\xc7\x5f\x8d\x95\x04\x6d\x7c\x32\x87\x9a\x99\x37\x9f\x7c\xba\xa1\x1b\xf8\x40\x8e\x27\x6a\xf1\xdf\x68\x4e\x5c\x4c\xd4\x35\xfc\x82\x0c\xde\x19\xe3\x22\xcb\xa8\x86\xe8\x42\x8b\x9e\x8c\x94\x62\x5d\x63\xa2\x96\x4b\x45\x6c\x6c\x2c\xa0\xc6\xf3\x58\xeb\x3c\x89\xc7\x2a\x57\xab\x55\x66\x1c\x8b\x77\x36\x6b\xac\x66\xac\x35\x42\xa3\x4d\xa7\x96\x5f\xc1\x42\x07\xe4\x9f\x1f\xc4\x6a\xb5\x1a\x29\x65\xf5\x14\x36\x24\x0f\xcb\x65\xb6\x63\xbc\xbb\x4b\xe6\x7f\x2a\x26\x2e\xc0\xa2\xfe\x4f\x6a\x59\x96\x8d\xb6\x03\xf0\x53\x6d\x72\x1d\xa5\x72\x9e\xee\xb5\x90\xe3\x7c\x7e\x19\x72\x72\x17\x9b\xd0\x3e\xd8\x18\x04\xfe\xca\x59\x9c\x17\xd7\x64\x37\xae\x41\x88\x7d\xb4\x68\x75\x32\xa5\x1b\xfa\xe8\x5d\x6c\xda\x63\xfa\x65\x6a\x3c\x6e\xff\x7a\x04\x17\xbd\xc1\xd6\xcd\x26\x89\x61\x23\x6a\x5c\xd1\x1f\x42\x57\xb1\x5e\x60\x1c\x97\x34\xab\x75\xd3\x89\x16\xf0\xd3\x2d\x73\x33\xc8\xe6\xbf\xa5\xd0\x1f\x6e\xb5\x98\xea\x7c\x78\x58\x80\xe5\xa0\x27\xe3\xa1\x05\x3d\xe8\x53\xf6\xdb\xd4\x91\x3b\xe6\x24\x95\xaa\x4d\x7e\xd8\x17\x11\x07\x9a\x55\xd2\xdf\xd4\x08\xd5\xd6\x87\xf7\x8e\x77\x4e\x8f\x34\xce\x4d\xcf\xc1\xd8\x62\x53\x1c\x0a\x75\x8d\x14\x16\xed\xe5\x90\xc8\x1b\xef\xee\x7e\x08\xea\xc6\x6a\xc1\x1b\x44\x7c\x11\x44\x4b\xfc\x2d\xf0\x23\x70\x86\xf8\x37\xe4\x4d\x24\x99\x7a\xe8\x39\x7c\x5f\x79\xdc\x09\x3c\x6b\xbb\x37\x2f\xa5\x8e\x56\x88\xbf\xc1\xa4\xb5\xd1\xcb\x2b\x68\x2b\x95\xa9\x60\xe6\xbd\x50\xbc\x2e\x4b\x32\x0d\x7c\x4d\x21\x3c\xfa\x7e\x7d\x65\xdd\x6c\x4f\xe6\x5d\x14\xec\x49\xc5\x6f\xa6\x7a\x48\x4d\xdb\xdd\x53\x2a\x7c\x57\xf9\x8d\xb6\x11\x21\x5f\xef\xa9\x2f\x69\x2c\xf2\xda\xa5\x9d\xe4\x51\x3b\xc1\xb8\xdb\xb4\xcf\xe8\x84\xe4\x0c\x5c\x24\x3b\x6b\xbf\x1b\xa7\x4c\x39\x58\x4f\x2d\x8a\xce\xcb\xe1\xa2\x5d\x76\x5f\x1a\x36\xe5\x89\xe2\x31\xe4\xd6\xf9\x79\xa6\x45\xb4\xa9\x6a\xb0\x64\x05\x4a\x62\xea\x4b\xf3\x22\xed\xbf\x8e\x6b\x2b\xaa\xb3\x17\x5f\x5a\xc2\x17\x25\xb1\xb6\x74\xff\xd0\x67\x3b\xd8\xc6\xff\x8e\x07\x36\x71\xb7\xc3\x5e\xcd\x7c\xbf\x4f\x9f\xe4\xe2\x1f\xb5\xd0\x96\x52\x9b\xa4\x3a\x2a\x71\x73\xb0\x9a\xa2\x74\x1e\x8a\x42\x88\x20\x9e\xa9\xfa\xeb\xa7\x6b\x65\xe0\xe5\x18\xa6\xf4\x3a\x83\x85\xcc\xf6\xf3\x7c\x0c\x61\xeb\xc3\x63\x41\xb8\x3d\xf5\xb8\x3c\x8f\x06\xbc\x27\x2e\x88\x67\x7f\x84\x0d\x38\x8b\x2b\x94\x49\xeb\x21\x55\x27\xd0\x8f\x94\xda\xe7\x30\xe7\x63\x0d\x71\x9a\xb6\xdc\x9a\x85\x1c\x24\x7c\x29\xbb\xe7\x13\xbd\xa7\x51\xbd\x01\xc5\x7a\x01\xb2\xf6\x8a\x24\x74\x28\xa5\x0b\x30\x1e\x7f\x09\xff\x38\x8e\xf2\x99\x3c\x72\x30\xd0\x81\x6d\xf2\x32\xc3\xfc\x94\x6e\x19\x38\xbb\x6f\x73\x68\x7f\x05\x00\x00\xff\xff\xb2\xeb\xf2\xc0\x26\x0e\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xd4\x56\x4d\x6f\xdb\x38\x10\xbd\xfb\x57\x10\xde\xdb\x02\x52\xb0\xc0\x1e\x02\xdf\x76\x7b\xe8\xa5\x28\x8a\xa4\xc8\x9d\xa6\x9e\xac\xa9\xa9\xa1\x4a\x0e\x9d\x34\xae\xff\x7b\x41\x59\xb1\x1c\x7f\x35\x56\x92\xb6\xd1\x49\x1c\x72\x66\xde\x70\x3e\xf8\x74\x43\x37\xf0\x81\x1c\x4f\xd4\xe2\x9f\xd1\x9c\xb8\x98\xa8\x6b\xf8\x05\x19\xfc\x67\x8c\x8b\x2c\xa3\x1a\xa2\x0b\x2d\x7a\x32\x52\x8a\x75\x8d\x89\x5a\x2e\x15\xb1\xb1\xb1\x80\x1a\xcf\x63\xad\xf3\x24\x1e\xab\x5c\xad\x56\x99\x71\x2c\xde\xd9\xac\xb1\x9a\xd1\x69\x84\x46\x9b\xb5\x5a\x7e\x05\x0b\x1d\x90\x7f\x7c\x10\xab\xd5\x6a\xa4\x94\xd5\x53\xd8\x90\x3c\x2c\x97\xd9\x8e\xf1\xf5\x5e\x32\xff\x5d\x31\x71\x01\x16\xf5\x6f\x52\xcb\xb2\x6c\xb4\x1d\x80\x9f\x6a\x93\xeb\x28\x95\xf3\x74\xaf\x85\x1c\xe7\xf3\xcb\x90\x93\xbb\xd8\x84\xf6\xce\xc6\x20\xf0\x57\xce\xe2\xbc\xb8\x26\xbb\x71\x0d\x42\xec\xa3\x45\xab\x93\x29\xdd\xd0\x7b\xef\x62\xd3\x2e\xd3\x97\xa9\xf1\xb8\xfd\xf5\x08\x2e\x7a\x83\xad\x9d\xcd\x25\x86\x8d\xa8\x71\x45\xbf\x08\xeb\x8c\xf5\x02\xe3\xb8\xa4\x59\xad\x9b\x5e\xc4\xae\xe8\x0e\x2c\xe0\xa7\x5b\xc6\x67\x90\xcd\xbf\xa5\xd0\x2f\x6e\xb5\x98\xea\x7c\xb0\x58\x80\xe5\xa0\x27\xe3\xa1\x05\x7d\x08\xa7\xec\xb7\x17\x49\xee\x98\x93\x94\xb8\x36\x15\x61\x5f\x44\x1c\x68\x56\x49\xbf\x53\x23\x54\x5b\x07\xef\x1d\xef\xac\x1e\x69\x9c\x7b\x3d\x07\x63\x8b\x4d\x71\x28\xd4\x0e\x29\x2c\xda\xcd\x21\x91\x37\xde\xdd\x7d\x13\xd4\x8d\xd5\x82\x37\x88\xf8\x22\x88\x96\xf8\x53\xe0\x47\xe0\x0c\xf1\x6f\xc8\x9b\x48\x32\xf5\xd0\x73\xf8\x3e\xf3\xb8\x13\x78\xd6\x76\xaf\x7b\x4a\x1d\xad\x10\x7f\x81\x49\x43\xa4\x97\x57\xd0\x56\x2a\x53\xc1\xcc\x7b\xa1\x78\x5d\x96\x64\x1a\xf8\x9a\x42\x78\x74\xbe\xdb\xb2\x6e\xb6\x27\xf3\x2e\x0a\xf6\xa4\xe2\x37\x3d\x3e\x24\xa7\xed\x24\x2a\x15\xbe\xaa\xfc\x46\xdb\x88\x90\x77\x53\xeb\x53\x6a\x8b\xbc\x76\x69\x42\x79\xd4\x4e\x30\x5e\xcf\xdd\x67\x54\x42\x72\x06\x2e\x92\x9d\xce\xef\xc6\x29\x53\x0e\xd6\x53\x8b\x62\xed\xe5\x70\xd2\x2e\xd7\x27\x0d\x9b\xf2\x44\xf2\x18\x72\xeb\xfc\x3c\xd3\x22\xda\x54\x35\x58\xb2\x02\x25\x31\xf5\xa9\x79\x91\xf2\xef\xe2\xda\x8a\xea\xec\xc1\x97\x46\xf2\x45\x49\xac\x2d\xdd\x3f\xd4\xd9\x0e\xb6\xf1\xdf\xe3\x81\x45\xbc\x9e\x61\xaf\x66\xbe\x9f\xa7\x4f\x72\xf1\x97\x5a\x68\x4b\xa9\x4c\x52\x1e\x95\xb8\x39\x58\x4d\x51\x3a\x0f\x45\x21\x44\x10\xcf\x54\xfd\xf9\xc3\xb5\x32\xf0\x72\x0c\x53\x7a\xab\xc1\x42\x66\xfb\xb1\x3e\x86\xb0\xf5\xe1\xb1\x20\xdc\x9e\x7a\x5c\x9e\x47\x0a\xfe\x27\x2e\x88\x67\xbf\x85\x1b\x38\x8b\x2b\x94\x49\xeb\xe1\xaa\x4e\xa0\x1f\x29\xb5\xcf\x68\xce\xc7\x1a\xe2\x34\x4d\xb9\x8e\x93\x1c\xa4\x7f\xe9\x76\xcf\xa7\x7d\x4f\x23\x7e\x03\x92\xf5\x02\xd4\xed\x15\x29\xe9\x50\x82\x17\x60\x3c\xfe\x10\xfe\x71\x1c\xe5\x0e\xab\xfc\x65\x40\x07\x96\xc9\xcb\x34\xf3\x53\xaa\x65\x60\xef\xbe\xcd\xa6\xfd\x11\x00\x00\xff\xff\x5b\x82\xc3\xe8\x34\x0e\x00\x00"),
 		},
 		"/templates/cp-service.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "cp-service.yaml",
@@ -222,7 +222,7 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/templates/cp-webhooks-and-secrets.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "cp-webhooks-and-secrets.yaml",
-			modTime:          time.Date(2020, 11, 2, 8, 36, 18, 432933644, time.UTC),
+			modTime:          time.Date(2020, 11, 2, 9, 41, 54, 745794754, time.UTC),
 			uncompressedSize: 5312,
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xe4\x58\xdd\x6f\xdb\x36\x10\x7f\xd7\x5f\x41\x18\x2d\xd0\x16\xa0\x14\x27\x71\x90\x09\xe8\x43\xd7\xa6\xc5\xb0\xac\x08\x9a\x2c\x7b\xa6\xa8\x93\xc4\x99\x22\x35\xf2\xe4\xd4\x73\xfd\xbf\x0f\xa4\x3e\x2c\x39\x4e\xe2\x7e\x0c\xcb\x5a\x3f\x25\xf7\xc5\xbb\xfb\xfd\xee\x48\x68\xb5\xa2\xe4\x09\x67\x3f\xd7\x2a\x95\x40\xe2\x97\x24\xbc\x66\xb2\x06\x1b\x72\xad\xd0\x68\x79\x21\x99\x82\x10\xa5\x0d\x73\x50\x60\x98\x0c\x7b\xe3\xf5\x3a\x58\xad\xa2\x17\xc1\x3b\xaf\x40\x20\x1c\x0c\x8a\x4c\x70\x86\x60\x03\x0b\x10\x93\x02\xb1\xb2\x71\x14\x95\xcc\x22\x98\x52\xa8\xd4\x86\xb9\xc0\xa2\x4e\x42\xa1\x23\x5b\x19\x91\x47\xdc\x2c\x2b\xd4\x61\x81\xa5\xdc\x72\x82\x54\xd4\x65\xc8\x75\x19\xa9\x7a\xa1\x69\x6e\x74\x5d\x51\x04\x5e\x44\xa5\x5e\x00\x5d\xea\xda\x50\x77\xa6\xa5\xa8\x69\x01\xb2\xa4\xc7\xd9\x2c\x3b\x99\x1e\x1d\x9d\x32\xce\xc6\xc1\xda\x53\x7d\x30\xc0\x1b\x6d\xe6\x16\xcc\x42\x70\x28\xc1\x16\xbb\x44\x89\xd4\x49\x74\x7a\x70\xcc\xd2\xd9\xc1\xe1\x49\x92\xcc\xd2\x24\x3d\x3c\x9d\xf1\xc3\xc3\x83\x6c\x3a\x3b\xfa\x69\x96\xc1\xe1\x0c\x8e\x4f\xb2\x19\xa4\x49\x94\x42\x25\xf5\xb2\x04\x85\x36\x72\x99\x44\xca\x96\x11\x2f\x98\x41\x1b\xb1\xb4\x14\xd6\x0a\xad\xe8\x0d\x24\x85\xd6\xf3\x08\xa1\xac\xa4\xeb\xd2\x6d\x1d\xb5\xc0\x0d\x60\x88\x95\x0c\x5e\x44\xeb\x75\x10\x38\x84\x44\x46\xe0\xaf\x87\xa1\x69\x7c\xdf\xb3\x12\xc8\x64\x42\xa8\x07\xc8\xc1\xab\xcb\x52\x2b\x2f\x8e\x5f\x92\x67\x42\x71\x59\xa7\x40\x26\xf3\xba\x64\xe3\x60\x6d\x03\x9c\xe9\x84\x84\xcf\x37\x21\x98\xf4\x61\xad\x0b\x20\x85\x45\xf2\xac\x32\x42\x61\x46\x26\x4f\x6d\xf8\xd4\x4e\x46\x87\x84\x1f\x40\x02\xb3\x10\x7a\x97\x8a\x71\x78\xbe\x65\x1f\xda\x05\x7f\xd8\x67\x53\x00\x18\xbc\xba\x3a\x77\x87\x1f\x9d\xcc\x0e\x06\x0a\xe6\x64\x39\xa8\xd7\xaf\x9a\x72\x28\x67\x93\x8d\x3d\xed\xfa\xf7\xc4\x99\x80\xc1\xd6\xfa\x52\xe4\x0a\x52\x2f\x18\xe6\xa0\x84\x1c\x54\xda\x47\x71\xa7\x8c\x52\x71\x51\xba\x88\xa1\x8f\xd2\xab\xe7\xb0\x1c\x69\x7f\x85\x65\xab\x1c\x4c\xd9\x4b\xf7\x77\xe3\xf8\x89\x24\x27\xc7\xa0\xb8\x1b\x26\x4a\x69\xc0\x2a\x71\x0d\xc6\x11\x22\x26\x8b\x69\x30\x17\x2a\x8d\xc9\xa5\x87\x35\xc0\x65\x05\x31\x99\xd7\x09\x18\x05\x08\xd6\x8d\x10\x4a\x1b\x94\x80\x2c\x65\xc8\xe2\x80\x10\xc5\x4a\x88\xc9\x6a\x45\xc6\x20\xab\x06\x50\xb2\x5e\x53\x94\xd6\x0f\x4d\x6b\xec\x5b\xed\x3d\x6e\x23\xe0\x92\x22\x44\xb2\x04\xa4\x75\xc1\x3d\x13\x47\x71\x1b\x9d\x8b\xfc\x89\x28\xa1\x52\x50\x48\x8e\x9d\x5b\x97\x8f\x63\x27\x37\xe8\x0f\x68\x7a\x37\xac\xb8\xd1\xcf\x61\xd9\xe8\x5d\xf3\xb6\xf4\x9c\x0d\xdc\x47\x8b\x87\x12\x50\xe9\xae\xb6\xf5\x23\x65\x20\x17\x16\x0d\x43\xa1\x55\x38\x3f\xf5\xfd\x5a\x4c\x13\x40\xd6\x35\xf6\xb7\x1a\x19\x0a\x95\xff\xd1\xcc\xde\x6b\xad\x32\x91\xd7\x8d\xc7\x67\xb6\x75\x33\xc8\x65\x1b\xb4\x9f\x68\x3e\x0a\xfb\x25\x6d\xdf\xb7\xeb\xed\x89\xde\x8b\xb6\x49\xbb\x65\x16\xa6\x90\xb1\x5a\x22\x98\xd0\x0f\x49\x9f\xac\xff\x37\x14\x3a\x20\x84\x90\x8c\x09\x59\x1b\xb8\xd0\x52\xf0\x65\x4c\xde\x32\x21\xbd\x9c\x4b\x01\x0a\x9b\xe6\xc4\x5e\xe2\x70\x69\xb0\xb8\x8d\x4c\xa3\x6f\x17\x49\x67\xbe\x6f\xd1\x1b\xdb\x1d\xdd\xbe\x67\x53\x0d\xbd\x2b\x86\x45\x4c\xa2\xb6\x64\xea\x0b\x16\x9a\x2e\xa6\x4c\x56\x05\x9b\x52\xd7\x10\x6f\x6c\x6a\x09\xb6\xcb\x90\x12\x56\x89\x77\xee\x86\xb1\x9b\xa4\x9d\x78\xd8\x21\xf7\xdb\x50\x6d\xcb\xb0\x3b\xa0\x17\xea\x0a\x1a\xcc\xb7\x0c\x5f\x7f\x38\x7b\x75\x75\x36\x12\xfd\x7e\xf1\x66\x28\x32\x60\x75\x6d\x38\x6c\x39\xba\xcc\xc1\x7a\x91\x15\x29\x9c\x65\x19\x70\xb4\x31\x79\xaf\x15\x0c\x10\xd7\x37\x0a\x0c\x35\x90\x81\x01\xc5\xe1\xc7\x81\x7c\xab\xf0\x5b\xd0\x3f\x26\xd4\xef\x80\x98\x0b\xc3\x6b\x81\x89\x01\x36\x07\x63\x47\x3a\xf8\x88\x60\x14\x93\x6d\x1f\xc6\x4a\x4f\x76\xa1\xfe\x04\xee\xcf\x1e\xe9\x0a\x60\x12\x0b\x5e\x00\x9f\x8f\x15\x95\xd1\x1f\x97\xfd\x63\x64\xa4\x42\xc3\xb2\x4c\x70\xa9\xf3\x9d\xf2\xca\xbd\xe6\x3c\x9f\x76\xaa\x8d\xae\xef\x08\x88\x86\xf1\x3d\x38\xdc\x40\xe7\xcb\xd1\xe6\x3e\xca\x3a\x66\xed\x7a\x16\x75\xbe\x6f\x87\xe6\x1d\x67\xfe\x9f\xf4\x6e\x4a\xa2\xae\x6d\x9c\x99\xcf\x20\xf3\x64\xb2\x0f\x8f\xbf\x11\x83\x2b\x9d\xde\x05\xef\x57\xdc\xd4\xd7\x4c\x8a\xf4\x5b\xdd\xd5\x8b\x3e\xd8\x23\xb9\xa3\xdb\x84\xf4\x0f\x74\x3d\xb7\x25\x3f\xee\x25\xbd\xe3\x6a\x76\xa2\x37\x67\xe7\x67\x5f\xb7\xca\x1d\x57\x2b\xd7\xa8\x7f\x7b\xc3\x0f\x9e\x0c\x8f\x63\xe9\x77\x9a\xbf\xb5\xda\xe3\x1a\x68\x1b\x11\x7e\xc9\x80\xfc\x92\x2b\x6d\xe0\x7b\x18\x91\xc5\x94\xb6\xc6\xff\xf9\xd2\xdf\xff\xb1\x3a\xe2\xf0\xfd\x18\xfb\x0f\x1e\x7b\x41\xdc\x63\x70\x09\xd2\x5f\xef\xdd\x99\x25\x43\x5e\x9c\xf7\xeb\xb8\xf9\xb5\x9e\x91\x5d\x5a\x84\x92\x0e\x00\x9c\xa0\xa9\x61\xf2\x1d\xb0\xe6\x41\xda\xf8\x2f\x07\x8f\x90\x35\xfb\xef\xd1\xa6\x86\xbb\x78\xf4\x4f\x00\x00\x00\xff\xff\xb1\x8a\x50\x1d\xc0\x14\x00\x00"),
@@ -264,7 +264,7 @@ var HelmTemplates = func() http.FileSystem {
 		},
 		"/values.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "values.yaml",
-			modTime:          time.Date(2020, 11, 2, 8, 36, 18, 433473494, time.UTC),
+			modTime:          time.Date(2020, 11, 2, 9, 41, 54, 746421125, time.UTC),
 			uncompressedSize: 1802,
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xac\x54\xc1\x6e\x23\x45\x10\xbd\xcf\x57\x94\xec\x73\x6c\x67\x21\x11\x9a\xdb\xae\x57\xa0\x88\x6c\x14\xe1\x68\x39\x97\x7b\xca\x33\x85\x7b\xaa\x87\xea\x6a\x83\x41\xfc\x3b\xea\x6e\xc7\x49\x20\x64\x41\xe2\x66\xbf\xae\x7e\xf3\xba\xea\xd5\x9b\xc3\xc3\x40\xd0\xd1\x0e\x93\x37\x50\xea\x39\x9a\x1e\x01\xa5\x03\xc3\x1e\x2c\x40\x8a\x04\xbb\xa0\x80\xde\xc3\xf7\x69\x44\xe0\x11\x7b\x8a\x4d\xef\xc3\x16\x7d\xdb\x00\x08\x8e\x14\x27\x74\xd4\xc2\x6c\x9f\x46\xbc\x88\xc7\x68\x34\xce\x1a\xa8\xb5\xb9\x06\xce\xdc\xb9\x28\x48\x7f\xd1\x05\xb7\x27\xbd\x28\x17\xea\xef\xc5\x96\xc5\x14\x8f\x0b\x0e\xb3\x72\x65\x0e\x1f\xab\xb0\x98\x85\x2c\xd6\x03\xaa\x2d\xde\x4f\xd3\x67\xd2\xc8\x41\x4e\x35\x86\x7d\x0b\xb3\x59\xd3\xcc\xe1\xc7\x81\x6c\x20\x85\xa0\x20\xc1\xf2\xa5\x09\xcd\x0d\x60\x03\x81\xa1\xf6\x64\x4f\x62\xe1\x17\xb6\x7a\x52\xe5\x82\xc7\x2d\xf9\xa6\x5c\xd8\x14\xe4\xee\xe9\x5d\xa6\x89\x9a\xc6\x05\x31\x0d\xfe\xde\xa3\x94\x47\xf9\xd0\xdf\xd2\x81\x7c\x0b\x33\x96\x5d\x11\x3d\x86\x2e\xb7\x21\x1a\x4a\x87\x3e\x08\x65\x70\x0e\xbf\x05\xa1\x2a\x12\x60\xdf\xc5\xef\x4a\xef\xde\x77\x9d\x52\x8c\x8f\xb8\x84\x8e\x36\xe4\xc9\x59\xd0\xda\xb2\x7d\xda\x92\x0a\x19\xc5\x05\x87\x65\x88\x2d\x78\x96\xf4\xeb\x2b\x67\xa8\x6e\x68\x01\xc7\xee\xfa\xeb\x4c\xc5\xf2\x53\xa1\xf9\x16\xd9\x27\xa5\xfb\xe0\xd9\x1d\x5b\xb8\xe9\x25\x28\xe5\x82\x48\x7a\x60\x77\x9a\xcc\xbc\x34\xa5\xc8\xc8\x7f\xed\x38\x51\x0b\x6b\x9f\xa2\x91\xde\xdc\x17\x0c\x45\x82\xa1\x71\x90\xd8\xc2\xef\x7f\x64\x8a\x3a\xff\x1f\x68\x0c\x46\x9b\xa3\xb8\xcd\x17\x29\x6f\x03\x76\x1f\xd0\xa3\x38\xd2\x57\x59\x33\x36\x05\xb5\x16\xae\xae\xbf\xb9\xca\x1f\x39\x19\x33\x56\xd6\xb8\xe7\xe9\x13\xc5\x61\xad\x54\x6e\xb5\xb0\x43\x1f\xcb\x83\xe6\xd9\x60\x31\x24\x75\x54\x8a\xe7\x50\x3d\xf7\x73\xa2\x68\xcf\x10\x00\x37\xa5\x16\x2e\x57\xab\xf1\x19\x36\xd2\x18\xb2\x33\xdf\x5d\x5d\x7f\xe2\x4a\xf7\x70\xbb\x29\xb6\x3f\xa0\x72\x48\xb1\x74\x8c\x34\x36\x00\xe6\x4f\x72\x7a\x12\xd2\xba\x02\x45\x1d\x39\x25\xbb\x7b\xfe\x6e\x00\x87\x1f\x92\x74\xfe\x09\xc2\x89\x37\x85\xea\xed\x6b\x9e\x49\x6c\x4d\x6a\x71\xf3\xf7\xf3\xb3\x83\xbe\xc8\xb4\xef\x62\x9d\xd0\xba\x10\xfe\x43\xe5\xcb\x45\x9d\x92\xf7\x67\xc7\xec\xee\x82\xdd\x2b\x45\x12\x3b\x6d\xf1\x14\x22\x5b\xa8\x7b\x9c\x77\xd7\x4d\xd5\xe2\x95\xf3\x6c\x0f\x92\xc3\x67\xd4\xfa\xd7\x09\xb7\x05\xc2\xad\xa7\xee\x71\x6a\x00\x6e\x40\x96\xe7\x80\x90\x7d\x64\x6d\x61\x49\xe6\x96\x4e\x78\x39\x26\x6f\x29\x2e\x85\x6c\xd1\x35\x00\x5b\x96\x7a\x7e\x40\x5d\x7a\xde\x96\x9a\x2d\xe7\x24\x70\x41\x76\xf5\x41\x55\x95\xf0\x22\x43\x2f\xb6\x34\x2f\xe9\xff\xbd\x69\xaf\x06\xdc\x29\xcf\x1e\x73\xec\x45\xd3\x7c\xd8\xee\xc3\x81\xfd\x11\x97\x2c\xd1\xd0\xfb\x2c\xf6\xb4\x27\x25\xca\x56\x8b\xd5\xe2\x5d\xc9\xb3\x75\x90\x1d\xf7\x49\x8b\xdb\x8b\x1d\x73\x5e\xe5\x07\x42\x87\x86\x53\x0e\x22\x88\xdc\x91\x43\x6d\x32\x72\x8e\xa6\x17\xba\xfe\x3a\xb2\x6e\x9a\xbd\x3d\xe9\x32\xd0\x37\x3e\xce\xc2\x06\xd3\x80\x91\x80\xa5\x66\xe8\x49\x04\x94\xb3\x9b\xb7\xbe\x9e\x0b\x66\x4d\xc3\xd2\x97\xf4\x7b\xcd\x18\x23\xc5\xa1\x7d\x5c\xfe\x1c\x03\x8a\x2c\x0f\x9c\xa7\xfb\xd5\x2a\xfe\xab\xfc\xfa\x0f\x61\x73\xb9\x5a\xad\x2e\x9b\x3f\x03\x00\x00\xff\xff\xab\xb7\x94\xbd\x0a\x07\x00\x00"),
diff --git a/app/kumactl/pkg/resources/dataplane_overview_client.go b/app/kumactl/pkg/resources/dataplane_overview_client.go
index 87ecc516e..b46b233c3 100644
--- a/app/kumactl/pkg/resources/dataplane_overview_client.go
+++ b/app/kumactl/pkg/resources/dataplane_overview_client.go
@@ -18,7 +18,7 @@ import (
 )
 
 type DataplaneOverviewClient interface {
-	List(ctx context.Context, meshName string, tags map[string]string, gateway bool) (*mesh.DataplaneOverviewResourceList, error)
+	List(ctx context.Context, meshName string, tags map[string]string, gateway bool, ingress bool) (*mesh.DataplaneOverviewResourceList, error)
 }
 
 func NewDataplaneOverviewClient(coordinates *config_proto.ControlPlaneCoordinates_ApiServer) (DataplaneOverviewClient, error) {
@@ -35,8 +35,8 @@ type httpDataplaneOverviewClient struct {
 	Client kuma_http.Client
 }
 
-func (d *httpDataplaneOverviewClient) List(ctx context.Context, meshName string, tags map[string]string, gateway bool) (*mesh.DataplaneOverviewResourceList, error) {
-	resUrl, err := constructUrl(meshName, tags, gateway)
+func (d *httpDataplaneOverviewClient) List(ctx context.Context, meshName string, tags map[string]string, gateway bool, ingress bool) (*mesh.DataplaneOverviewResourceList, error) {
+	resUrl, err := constructUrl(meshName, tags, gateway, ingress)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not construct the url")
 	}
@@ -58,7 +58,7 @@ func (d *httpDataplaneOverviewClient) List(ctx context.Context, meshName string,
 	return &overviews, nil
 }
 
-func constructUrl(meshName string, tags map[string]string, gateway bool) (*url.URL, error) {
+func constructUrl(meshName string, tags map[string]string, gateway bool, ingress bool) (*url.URL, error) {
 	result, err := url.Parse(fmt.Sprintf("/meshes/%s/dataplanes+insights", meshName))
 	if err != nil {
 		return nil, err
@@ -67,6 +67,9 @@ func constructUrl(meshName string, tags map[string]string, gateway bool) (*url.U
 	if gateway {
 		query.Add("gateway", fmt.Sprintf("%t", gateway))
 	}
+	if ingress {
+		query.Add("ingress", fmt.Sprintf("%t", ingress))
+	}
 	for tag, value := range tags {
 		query.Add("tag", fmt.Sprintf("%s:%s", tag, value))
 	}
diff --git a/deployments/charts/kuma/templates/cp-rbac.yaml b/deployments/charts/kuma/templates/cp-rbac.yaml
index cb56c569e..99b8ba550 100644
--- a/deployments/charts/kuma/templates/cp-rbac.yaml
+++ b/deployments/charts/kuma/templates/cp-rbac.yaml
@@ -20,6 +20,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/docs/cmd/kumactl/HELP.md b/docs/cmd/kumactl/HELP.md
index ed87f0e5d..cd19634f9 100644
--- a/docs/cmd/kumactl/HELP.md
+++ b/docs/cmd/kumactl/HELP.md
@@ -694,6 +694,7 @@ Usage:
 Flags:
       --gateway              filter gateway dataplanes
   -h, --help                 help for dataplanes
+      --ingress              filter ingress dataplanes
       --tag stringToString   filter by tag in format of key=value. You can provide many tags (default [])
 
 Global Flags:
diff --git a/examples/kafka/manifest.yaml b/examples/kafka/manifest.yaml
new file mode 100644
index 000000000..a9c48a2c2
--- /dev/null
+++ b/examples/kafka/manifest.yaml
@@ -0,0 +1,136 @@
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: kuma-kafka
+  annotations:
+    kuma.io/sidecar-injection: "enabled"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: zoo1
+  namespace: kuma-kafka
+  labels:
+    app: zookeeper-1
+spec:
+  ports:
+    - name: client
+      port: 2181
+      protocol: TCP
+    - name: follower
+      port: 2888
+      protocol: TCP
+    - name: leader
+      port: 3888
+      protocol: TCP
+  selector:
+    app: zookeeper-1
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: kafka-service
+  namespace: kuma-kafka
+  annotations:
+    9092.service.kuma.io/protocol: kafka
+  labels:
+    name: kafka
+spec:
+  ports:
+    - port: 9092
+      name: kafka-port
+      protocol: TCP
+  selector:
+    app: kafka
+    id: "0"
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: zookeeper-deployment-1
+  namespace: kuma-kafka
+spec:
+  selector:
+    matchLabels:
+      app: zookeeper-1
+  template:
+    metadata:
+      labels:
+        app: zookeeper-1
+    spec:
+      containers:
+        - name: zoo1
+          image: zookeeper
+          ports:
+            - containerPort: 2181
+          env:
+            - name: ZOOKEEPER_ID
+              value: "1"
+            - name: ZOOKEEPER_SERVER_1
+              value: zoo1
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: kafka-broker0
+  namespace: kuma-kafka
+spec:
+  selector:
+    matchLabels:
+      app: kafka
+  template:
+    metadata:
+      labels:
+        app: kafka
+        id: "0"
+    spec:
+      containers:
+        - name: kafka
+          image: wurstmeister/kafka:2.12-2.4.1
+          ports:
+            - containerPort: 9092
+          env:
+            - name: KAFKA_ADVERTISED_PORT
+              value: "9092"
+            - name: KAFKA_ADVERTISED_HOST_NAME
+              value: kafka-service
+            - name: KAFKA_ZOOKEEPER_CONNECT
+              value: zoo1:2181
+            - name: KAFKA_BROKER_ID
+              value: "0"
+            - name: KAFKA_CREATE_TOPICS
+              value: sample.topic:1:1
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: kafka-cat
+  namespace: kuma-kafka
+  labels:
+    name: kafka
+spec:
+  ports:
+    - port: 1234
+  selector:
+    app: kafka-cat
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: kafka-cat
+  namespace: kuma-kafka
+spec:
+  selector:
+    matchLabels:
+      app: kafka-cat
+  template:
+    metadata:
+      labels:
+        app: kafka-cat
+    spec:
+      containers:
+        - name: kafka-cat
+          image: confluentinc/cp-kafkacat
+          command: ["/bin/sh"]
+          args: ["-c", "trap : TERM INT; sleep infinity & wait"]
diff --git a/go.sum b/go.sum
index 90cb17192..e3426900d 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,7 @@ github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
 github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v38.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
 github.com/Azure/go-autorest v13.3.2+incompatible h1:VxzPyuhtnlBOzc4IWCZHqpyH2d+QMLQEuy3wREyY4oc=
 github.com/Azure/go-autorest v13.3.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
@@ -62,6 +63,7 @@ github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhH
 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
 github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190405210948-c70a36b8193f/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
 github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
@@ -69,10 +71,13 @@ github.com/InVisionApp/go-health v2.1.0+incompatible/go.mod h1:/+Gv1o8JUsrjC6pi6
 github.com/InVisionApp/go-logger v1.0.1/go.mod h1:+cGTDSn+P8105aZkeOfIhdd7vFO5X1afUHcjvanY0L8=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
+github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
 github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
 github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
 github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk=
 github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig v2.20.0+incompatible h1:dJTKKuUkYW3RMFdQFXPU/s6hg10RgctmTjRcbZ98Ap8=
 github.com/Masterminds/sprig v2.20.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
 github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y=
 github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
@@ -104,6 +109,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
 github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -111,6 +117,7 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-metrics v0.3.2 h1:EyUnxyP2yaGpLgMiuyyz8sHnByqeTJUfGs72pdH0i4A=
 github.com/armon/go-metrics v0.3.2/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
@@ -130,6 +137,7 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw
 github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
@@ -149,9 +157,12 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+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/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -163,6 +174,7 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533 h1:8wZizuKuZVu5COB7EsBYxBQz8nRcXXn5d4Gt91eJLvU=
 github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
@@ -204,6 +216,7 @@ github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2
 github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
 github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
 github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
@@ -211,8 +224,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zA
 github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
 github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dhui/dktest v0.3.1 h1:NVUdB50k8tml431Ho1hcQBNeC52Qe8oSDPAjseA67Y8=
 github.com/dhui/dktest v0.3.1/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
 github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
@@ -221,6 +236,7 @@ github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop
 github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
 github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
@@ -230,9 +246,11 @@ github.com/docker/docker v1.4.2-0.20191008235115-448db5a783a0/go.mod h1:eEKB0N0r
 github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce h1:KXS1Jg+ddGcWA8e1N7cupxaHHZhit5rB9tfDU+mfjyY=
 github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
@@ -260,8 +278,10 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.5 h1:lRJIqDD8yjV1YyPRqecMdytjDLs2fTXq363aCib5xPU=
 github.com/envoyproxy/go-control-plane v0.9.5/go.mod h1:OXl5to++W0ctG+EHWTFUjiypVxC/Y4VLc/KFU+al13s=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9 h1:mU3oOAYTK9ZRKMj//H1EWk1vWbkYeWKBPYKMnIwcs/A=
 github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
 github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc=
@@ -275,10 +295,12 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 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/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
 github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
@@ -297,7 +319,9 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
 github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
 github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
@@ -350,6 +374,7 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
 github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
@@ -368,7 +393,9 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
 github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang-migrate/migrate/v4 v4.8.0 h1:zcamXqBH0W8hHwpaikOGnaFTRrQWU+X8ukBeY1dYucU=
 github.com/golang-migrate/migrate/v4 v4.8.0/go.mod h1:F6bGIGAA7xSb2k17sF1+eHl2gRHa+DWNZpoIKbThPLE=
 github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -376,10 +403,12 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -392,12 +421,14 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
 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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -405,12 +436,14 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
 github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
 github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
 github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
 github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
@@ -429,6 +462,7 @@ github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -443,15 +477,20 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMW
 github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
+github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
+github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
 github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
 github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
@@ -465,14 +504,18 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 h1:LaH4JWe6Q7ICdxL5raxQjSRw7Pj8uTtAENrjejIYZIg=
 github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69 h1:umaj0TCQ9lWUUKy2DxAhEzPbwd0jnxiw1EI2z3FiILM=
 github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69/go.mod h1:zdLK9ilQRSMjSeLKoZ4BqUfBT7jswTGF8zRlKEsiRXA=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
@@ -485,6 +528,7 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
 github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
 github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imkira/go-observer v1.0.3/go.mod h1:zLzElv2cGTHufQG17IEILJMPDg32TD85fFgKyFv00wU=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
@@ -515,6 +559,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
 github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -524,9 +569,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
 github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
@@ -568,6 +615,7 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -591,15 +639,19 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQ
 github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
 github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
@@ -613,6 +665,7 @@ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@@ -642,6 +695,7 @@ github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQ
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@@ -658,7 +712,9 @@ github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
 github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
 github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
 github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -675,6 +731,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
 github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
@@ -696,6 +753,7 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
@@ -745,6 +803,7 @@ github.com/sethvargo/go-retry v0.1.0/go.mod h1:JzIOdZqQDNpPkQDmcqgtteAcxFLtYpNF/
 github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
 github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -770,24 +829,30 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spiffe/go-spiffe v0.0.0-20190717182101-d8657cb50cae/go.mod h1:HyNeJnVYkDyQgB2qcSPxVYkAA2F3lQu51bDxNpFcKxY=
+github.com/spiffe/go-spiffe v0.0.0-20190820222348-6adcf1eecbcc h1:YeGvOZLHZxE8nrxPGDNH1LGv8zzkAIDfIRgy256rotk=
 github.com/spiffe/go-spiffe v0.0.0-20190820222348-6adcf1eecbcc/go.mod h1:HyNeJnVYkDyQgB2qcSPxVYkAA2F3lQu51bDxNpFcKxY=
+github.com/spiffe/spire v0.10.0 h1:UuBHgHI/4Uqcn0SpVMXWPgWtgKLJkBXOWP9Vs/82sZ4=
 github.com/spiffe/spire v0.10.0/go.mod h1:6dqxKqiDPREetq8Z62bcb+zFybVr/cj2ncTt0iLwREw=
+github.com/spiffe/spire/proto/spire v0.10.0 h1:NJ6HK9/XlnvqTox3fJUTAt6180105ZknpDS6sJC+QUM=
 github.com/spiffe/spire/proto/spire v0.10.0/go.mod h1:QmfLOnjxfc4o9KAe1f8bwYX3WcMLWSiKljTEHdGNFYU=
 github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -802,6 +867,7 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/uber-go/tally v3.3.12+incompatible h1:Qa0XrHsKXclmhEpHmBHTTEZotwvQHAbm3lvtJ6RNn+0=
 github.com/uber-go/tally v3.3.12+incompatible/go.mod h1:YDTIBxdXyOU/sCWilKB4bgyufu1cEi0jdVnRdxvjnmU=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@@ -835,6 +901,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+github.com/zeebo/errs v1.2.0 h1:Tk8UszIOLEjtx6DWnvfmMJe6N8q7vu03Bj95HMWDUkc=
 github.com/zeebo/errs v1.2.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
 github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
 gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
@@ -955,6 +1022,7 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
 golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 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=
@@ -1076,6 +1144,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
 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=
+gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
 gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
 gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
@@ -1110,6 +1179,7 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA=
 google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1136,6 +1206,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -1144,11 +1215,13 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
 gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
 gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
 gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+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/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
 gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -1163,6 +1236,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 helm.sh/helm/v3 v3.3.4 h1:tbad6WQVMxEw1HlVBvI2rQqOblmI5lgXOrWAMwJ198M=
 helm.sh/helm/v3 v3.3.4/go.mod h1:CyCGQa53/k1JFxXvXveGwtfJ4cuB9zkaBSGa5rnAiHU=
@@ -1209,10 +1283,12 @@ k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
 k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
 k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
 k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
+k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY=
 k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
 k8s.io/kubectl v0.18.8/go.mod h1:PlEgIAjOMua4hDFTEkVf+W5M0asHUKfE4y7VDZkpLHM=
 k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
@@ -1243,11 +1319,15 @@ sigs.k8s.io/controller-runtime v0.6.1 h1:LcK2+nk0kmaOnKGN+vBcWHqY5WDJNJNB/c5pW+s
 sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A=
 sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
 sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
+sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
 sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
+sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
+sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs=
 sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
 vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
diff --git a/pkg/api-server/dataplane_overview_endpoints.go b/pkg/api-server/dataplane_overview_endpoints.go
index b79ba2165..256d7ec62 100644
--- a/pkg/api-server/dataplane_overview_endpoints.go
+++ b/pkg/api-server/dataplane_overview_endpoints.go
@@ -4,6 +4,8 @@ import (
 	"context"
 	"strings"
 
+	"github.com/kumahq/kuma/pkg/core/validators"
+
 	"github.com/emicklei/go-restful"
 	"github.com/golang/protobuf/proto"
 
@@ -98,14 +100,23 @@ func (r *dataplaneOverviewEndpoints) inspectDataplanes(request *restful.Request,
 		return
 	}
 
-	tags := parseTags(request.QueryParameters("tag"))
-	if request.QueryParameter("gateway") == "true" {
-		overviews.RetainGatewayDataplanes()
+	mode, err := modeFromParameter(request, "gateway")
+	if err != nil {
+		rest_errors.HandleError(response, err, "Could not retrieve dataplane overviews")
+		return
 	}
-	if request.QueryParameter("ingress") == "true" {
-		overviews.RetainIngressDataplanes()
+	overviews.RetainGatewayDataplanes(mode)
+
+	mode, err = modeFromParameter(request, "ingress")
+	if err != nil {
+		rest_errors.HandleError(response, err, "Could not retrieve dataplane overviews")
+		return
 	}
+	overviews.RetainIngressDataplanes(mode)
+
+	tags := parseTags(request.QueryParameters("tag"))
 	overviews.RetainMatchingTags(tags)
+
 	// pagination is not supported yet so we need to override pagination total items after retaining dataplanes
 	overviews.GetPagination().SetTotal(uint32(len(overviews.Items)))
 	restList := rest.From.ResourceList(&overviews)
@@ -148,3 +159,17 @@ func parseTags(queryParamValues []string) map[string]string {
 	}
 	return tags
 }
+
+func modeFromParameter(request *restful.Request, param string) (string, error) {
+	mode := strings.ToLower(request.QueryParameter(param))
+	if mode == "" || mode == "true" || mode == "false" {
+		return mode, nil
+	}
+
+	verr := validators.ValidationError{}
+	verr.AddViolationAt(
+		validators.RootedAt(request.SelectedRoutePath()).Field(param),
+		"shoud use `true` or `false` instead of "+mode)
+
+	return "", &verr
+}
diff --git a/pkg/api-server/zones_ws.go b/pkg/api-server/zones_ws.go
index a666c35f3..49f36f8ac 100644
--- a/pkg/api-server/zones_ws.go
+++ b/pkg/api-server/zones_ws.go
@@ -13,9 +13,8 @@ import (
 )
 
 type Zone struct {
-	Name    string `json:"name"`
-	Address string `json:"url"`
-	Active  bool   `json:"active"`
+	Name   string `json:"name"`
+	Active bool   `json:"active"`
 }
 
 type Zones []Zone
@@ -54,9 +53,8 @@ func toZones(rlist system.ZoneOverviewResourceList) Zones {
 	var zones Zones
 	for _, overview := range rlist.Items {
 		zones = append(zones, Zone{
-			Name:    overview.GetMeta().GetName(),
-			Address: overview.Spec.Zone.Ingress.Address,
-			Active:  overview.Spec.ZoneInsight.IsOnline(),
+			Name:   overview.GetMeta().GetName(),
+			Active: overview.Spec.ZoneInsight.IsOnline(),
 		})
 	}
 	return zones
diff --git a/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml b/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml
index b4d561f91..ab0f02edd 100644
--- a/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml
+++ b/pkg/config/app/kuma-cp/kuma-cp.defaults.yaml
@@ -94,7 +94,7 @@ apiServer:
     # Network interface on which HTTP API Server will be exposed
     interface: 0.0.0.0 # ENV: KUMA_API_SERVER_HTTP_INTERFACE
     # Port of the API Server
-    port: 5681 # ENV: KUMA_API_SERVER_PORT
+    port: 5681 # ENV: KUMA_API_SERVER_HTTP_PORT
   # HTTPS configuration of the API Server
   https:
     # If true then API Server will be served on HTTPS
diff --git a/pkg/core/resources/apis/mesh/dataplane_helpers.go b/pkg/core/resources/apis/mesh/dataplane_helpers.go
index 64544142f..d4ad39fbd 100644
--- a/pkg/core/resources/apis/mesh/dataplane_helpers.go
+++ b/pkg/core/resources/apis/mesh/dataplane_helpers.go
@@ -19,6 +19,7 @@ const (
 	ProtocolHTTP    = "http"
 	ProtocolHTTP2   = "http2"
 	ProtocolGRPC    = "grpc"
+	ProtocolKafka   = "kafka"
 )
 
 func ParseProtocol(tag string) Protocol {
@@ -31,6 +32,8 @@ func ParseProtocol(tag string) Protocol {
 		return ProtocolTCP
 	case ProtocolGRPC:
 		return ProtocolGRPC
+	case ProtocolKafka:
+		return ProtocolKafka
 	default:
 		return ProtocolUnknown
 	}
@@ -52,6 +55,7 @@ var SupportedProtocols = ProtocolList{
 	ProtocolGRPC,
 	ProtocolHTTP,
 	ProtocolHTTP2,
+	ProtocolKafka,
 	ProtocolTCP,
 }
 
diff --git a/pkg/core/resources/apis/mesh/dataplane_overview.go b/pkg/core/resources/apis/mesh/dataplane_overview.go
index d73969c73..d75fab8a3 100644
--- a/pkg/core/resources/apis/mesh/dataplane_overview.go
+++ b/pkg/core/resources/apis/mesh/dataplane_overview.go
@@ -2,6 +2,7 @@ package mesh
 
 import (
 	"errors"
+	"reflect"
 
 	"github.com/golang/protobuf/proto"
 
@@ -20,6 +21,8 @@ type DataplaneOverviewResource struct {
 	Spec mesh_proto.DataplaneOverview
 }
 
+type DpFilter func(a interface{}) bool
+
 func (t *DataplaneOverviewResource) GetType() model.ResourceType {
 	return DataplaneOverviewType
 }
@@ -125,11 +128,33 @@ func (d *DataplaneOverviewResourceList) RetainMatchingTags(tags map[string]strin
 	d.Items = result
 }
 
+func modeToFilter(mode string) DpFilter {
+	isnil := func(a interface{}) bool {
+		return a == nil || reflect.ValueOf(a).IsNil()
+	}
+	switch mode {
+	case "true":
+		return func(a interface{}) bool {
+			return !isnil(a)
+		}
+	case "false":
+		return func(a interface{}) bool {
+			return isnil(a)
+		}
+	default:
+		return func(a interface{}) bool {
+			return true
+		}
+	}
+}
+
 // RetainGatewayDataplanes to get only gateway Dataplanes
-func (l *DataplaneOverviewResourceList) RetainGatewayDataplanes() {
+func (l *DataplaneOverviewResourceList) RetainGatewayDataplanes(mode string) {
 	result := []*DataplaneOverviewResource{}
+	filter := modeToFilter(mode)
+
 	for _, overview := range l.Items {
-		if overview.Spec.GetDataplane().GetNetworking().GetGateway() != nil {
+		if filter(overview.Spec.GetDataplane().GetNetworking().GetGateway()) {
 			result = append(result, overview)
 		}
 	}
@@ -137,10 +162,12 @@ func (l *DataplaneOverviewResourceList) RetainGatewayDataplanes() {
 }
 
 // RetainIngressDataplanes to get only ingress Dataplanes
-func (l *DataplaneOverviewResourceList) RetainIngressDataplanes() {
+func (l *DataplaneOverviewResourceList) RetainIngressDataplanes(mode string) {
 	result := []*DataplaneOverviewResource{}
+	filter := modeToFilter(mode)
+
 	for _, overview := range l.Items {
-		if overview.Spec.GetDataplane().GetNetworking().GetIngress() != nil {
+		if filter(overview.Spec.GetDataplane().GetNetworking().GetIngress()) {
 			result = append(result, overview)
 		}
 	}
diff --git a/pkg/core/resources/apis/mesh/dataplane_validator.go b/pkg/core/resources/apis/mesh/dataplane_validator.go
index 299bf9337..3bc8d4204 100644
--- a/pkg/core/resources/apis/mesh/dataplane_validator.go
+++ b/pkg/core/resources/apis/mesh/dataplane_validator.go
@@ -14,6 +14,7 @@ func (d *DataplaneResource) Validate() error {
 	var err validators.ValidationError
 	if d.Spec.IsIngress() {
 		err.Add(validateIngressNetworking(d.Spec.GetNetworking()))
+		err.Add(validateIngress(validators.RootedAt("networking").Field("ingress"), d.Spec.GetNetworking().GetIngress()))
 	} else {
 		err.Add(validateNetworking(d.Spec.GetNetworking()))
 		err.Add(validateProbes(d.Spec.GetProbes()))
@@ -102,7 +103,7 @@ func validateIngressNetworking(networking *mesh_proto.Dataplane_Networking) vali
 	}
 	for i, inbound := range networking.GetInbound() {
 		p := path.Field("inbound").Index(i)
-		if inbound.Port < 1 || inbound.Port > 65535 {
+		if inbound.Port > 65535 {
 			err.AddViolationAt(p.Field("port"), `port has to be in range of [1, 65535]`)
 		}
 		if inbound.ServicePort != 0 {
@@ -121,8 +122,28 @@ func validateIngressNetworking(networking *mesh_proto.Dataplane_Networking) vali
 			}
 		}
 	}
-	for i, ingressInterface := range networking.GetIngress().GetAvailableServices() {
-		p := path.Field("ingress").Field("availableService").Index(i)
+	return err
+}
+
+func validateIngress(path validators.PathBuilder, ingress *mesh_proto.Dataplane_Networking_Ingress) validators.ValidationError {
+	if ingress == nil {
+		return validators.ValidationError{}
+	}
+	var err validators.ValidationError
+	if ingress.GetPublicAddress() == "" && ingress.GetPublicPort() != 0 {
+		err.AddViolationAt(path.Field("publicAddress"), `has to be defined with publicPort`)
+	}
+	if ingress.GetPublicPort() == 0 && ingress.GetPublicAddress() != "" {
+		err.AddViolationAt(path.Field("publicPort"), `has to be defined with publicAddress`)
+	}
+	if ingress.GetPublicAddress() != "" {
+		err.Add(validateAddress(path.Field("publicAddress"), ingress.GetPublicAddress()))
+	}
+	if ingress.GetPublicPort() > 65535 {
+		err.AddViolationAt(path.Field("publicPort"), `port has to be in range of [1, 65535]`)
+	}
+	for i, ingressInterface := range ingress.GetAvailableServices() {
+		p := path.Field("availableService").Index(i)
 		if _, ok := ingressInterface.Tags[mesh_proto.ServiceTag]; !ok {
 			err.AddViolationAt(p.Field("tags").Key(mesh_proto.ServiceTag), "cannot be empty")
 		}
diff --git a/pkg/core/resources/apis/system/zone_validator.go b/pkg/core/resources/apis/system/zone_validator.go
index ffb705791..c8b763af3 100644
--- a/pkg/core/resources/apis/system/zone_validator.go
+++ b/pkg/core/resources/apis/system/zone_validator.go
@@ -1,40 +1,5 @@
 package system
 
-import (
-	"net"
-	"net/url"
-
-	"github.com/kumahq/kuma/pkg/core/validators"
-)
-
 func (c *ZoneResource) Validate() error {
-	var err validators.ValidationError
-	err.Add(c.validateIngress())
-	return err.OrNil()
-}
-
-func (c *ZoneResource) validateIngress() validators.ValidationError {
-	var verr validators.ValidationError
-	if c.Spec.GetIngress().GetAddress() == "" {
-		verr.AddViolation("address", "cannot be empty")
-	} else {
-		host, port, err := net.SplitHostPort(c.Spec.GetIngress().GetAddress())
-		if err != nil {
-			url, urlErr := url.Parse(c.Spec.GetIngress().GetAddress())
-			if urlErr == nil && url.Scheme != "" {
-				verr.AddViolation("address", "should not be URL. Expected format is hostname:port")
-			} else {
-				verr.AddViolation("address", "invalid address: "+err.Error())
-			}
-		} else {
-			if host == "" {
-				verr.AddViolation("address", "host has to be explicitly specified")
-			}
-			if port == "" {
-				verr.AddViolation("address", "port has to be explicitly specified")
-			}
-		}
-	}
-
-	return verr
+	return nil
 }
diff --git a/pkg/kds/global/components.go b/pkg/kds/global/components.go
index 5b49a5987..5cbe78e6a 100644
--- a/pkg/kds/global/components.go
+++ b/pkg/kds/global/components.go
@@ -3,11 +3,10 @@ package global
 import (
 	"context"
 	"fmt"
-	"net"
-	"strconv"
 	"strings"
 
 	config_manager "github.com/kumahq/kuma/pkg/core/config/manager"
+	"github.com/kumahq/kuma/pkg/core/resources/manager"
 
 	"github.com/pkg/errors"
 
@@ -20,7 +19,6 @@ import (
 	"github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
 	"github.com/kumahq/kuma/pkg/core/resources/model"
-	"github.com/kumahq/kuma/pkg/core/resources/registry"
 	"github.com/kumahq/kuma/pkg/core/runtime"
 	"github.com/kumahq/kuma/pkg/kds/client"
 	sync_store "github.com/kumahq/kuma/pkg/kds/store"
@@ -67,10 +65,10 @@ func Setup(rt runtime.Runtime) (err error) {
 			}
 		}()
 		kdsStream := client.NewKDSStream(session.ClientStream(), session.PeerID())
-		zone := &system.ZoneResource{}
-		if err := rt.ReadOnlyResourceManager().Get(context.Background(), zone, store.GetByKey(session.PeerID(), "default")); err != nil {
-			// send error back to Remote CP, it will re-try later when ZoneResource will appear
-			return errors.Wrap(err, "ZoneResource doesn't exist")
+		zone, err := createZoneIfAbsent(session.PeerID(), rt.ResourceManager())
+		if err != nil {
+			log.Error(err, "Global CP could not create a zone")
+			return errors.New("Global CP could not create a zone") // send back message without details. Remote CP will retry
 		}
 		sink := client.NewKDSSink(log, consumedTypes, kdsStream, Callbacks(resourceSyncer, rt.Config().Store.Type == store_config.KubernetesStore, zone))
 		go func() {
@@ -83,6 +81,21 @@ func Setup(rt runtime.Runtime) (err error) {
 	return rt.Add(mux.NewServer(onSessionStarted, *rt.Config().Multicluster.Global.KDS, rt.Metrics()))
 }
 
+func createZoneIfAbsent(name string, resManager manager.ResourceManager) (*system.ZoneResource, error) {
+	zone := &system.ZoneResource{}
+	if err := resManager.Get(context.Background(), zone, store.GetByKey(name, model.DefaultMesh)); err != nil {
+		if !store.IsResourceNotFound(err) {
+			return nil, err
+		}
+		kdsGlobalLog.Info("creating zone", "name", name)
+		err := resManager.Create(context.Background(), zone, store.CreateByKey(name, model.DefaultMesh))
+		if err != nil {
+			return nil, err
+		}
+	}
+	return zone, nil
+}
+
 // ProvidedFilter filter Resources provided by Remote, specifically excludes Dataplanes and Ingresses from 'clusterID' cluster
 func ProvidedFilter(clusterID string, r model.Resource) bool {
 	if r.GetType() == system.ConfigType && r.GetMeta().GetName() != config_manager.ClusterIdConfigKey {
@@ -106,10 +119,6 @@ func Callbacks(s sync_store.ResourceSyncer, k8sStore bool, zone *system.ZoneReso
 			if k8sStore {
 				util.AddSuffixToNames(rs.GetItems(), "default")
 			}
-			if rs.GetItemType() == mesh.DataplaneType {
-				rs = dedupIngresses(rs)
-				adjustIngressNetworking(zone, rs)
-			}
 			return s.Sync(rs, sync_store.PrefilterBy(func(r model.Resource) bool {
 				return strings.HasPrefix(r.GetMeta().GetName(), fmt.Sprintf("%s.", clusterName))
 			}))
@@ -117,40 +126,6 @@ func Callbacks(s sync_store.ResourceSyncer, k8sStore bool, zone *system.ZoneReso
 	}
 }
 
-func adjustIngressNetworking(zone *system.ZoneResource, rs model.ResourceList) {
-	host, portStr, err := net.SplitHostPort(zone.Spec.GetIngress().GetAddress())
-	if err != nil {
-		kdsGlobalLog.Error(err, "failed parsing ingress", "host", host, "port", portStr)
-		return
-	}
-	port, _ := strconv.ParseUint(portStr, 10, 32)
-	for _, r := range rs.GetItems() {
-		if !r.(*mesh.DataplaneResource).Spec.IsIngress() {
-			continue
-		}
-		r.(*mesh.DataplaneResource).Spec.Networking.Address = host
-		r.(*mesh.DataplaneResource).Spec.Networking.Inbound[0].Port = uint32(port)
-	}
-}
-
-// dedupIngresses returns ResourceList that consist of Dataplanes from 'rs' and has single Ingress.
-// We assume to have single Ingress Resource per Zone.
-func dedupIngresses(rs model.ResourceList) model.ResourceList {
-	rv, _ := registry.Global().NewList(rs.GetItemType())
-	ingressPicked := false
-	for _, r := range rs.GetItems() {
-		if !r.(*mesh.DataplaneResource).Spec.IsIngress() {
-			_ = rv.AddItem(r)
-			continue
-		}
-		if !ingressPicked {
-			_ = rv.AddItem(r)
-			ingressPicked = true
-		}
-	}
-	return rv
-}
-
 func ConsumesType(typ model.ResourceType) bool {
 	for _, consumedTyp := range consumedTypes {
 		if consumedTyp == typ {
diff --git a/pkg/plugins/resources/k8s/native/go.sum b/pkg/plugins/resources/k8s/native/go.sum
index 2d657754f..0dc17db43 100644
--- a/pkg/plugins/resources/k8s/native/go.sum
+++ b/pkg/plugins/resources/k8s/native/go.sum
@@ -1,5 +1,6 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
 github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
@@ -25,12 +26,15 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+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-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533 h1:8wZizuKuZVu5COB7EsBYxBQz8nRcXXn5d4Gt91eJLvU=
 github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -45,6 +49,7 @@ github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfc
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
@@ -60,8 +65,10 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT
 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.5 h1:lRJIqDD8yjV1YyPRqecMdytjDLs2fTXq363aCib5xPU=
 github.com/envoyproxy/go-control-plane v0.9.5/go.mod h1:OXl5to++W0ctG+EHWTFUjiypVxC/Y4VLc/KFU+al13s=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9 h1:mU3oOAYTK9ZRKMj//H1EWk1vWbkYeWKBPYKMnIwcs/A=
 github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200311152155-ab56c3dd1cf9/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -69,14 +76,18 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 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 v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
 github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
 github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
@@ -124,9 +135,11 @@ github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85n
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -148,16 +161,20 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
 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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
 github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
 github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
 github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@@ -168,6 +185,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -188,9 +206,11 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -202,12 +222,15 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
@@ -235,14 +258,18 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -263,6 +290,7 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -270,6 +298,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -285,8 +314,11 @@ go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL
 go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -325,6 +357,7 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARV
 golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 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=
@@ -363,6 +396,7 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -378,16 +412,20 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw
 golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
 gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 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/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
 google.golang.org/appengine v1.5.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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA=
 google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
@@ -406,13 +444,16 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -443,9 +484,11 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
 k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
 k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
 k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY=
 k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
 k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
@@ -454,6 +497,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT
 sigs.k8s.io/controller-runtime v0.6.1 h1:LcK2+nk0kmaOnKGN+vBcWHqY5WDJNJNB/c5pW+sU8fc=
 sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
+sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/pkg/plugins/runtime/k8s/controllers/ingress_converter.go b/pkg/plugins/runtime/k8s/controllers/ingress_converter.go
new file mode 100644
index 000000000..adbf763c4
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/ingress_converter.go
@@ -0,0 +1,131 @@
+package controllers
+
+import (
+	"context"
+
+	"github.com/pkg/errors"
+	kube_core "k8s.io/api/core/v1"
+
+	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
+	"github.com/kumahq/kuma/pkg/plugins/runtime/k8s/metadata"
+)
+
+// List of priority for picking IP when Service that selects ingress is of type NodePort
+// We first try to find ExternalIP and then InternalIP.
+// ExternalIP will be available in public clouds like GCP, but not on Kind or Minikube.
+// On the other hand, on Kind with multicluster, there is a connectivity between clusters using InternalIP.
+// Technically there is a risk that we will pick InternalIP and other cluster will try to access it without connectivity between them.
+// However, in most cases, LoadBalancer will be used anyways, therefore we accept this risk.
+var NodePortAddressPriority = []kube_core.NodeAddressType{
+	kube_core.NodeExternalIP,
+	kube_core.NodeInternalIP,
+}
+
+func (p *PodConverter) IngressFor(pod *kube_core.Pod, services []*kube_core.Service) (*mesh_proto.Dataplane, error) {
+	if len(services) != 1 {
+		return nil, errors.Errorf("ingress should be matched by exactly one service. Matched %d services", len(services))
+	}
+	ifaces, err := InboundInterfacesFor(p.Zone, pod, services)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not generate inbound interfaces")
+	}
+	if len(ifaces) != 1 {
+		return nil, errors.Errorf("generated %d inbound interfaces, expected 1. Interfaces: %v", len(ifaces), ifaces)
+	}
+
+	ingress, err := p.ingressSpecFromAnnotations(metadata.Annotations(pod.Annotations))
+	if err != nil {
+		return nil, err
+	}
+
+	if ingress == nil { // if ingress public coordinates were not present in annotations we will try to pick it from service
+		ingress, err = p.ingressSpecFromService(services[0])
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &mesh_proto.Dataplane{
+		Networking: &mesh_proto.Dataplane_Networking{
+			Ingress: ingress,
+			Address: pod.Status.PodIP,
+			Inbound: ifaces,
+		},
+	}, nil
+}
+
+func (p *PodConverter) ingressSpecFromAnnotations(annotations metadata.Annotations) (*mesh_proto.Dataplane_Networking_Ingress, error) {
+	publicAddress, addressExist := annotations.GetString(metadata.KumaIngressPublicAddressAnnotation)
+	publicPort, portExist, err := annotations.GetUint32(metadata.KumaIngressPublicPortAnnotation)
+	if err != nil {
+		return nil, errors.Wrapf(err, "failed to parse annotation %s", metadata.KumaIngressPublicPortAnnotation)
+	}
+	if addressExist != portExist {
+		return nil, errors.Errorf("both %s and %s has to be defined", metadata.KumaIngressPublicAddressAnnotation, metadata.KumaIngressPublicPortAnnotation)
+	}
+	if addressExist && portExist {
+		return &mesh_proto.Dataplane_Networking_Ingress{
+			PublicAddress: publicAddress,
+			PublicPort:    publicPort,
+		}, nil
+	}
+	return nil, nil
+}
+
+// ingressSpecFromService is trying to generate ingress with public address and port using Service that selects the ingress
+func (p *PodConverter) ingressSpecFromService(service *kube_core.Service) (*mesh_proto.Dataplane_Networking_Ingress, error) {
+	switch service.Spec.Type {
+	case kube_core.ServiceTypeLoadBalancer:
+		return p.ingressSpecFromLoadBalancer(service)
+	case kube_core.ServiceTypeNodePort:
+		return p.ingressSpecFromNodePort(service)
+	default:
+		converterLog.Info("ingress service type is not public, therefore the public coordinates of the ingress will not be automatically set. Change the ingress service to LoadBalancer or NodePort or override the settings using annotations.")
+		return &mesh_proto.Dataplane_Networking_Ingress{}, nil
+	}
+}
+
+func (p *PodConverter) ingressSpecFromNodePort(service *kube_core.Service) (*mesh_proto.Dataplane_Networking_Ingress, error) {
+	nodes := &kube_core.NodeList{}
+	if err := p.NodeGetter.List(context.Background(), nodes); err != nil {
+		return nil, err
+	}
+	if len(nodes.Items) < 1 { // this should not happen, K8S always has at least one node
+		return nil, errors.New("there are no nodes")
+	}
+	for _, addressType := range NodePortAddressPriority {
+		for _, address := range nodes.Items[0].Status.Addresses {
+			if address.Type == addressType {
+				ingress := &mesh_proto.Dataplane_Networking_Ingress{
+					PublicAddress: address.Address,
+					PublicPort:    uint32(service.Spec.Ports[0].NodePort),
+				}
+				return ingress, nil
+			}
+		}
+	}
+	return nil, errors.New("could not find valid Node address for Ingress publicAddress")
+}
+
+func (p *PodConverter) ingressSpecFromLoadBalancer(service *kube_core.Service) (*mesh_proto.Dataplane_Networking_Ingress, error) {
+	if len(service.Status.LoadBalancer.Ingress) == 0 {
+		converterLog.V(1).Info("load balancer for ingress is not yet ready")
+		return &mesh_proto.Dataplane_Networking_Ingress{}, nil
+	}
+	publicAddress := ""
+	if service.Status.LoadBalancer.Ingress[0].Hostname != "" {
+		publicAddress = service.Status.LoadBalancer.Ingress[0].Hostname
+	}
+	if service.Status.LoadBalancer.Ingress[0].IP != "" {
+		publicAddress = service.Status.LoadBalancer.Ingress[0].IP
+	}
+	if publicAddress == "" {
+		converterLog.V(1).Info("load balancer for ingress is not yet ready. Hostname and IP are empty")
+		return &mesh_proto.Dataplane_Networking_Ingress{}, nil
+	}
+	ingress := &mesh_proto.Dataplane_Networking_Ingress{
+		PublicAddress: publicAddress,
+		PublicPort:    uint32(service.Spec.Ports[0].Port), // service has to have port, otherwise we would not generate inbound
+	}
+	return ingress, nil
+}
diff --git a/pkg/plugins/runtime/k8s/controllers/pod_converter.go b/pkg/plugins/runtime/k8s/controllers/pod_converter.go
index 3ceaeb505..d7dee7794 100644
--- a/pkg/plugins/runtime/k8s/controllers/pod_converter.go
+++ b/pkg/plugins/runtime/k8s/controllers/pod_converter.go
@@ -25,6 +25,7 @@ var (
 
 type PodConverter struct {
 	ServiceGetter     kube_client.Reader
+	NodeGetter        kube_client.Reader
 	ResourceConverter k8s_common.Converter
 	Zone              string
 }
@@ -153,24 +154,6 @@ func (p *PodConverter) DataplaneFor(
 	return dataplane, nil
 }
 
-func (p *PodConverter) IngressFor(pod *kube_core.Pod, services []*kube_core.Service) (*mesh_proto.Dataplane, error) {
-	ifaces, err := InboundInterfacesFor(p.Zone, pod, services)
-	if err != nil {
-		return nil, errors.Wrap(err, "could not generate inbound interfaces")
-	}
-	if len(ifaces) != 1 {
-		return nil, errors.Errorf("generated %d inbound interfaces, expected 1. Interfaces: %v", len(ifaces), ifaces)
-	}
-
-	return &mesh_proto.Dataplane{
-		Networking: &mesh_proto.Dataplane_Networking{
-			Ingress: &mesh_proto.Dataplane_Networking_Ingress{},
-			Address: pod.Status.PodIP,
-			Inbound: ifaces,
-		},
-	}, nil
-}
-
 func GatewayFor(clusterName string, pod *kube_core.Pod, services []*kube_core.Service) (*mesh_proto.Dataplane_Networking_Gateway, error) {
 	interfaces, err := InboundInterfacesFor(clusterName, pod, services)
 	if err != nil {
diff --git a/pkg/plugins/runtime/k8s/metadata/annotations.go b/pkg/plugins/runtime/k8s/metadata/annotations.go
index e13b7cfa6..caeb71a1b 100644
--- a/pkg/plugins/runtime/k8s/metadata/annotations.go
+++ b/pkg/plugins/runtime/k8s/metadata/annotations.go
@@ -25,6 +25,14 @@ const (
 	// which is crucial for Multicluster communication
 	KumaIngressAnnotation = "kuma.io/ingress"
 
+	// KumaIngressPublicAddressAnnotation allows to pick public address for Ingress
+	// If not defined, Kuma will try to pick this address from the Ingress Service
+	KumaIngressPublicAddressAnnotation = "kuma.io/ingress-public-address"
+
+	// KumaIngressPublicPortAnnotation allows to pick public port for Ingress
+	// If not defined, Kuma will try to pick this address from the Ingress Service
+	KumaIngressPublicPortAnnotation = "kuma.io/ingress-public-port"
+
 	// KumaDirectAccess defines a comma-separated list of Services that will be accessed directly
 	KumaDirectAccess = "kuma.io/direct-access-services"
 
diff --git a/pkg/plugins/runtime/k8s/plugin.go b/pkg/plugins/runtime/k8s/plugin.go
index 511935095..866398cd4 100644
--- a/pkg/plugins/runtime/k8s/plugin.go
+++ b/pkg/plugins/runtime/k8s/plugin.go
@@ -124,6 +124,7 @@ func addPodReconciler(mgr kube_ctrl.Manager, rt core_runtime.Runtime, converter
 		Log:           core.Log.WithName("controllers").WithName("Pod"),
 		PodConverter: controllers.PodConverter{
 			ServiceGetter:     mgr.GetClient(),
+			NodeGetter:        mgr.GetClient(),
 			Zone:              rt.Config().Multicluster.Remote.Zone,
 			ResourceConverter: converter,
 		},
diff --git a/pkg/xds/bootstrap/template.go b/pkg/xds/bootstrap/template.go
index 51c6c83a7..946b559dd 100644
--- a/pkg/xds/bootstrap/template.go
+++ b/pkg/xds/bootstrap/template.go
@@ -48,6 +48,10 @@ stats_config:
     regex: '^grpc\.((.+)\.)'
   - tag_name: status
     regex: '^grpc.*streams_closed(_([0-9]+))'
+  - tag_name: kafka_name
+    regex: '^kafka(\.(\S*[0-9]))\.'
+  - tag_name: kafka_type
+    regex: '^kafka\..*\.(.*)'
   - tag_name: worker
     regex: '(worker_([0-9]+)\.)'
   - tag_name: listener
diff --git a/pkg/xds/envoy/listeners/kafka_configurer.go b/pkg/xds/envoy/listeners/kafka_configurer.go
new file mode 100644
index 000000000..7342f6f9b
--- /dev/null
+++ b/pkg/xds/envoy/listeners/kafka_configurer.go
@@ -0,0 +1,42 @@
+package listeners
+
+import (
+	envoy_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
+	envoy_kafka "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/kafka_broker/v2alpha1"
+
+	util_xds "github.com/kumahq/kuma/pkg/util/xds"
+
+	"github.com/kumahq/kuma/pkg/util/proto"
+)
+
+func Kafka(statsName string) FilterChainBuilderOpt {
+	return FilterChainBuilderOptFunc(func(config *FilterChainBuilderConfig) {
+		config.Add(&KafkaConfigurer{
+			statsName: statsName,
+		})
+	})
+}
+
+type KafkaConfigurer struct {
+	statsName string
+}
+
+func (c *KafkaConfigurer) Configure(filterChain *envoy_listener.FilterChain) error {
+	pbst, err := proto.MarshalAnyDeterministic(
+		&envoy_kafka.KafkaBroker{
+			StatPrefix: util_xds.SanitizeMetric(c.statsName),
+		})
+	if err != nil {
+		return err
+	}
+
+	filterChain.Filters = append([]*envoy_listener.Filter{
+		{
+			Name: "envoy.filters.network.kafka_broker",
+			ConfigType: &envoy_listener.Filter_TypedConfig{
+				TypedConfig: pbst,
+			},
+		},
+	}, filterChain.Filters...)
+	return nil
+}
diff --git a/pkg/xds/generator/inbound_proxy_generator.go b/pkg/xds/generator/inbound_proxy_generator.go
index 59dafaa79..518e2eab6 100644
--- a/pkg/xds/generator/inbound_proxy_generator.go
+++ b/pkg/xds/generator/inbound_proxy_generator.go
@@ -68,6 +68,10 @@ func (g InboundProxyGenerator) Generate(ctx xds_context.Context, proxy *model.Pr
 					Configure(envoy_listeners.FaultInjection(proxy.FaultInjections[endpoint])).
 					Configure(envoy_listeners.Tracing(proxy.TracingBackend)).
 					Configure(envoy_listeners.HttpInboundRoute(service, envoy_common.ClusterSubset{ClusterName: localClusterName}))
+			case mesh_core.ProtocolKafka:
+				filterChainBuilder.
+					Configure(envoy_listeners.Kafka(localClusterName)).
+					Configure(envoy_listeners.TcpProxy(localClusterName, envoy_common.ClusterSubset{ClusterName: localClusterName}))
 			case mesh_core.ProtocolTCP:
 				fallthrough
 			default:
diff --git a/pkg/xds/generator/outbound_proxy_generator.go b/pkg/xds/generator/outbound_proxy_generator.go
index b10f7fe81..d85433305 100644
--- a/pkg/xds/generator/outbound_proxy_generator.go
+++ b/pkg/xds/generator/outbound_proxy_generator.go
@@ -96,6 +96,11 @@ func (_ OutboundProxyGenerator) generateLDS(proxy *model.Proxy, subsets []envoy_
 				Configure(envoy_listeners.Tracing(proxy.TracingBackend)).
 				Configure(envoy_listeners.HttpAccessLog(meshName, envoy_listeners.TrafficDirectionOutbound, sourceService, serviceName, proxy.Logs[serviceName], proxy)).
 				Configure(envoy_listeners.HttpOutboundRoute(serviceName, subsets, proxy.Dataplane.Spec.TagSet()))
+		case mesh_core.ProtocolKafka:
+			filterChainBuilder.
+				Configure(envoy_listeners.Kafka(serviceName)).
+				Configure(envoy_listeners.TcpProxy(serviceName, subsets...)).
+				Configure(envoy_listeners.NetworkAccessLog(meshName, envoy_listeners.TrafficDirectionOutbound, sourceService, serviceName, proxy.Logs[serviceName], proxy))
 		case mesh_core.ProtocolTCP:
 			fallthrough
 		default:
diff --git a/pkg/xds/generator/protocol.go b/pkg/xds/generator/protocol.go
index 73679e853..52e0140f5 100644
--- a/pkg/xds/generator/protocol.go
+++ b/pkg/xds/generator/protocol.go
@@ -15,6 +15,7 @@ var (
 		mesh_core.ProtocolGRPC:  {mesh_core.ProtocolGRPC, mesh_core.ProtocolHTTP2, mesh_core.ProtocolTCP},
 		mesh_core.ProtocolHTTP2: {mesh_core.ProtocolHTTP2, mesh_core.ProtocolTCP},
 		mesh_core.ProtocolHTTP:  {mesh_core.ProtocolHTTP, mesh_core.ProtocolTCP},
+		mesh_core.ProtocolKafka: {mesh_core.ProtocolKafka, mesh_core.ProtocolTCP},
 		mesh_core.ProtocolTCP:   {mesh_core.ProtocolTCP},
 	}
 )
diff --git a/pkg/xds/topology/dataplanes.go b/pkg/xds/topology/dataplanes.go
index a0ef64e9e..6ab05960c 100644
--- a/pkg/xds/topology/dataplanes.go
+++ b/pkg/xds/topology/dataplanes.go
@@ -46,12 +46,34 @@ func ResolveAddress(lookupIPFunc lookup.LookupIPFunc, dataplane *core_mesh.Datap
 	return nil
 }
 
+func ResolveIngressPublicAddress(lookupIPFunc lookup.LookupIPFunc, dataplane *core_mesh.DataplaneResource) error {
+	if dataplane.Spec.Networking.Ingress.PublicAddress == "" { // Ingress may not have public address yet.
+		return nil
+	}
+	ips, err := lookupIPFunc(dataplane.Spec.Networking.Ingress.PublicAddress)
+	if err != nil {
+		return err
+	}
+	if len(ips) == 0 {
+		return errors.Errorf("can't resolve address %v", dataplane.Spec.Networking.Ingress.PublicAddress)
+	}
+	dataplane.Spec.Networking.Ingress.PublicAddress = ips[0].String()
+	return nil
+}
+
 func ResolveAddresses(log logr.Logger, lookupIPFunc lookup.LookupIPFunc, dataplanes []*core_mesh.DataplaneResource) []*core_mesh.DataplaneResource {
 	rv := []*core_mesh.DataplaneResource{}
 	for _, d := range dataplanes {
-		if err := ResolveAddress(lookupIPFunc, d); err != nil {
-			log.Error(err, "failed to resolve dataplane's domain name, skipping dataplane")
-			continue
+		if d.Spec.IsIngress() {
+			if err := ResolveIngressPublicAddress(lookupIPFunc, d); err != nil {
+				log.Error(err, "failed to resolve ingress's public name, skipping dataplane")
+				continue
+			}
+		} else {
+			if err := ResolveAddress(lookupIPFunc, d); err != nil {
+				log.Error(err, "failed to resolve dataplane's domain name, skipping dataplane")
+				continue
+			}
 		}
 		rv = append(rv, d)
 	}
diff --git a/pkg/xds/topology/outbound.go b/pkg/xds/topology/outbound.go
index ebaa7e2bf..330fca410 100644
--- a/pkg/xds/topology/outbound.go
+++ b/pkg/xds/topology/outbound.go
@@ -1,6 +1,8 @@
 package topology
 
 import (
+	"fmt"
+
 	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
 	mesh_core "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	core_xds "github.com/kumahq/kuma/pkg/core/xds"
@@ -22,47 +24,100 @@ func BuildEndpointMap(
 	externalServices []*mesh_core.ExternalServiceResource,
 ) core_xds.EndpointMap {
 	outbound := core_xds.EndpointMap{}
+	ingressInstances := fillIngressOutbounds(outbound, dataplanes, zone, mesh)
+	endpointWeight := uint32(1)
+	if ingressInstances > 0 {
+		endpointWeight = ingressInstances
+	}
+	fillDataplaneOutbounds(outbound, dataplanes, mesh, endpointWeight)
+	fillExternalServicesOutbounds(outbound, externalServices, mesh)
+	return outbound
+}
+
+// endpointWeight defines default weight for in-cluster endpoint.
+// Examples of having service "backend":
+// 1) Standalone deployment, 2 instances in one cluster (zone1)
+//    All endpoints have to have the same weight (ex. 1) to achieve fair loadbalancing.
+//    Endpoints:
+//    * backend-zone1-1 - weight: 1
+//    * backend-zone1-2 - weight: 1
+// 2) Multi-zone deployment, 2 instances in "zone1" (local zone), 3 instances in "zone2" (remote zone) with 1 Ingress instance
+//    Endpoints:
+//    * backend-zone1-1 - weight: 1
+//    * backend-zone1-2 - weight: 1
+//    * ingress-zone2-1 - weight: 3 (all remote endpoints are aggregated to one Ingress, it needs to have weight of instances in other cluster)
+// 3) Multi-zone deployment, 2 instances in "zone1" (local zone), 2 instances in "zone2" (remote zone) with 1 Ingress instance
+//    Many instances of Ingress will forward the traffic to the same endpoints in "zone2" so we need to lower the weights.
+//    Since weights are integers, we cannot put fractional on ingress endpoints weights, we need to adjust "default" weight for local zone
+//    Endpoints:
+//    * backend-zone1-1 - weight: 2
+//    * backend-zone1-2 - weight: 2
+//    * ingress-zone2-1 - weight: 3
+//    * ingress-zone2-2 - weight: 3
+func fillDataplaneOutbounds(outbound core_xds.EndpointMap, dataplanes []*mesh_core.DataplaneResource, mesh *mesh_core.MeshResource, endpointWeight uint32) {
 	for _, dataplane := range dataplanes {
-		if dataplane.Spec.IsIngress() && dataplane.Spec.IsRemoteIngress(zone) && mesh.MTLSEnabled() {
-			for _, ingress := range dataplane.Spec.Networking.GetIngress().GetAvailableServices() {
-				if ingress.Mesh != mesh.GetMeta().GetName() {
-					continue
-				}
-				service := ingress.Tags[mesh_proto.ServiceTag]
-				outbound[service] = append(outbound[service], core_xds.Endpoint{
-					Target:   dataplane.Spec.Networking.Address,
-					Port:     dataplane.Spec.Networking.Inbound[0].Port,
-					Tags:     ingress.Tags,
-					Weight:   ingress.Instances,
-					Locality: localityFromTags(mesh, priorityRemote, ingress.Tags),
-				})
-			}
+		if dataplane.Spec.IsIngress() {
 			continue
 		}
+		for _, inbound := range dataplane.Spec.Networking.GetInbound() {
+			service := inbound.Tags[mesh_proto.ServiceTag]
+			iface := dataplane.Spec.Networking.ToInboundInterface(inbound)
+			// TODO(yskopets): do we need to dedup?
+			// TODO(yskopets): sort ?
+			outbound[service] = append(outbound[service], core_xds.Endpoint{
+				Target:   iface.DataplaneIP,
+				Port:     iface.DataplanePort,
+				Tags:     inbound.Tags,
+				Weight:   endpointWeight,
+				Locality: localityFromTags(mesh, priorityLocal, inbound.Tags),
+			})
+		}
+	}
+}
+
+func fillIngressOutbounds(outbound core_xds.EndpointMap, dataplanes []*mesh_core.DataplaneResource, zone string, mesh *mesh_core.MeshResource) uint32 {
+	ingressInstances := map[string]bool{}
+	for _, dataplane := range dataplanes {
 		if !dataplane.Spec.IsIngress() {
-			for _, inbound := range dataplane.Spec.Networking.GetInbound() {
-				service := inbound.Tags[mesh_proto.ServiceTag]
-				iface := dataplane.Spec.Networking.ToInboundInterface(inbound)
-				// TODO(yskopets): do we need to dedup?
-				// TODO(yskopets): sort ?
-				outbound[service] = append(outbound[service], core_xds.Endpoint{
-					Target:   iface.DataplaneIP,
-					Port:     iface.DataplanePort,
-					Tags:     inbound.Tags,
-					Weight:   1,
-					Locality: localityFromTags(mesh, priorityLocal, inbound.Tags),
-				})
+			continue
+		}
+		if !dataplane.Spec.IsRemoteIngress(zone) {
+			continue // we only need Ingress for other zones, we don't want to direct request to the same zone through Ingress
+		}
+		if !mesh.MTLSEnabled() {
+			// Ingress routes the request by TLS SNI, therefore for cross cluster communication MTLS is required
+			// We ignore Ingress from endpoints if MTLS is disabled, otherwise we would fail anyway.
+			continue
+		}
+		if !dataplane.Spec.HasPublicAddress() {
+			continue // Dataplane is not reachable yet from other clusters. This may happen when Ingress Service is pending waiting on External IP on Kubernetes.
+		}
+		ingressCoordinates := fmt.Sprintf("%s;%d", dataplane.Spec.Networking.Ingress.PublicAddress, dataplane.Spec.Networking.Ingress.PublicPort)
+		if ingressInstances[ingressCoordinates] {
+			continue // many Ingress instances can be placed in front of one load balancer (all instances can have the same public address and port). In this case we only need one Instance avoiding creating unnecessary duplicated endpoints
+		}
+		ingressInstances[ingressCoordinates] = true
+		for _, service := range dataplane.Spec.Networking.GetIngress().GetAvailableServices() {
+			if service.Mesh != mesh.GetMeta().GetName() {
+				continue
 			}
+			serviceName := service.Tags[mesh_proto.ServiceTag]
+			outbound[serviceName] = append(outbound[serviceName], core_xds.Endpoint{
+				Target:   dataplane.Spec.Networking.Ingress.PublicAddress,
+				Port:     dataplane.Spec.Networking.Ingress.PublicPort,
+				Tags:     service.Tags,
+				Weight:   service.Instances,
+				Locality: localityFromTags(mesh, priorityRemote, service.Tags),
+			})
 		}
 	}
+	return uint32(len(ingressInstances))
+}
 
+func fillExternalServicesOutbounds(outbound core_xds.EndpointMap, externalServices []*mesh_core.ExternalServiceResource, mesh *mesh_core.MeshResource) {
 	for _, externalService := range externalServices {
 		service := externalService.Spec.GetService()
-
-		tlsEnabled := false
-		if externalService.Spec.Networking.Tls != nil {
-			tlsEnabled = externalService.Spec.Networking.Tls.Enabled
-		}
+		tlsEnabled := externalService.Spec.GetNetworking().GetTls().GetEnabled()
 
 		tags := externalService.Spec.GetTags()
 		if tlsEnabled {
@@ -80,8 +135,6 @@ func BuildEndpointMap(
 			Locality: localityFromTags(mesh, priorityRemote, tags),
 		})
 	}
-
-	return outbound
 }
 
 func localityFromTags(mesh *mesh_core.MeshResource, priority uint32, tags map[string]string) *core_xds.Locality {


Test patch:
diff --git a/app/kumactl/cmd/completion/testdata/bash.golden b/app/kumactl/cmd/completion/testdata/bash.golden
index e5ac83ce7..b15a57978 100644
--- a/app/kumactl/cmd/completion/testdata/bash.golden
+++ b/app/kumactl/cmd/completion/testdata/bash.golden
@@ -1725,6 +1725,7 @@ _kumactl_inspect_dataplanes()
     flags_completion=()
 
     flags+=("--gateway")
+    flags+=("--ingress")
     flags+=("--tag=")
     two_word_flags+=("--tag")
     flags+=("--config-file=")
diff --git a/app/kumactl/cmd/completion/testdata/zsh.golden b/app/kumactl/cmd/completion/testdata/zsh.golden
index 11e49aea2..1d49273c1 100644
--- a/app/kumactl/cmd/completion/testdata/zsh.golden
+++ b/app/kumactl/cmd/completion/testdata/zsh.golden
@@ -705,6 +705,7 @@ function _kumactl_inspect {
 function _kumactl_inspect_dataplanes {
   _arguments \
     '--gateway[filter gateway dataplanes]' \
+    '--ingress[filter ingress dataplanes]' \
     '--tag[filter by tag in format of key=value. You can provide many tags]:' \
     '--config-file[path to the configuration file to use]:' \
     '--log-level[log level: one of off|info|debug]:' \
diff --git a/app/kumactl/cmd/get/get_zones_test.go b/app/kumactl/cmd/get/get_zones_test.go
index dc1a15fa9..f6945ee0e 100644
--- a/app/kumactl/cmd/get/get_zones_test.go
+++ b/app/kumactl/cmd/get/get_zones_test.go
@@ -30,21 +30,13 @@ var _ = Describe("kumactl get zones", func() {
 
 	zoneResources := []*system.ZoneResource{
 		{
-			Spec: v1alpha1.Zone{
-				Ingress: &v1alpha1.Zone_Ingress{
-					Address: "192.168.0.2:10000",
-				},
-			},
+			Spec: v1alpha1.Zone{},
 			Meta: &test_model.ResourceMeta{
 				Name: "zone-1",
 			},
 		},
 		{
-			Spec: v1alpha1.Zone{
-				Ingress: &v1alpha1.Zone_Ingress{
-					Address: "192.168.1.2:10000",
-				},
-			},
+			Spec: v1alpha1.Zone{},
 			Meta: &test_model.ResourceMeta{
 				Name: "zone-2",
 			},
diff --git a/app/kumactl/cmd/get/testdata/get-zones.golden.json b/app/kumactl/cmd/get/testdata/get-zones.golden.json
index f1a5c62f5..4826975d8 100644
--- a/app/kumactl/cmd/get/testdata/get-zones.golden.json
+++ b/app/kumactl/cmd/get/testdata/get-zones.golden.json
@@ -5,20 +5,14 @@
       "type": "Zone",
       "name": "zone-1",
       "creationTime": "0001-01-01T00:00:00Z",
-      "modificationTime": "0001-01-01T00:00:00Z",
-      "ingress": {
-        "address": "192.168.0.2:10000"
-      }
+      "modificationTime": "0001-01-01T00:00:00Z"
     },
     {
       "type": "Zone",
       "name": "zone-2",
       "creationTime": "0001-01-01T00:00:00Z",
-      "modificationTime": "0001-01-01T00:00:00Z",
-      "ingress": {
-        "address": "192.168.1.2:10000"
-      }
+      "modificationTime": "0001-01-01T00:00:00Z"
     }
   ],
   "next": null
-}
\ No newline at end of file
+}
diff --git a/app/kumactl/cmd/get/testdata/get-zones.golden.txt b/app/kumactl/cmd/get/testdata/get-zones.golden.txt
index e6c9da156..5e5e1e037 100644
--- a/app/kumactl/cmd/get/testdata/get-zones.golden.txt
+++ b/app/kumactl/cmd/get/testdata/get-zones.golden.txt
@@ -1,3 +1,3 @@
-NAME     INGRESS             AGE
-zone-1   192.168.0.2:10000   292y
-zone-2   192.168.1.2:10000   292y
\ No newline at end of file
+NAME     AGE
+zone-1   292y
+zone-2   292y
diff --git a/app/kumactl/cmd/get/testdata/get-zones.golden.yaml b/app/kumactl/cmd/get/testdata/get-zones.golden.yaml
index 73ce711e4..c4c1b7094 100644
--- a/app/kumactl/cmd/get/testdata/get-zones.golden.yaml
+++ b/app/kumactl/cmd/get/testdata/get-zones.golden.yaml
@@ -1,15 +1,11 @@
 total: 2
 items:
   - creationTime: "0001-01-01T00:00:00Z"
-    ingress:
-      address: 192.168.0.2:10000
     modificationTime: "0001-01-01T00:00:00Z"
     name: zone-1
     type: Zone
   - creationTime: "0001-01-01T00:00:00Z"
-    ingress:
-      address: 192.168.1.2:10000
     modificationTime: "0001-01-01T00:00:00Z"
     name: zone-2
     type: Zone
-next: null
\ No newline at end of file
+next: null
diff --git a/app/kumactl/cmd/get/testdata/get-zones.pagination.golden.txt b/app/kumactl/cmd/get/testdata/get-zones.pagination.golden.txt
index 9ac0ad0aa..806a8f3b8 100644
--- a/app/kumactl/cmd/get/testdata/get-zones.pagination.golden.txt
+++ b/app/kumactl/cmd/get/testdata/get-zones.pagination.golden.txt
@@ -1,4 +1,4 @@
-NAME     INGRESS             AGE
-zone-1   192.168.0.2:10000   292y
+NAME     AGE
+zone-1   292y
 
 Rerun command with --offset=1 argument to retrieve more resources
diff --git a/app/kumactl/cmd/inspect/inspect_dataplanes_test.go b/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
index cc23e7f64..973095b75 100644
--- a/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
+++ b/app/kumactl/cmd/inspect/inspect_dataplanes_test.go
@@ -33,13 +33,15 @@ import (
 type testDataplaneOverviewClient struct {
 	receivedTags    map[string]string
 	receivedGateway bool
+	receivedIngress bool
 	total           uint32
 	overviews       []*mesh_core.DataplaneOverviewResource
 }
 
-func (c *testDataplaneOverviewClient) List(_ context.Context, _ string, tags map[string]string, gateway bool) (*mesh_core.DataplaneOverviewResourceList, error) {
+func (c *testDataplaneOverviewClient) List(_ context.Context, _ string, tags map[string]string, gateway bool, ingress bool) (*mesh_core.DataplaneOverviewResourceList, error) {
 	c.receivedTags = tags
 	c.receivedGateway = gateway
+	c.receivedIngress = ingress
 	return &mesh_core.DataplaneOverviewResourceList{
 		Items: c.overviews,
 		Pagination: model.Pagination{
@@ -285,5 +287,21 @@ var _ = Describe("kumactl inspect dataplanes", func() {
 				Expect(testClient.receivedGateway).To(BeTrue())
 			})
 		})
+
+		Describe("kumactl inspect dataplanes --ingress", func() {
+			It("gateway should be passed to the client", func() {
+				// given
+				rootCmd.SetArgs([]string{
+					"--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"),
+					"inspect", "dataplanes", "--ingress"})
+
+				// when
+				err := rootCmd.Execute()
+				// then
+				Expect(err).ToNot(HaveOccurred())
+				// and
+				Expect(testClient.receivedIngress).To(BeTrue())
+			})
+		})
 	})
 })
diff --git a/app/kumactl/cmd/inspect/inspect_zones_test.go b/app/kumactl/cmd/inspect/inspect_zones_test.go
index 5275df481..860cdff1f 100644
--- a/app/kumactl/cmd/inspect/inspect_zones_test.go
+++ b/app/kumactl/cmd/inspect/inspect_zones_test.go
@@ -65,9 +65,7 @@ var _ = Describe("kumactl inspect zones", func() {
 					ModificationTime: now,
 				},
 				Spec: system_proto.ZoneOverview{
-					Zone: &system_proto.Zone{
-						Ingress: &system_proto.Zone_Ingress{Address: "192.168.1.1:1000"},
-					},
+					Zone: &system_proto.Zone{},
 					ZoneInsight: &system_proto.ZoneInsight{
 						Subscriptions: []*system_proto.KDSSubscription{
 							{
@@ -150,9 +148,7 @@ var _ = Describe("kumactl inspect zones", func() {
 					ModificationTime: now,
 				},
 				Spec: system_proto.ZoneOverview{
-					Zone: &system_proto.Zone{
-						Ingress: &system_proto.Zone_Ingress{Address: "192.168.1.2:1000"},
-					},
+					Zone: &system_proto.Zone{},
 					ZoneInsight: &system_proto.ZoneInsight{
 						Subscriptions: []*system_proto.KDSSubscription{
 							{
diff --git a/app/kumactl/cmd/inspect/testdata/inspect-zone.golden.yaml b/app/kumactl/cmd/inspect/testdata/inspect-zone.golden.yaml
index 24256c387..4a0a84ab6 100644
--- a/app/kumactl/cmd/inspect/testdata/inspect-zone.golden.yaml
+++ b/app/kumactl/cmd/inspect/testdata/inspect-zone.golden.yaml
@@ -3,9 +3,7 @@ items:
     modificationTime: "2019-07-17T18:08:41Z"
     name: zone-1
     type: ZoneOverview
-    zone:
-      ingress:
-        address: 192.168.1.1:1000
+    zone: {}
     zoneInsight:
       subscriptions:
         - connectTime: "2018-07-17T16:05:36.995Z"
@@ -60,9 +58,7 @@ items:
     modificationTime: "2019-07-17T18:08:41Z"
     name: zone-2
     type: ZoneOverview
-    zone:
-      ingress:
-        address: 192.168.1.2:1000
+    zone: {}
     zoneInsight:
       subscriptions:
         - globalInstanceId: node-001
@@ -72,4 +68,4 @@ items:
         - globalInstanceId: node-003
           id: "3"
 next: null
-total: 2
\ No newline at end of file
+total: 2
diff --git a/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.json b/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.json
index 19f723d0e..d2da3f966 100644
--- a/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.json
+++ b/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.json
@@ -7,9 +7,6 @@
       "creationTime": "2018-07-17T16:05:36.995Z",
       "modificationTime": "2019-07-17T18:08:41Z",
       "zone": {
-        "ingress": {
-          "address": "192.168.1.1:1000"
-        }
       },
       "zoneInsight": {
         "subscriptions": [
@@ -90,9 +87,6 @@
       "creationTime": "2018-07-17T16:05:36.995Z",
       "modificationTime": "2019-07-17T18:08:41Z",
       "zone": {
-        "ingress": {
-          "address": "192.168.1.2:1000"
-        }
       },
       "zoneInsight": {
         "subscriptions": [
@@ -113,4 +107,4 @@
     }
   ],
   "next": null
-}
\ No newline at end of file
+}
diff --git a/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.txt b/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.txt
index e250de97b..1412ca6e9 100644
--- a/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.txt
+++ b/app/kumactl/cmd/inspect/testdata/inspect-zones.golden.txt
@@ -1,3 +1,3 @@
-MESH      NAME     INGRESS            STATUS    LAST CONNECTED AGO   LAST UPDATED AGO   TOTAL UPDATES   TOTAL ERRORS
-default   zone-1   192.168.1.1:1000   Online    2h                   never              42              13
-default   zone-2   192.168.1.2:1000   Offline   never                never              0               0
\ No newline at end of file
+MESH      NAME     STATUS    LAST CONNECTED AGO   LAST UPDATED AGO   TOTAL UPDATES   TOTAL ERRORS
+default   zone-1   Online    2h                   never              42              13
+default   zone-2   Offline   never                never              0               0
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.cni-enabled.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.cni-enabled.golden.yaml
index 9c61747f6..bd654497b 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.cni-enabled.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.cni-enabled.golden.yaml
@@ -5610,6 +5610,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.defaults.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.defaults.golden.yaml
index e638ad025..c79d79e3c 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.defaults.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.defaults.golden.yaml
@@ -5557,6 +5557,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.global.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.global.golden.yaml
index 5a4ca54fd..6004f5211 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.global.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.global.golden.yaml
@@ -5557,6 +5557,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.overrides.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.overrides.golden.yaml
index 7c417ec8e..59f9d6486 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.overrides.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.overrides.golden.yaml
@@ -5557,6 +5557,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.remote.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.remote.golden.yaml
index 229a3628f..044b580f3 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.remote.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.remote.golden.yaml
@@ -5557,6 +5557,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/cmd/install/testdata/install-control-plane.with-ingress.golden.yaml b/app/kumactl/cmd/install/testdata/install-control-plane.with-ingress.golden.yaml
index 049443087..8025d10cf 100644
--- a/app/kumactl/cmd/install/testdata/install-control-plane.with-ingress.golden.yaml
+++ b/app/kumactl/cmd/install/testdata/install-control-plane.with-ingress.golden.yaml
@@ -5566,6 +5566,7 @@ rules:
       - pods
       - services
       - configmaps
+      - nodes
     verbs:
       - get
       - list
diff --git a/app/kumactl/pkg/resources/dataplane_overview_client_test.go b/app/kumactl/pkg/resources/dataplane_overview_client_test.go
index eff859772..5bb170a9f 100644
--- a/app/kumactl/pkg/resources/dataplane_overview_client_test.go
+++ b/app/kumactl/pkg/resources/dataplane_overview_client_test.go
@@ -44,7 +44,7 @@ var _ = Describe("httpDataplaneOverviewClient", func() {
 			}
 
 			// when
-			list, err := client.List(context.Background(), meshName, tags, false)
+			list, err := client.List(context.Background(), meshName, tags, false, false)
 			// then
 			Expect(err).ToNot(HaveOccurred())
 			// and
@@ -78,7 +78,7 @@ var _ = Describe("httpDataplaneOverviewClient", func() {
 			}
 
 			// when
-			list, err := client.List(context.Background(), meshName, map[string]string{}, true)
+			list, err := client.List(context.Background(), meshName, map[string]string{}, true, false)
 			// then
 			Expect(err).ToNot(HaveOccurred())
 			// and
@@ -102,7 +102,7 @@ var _ = Describe("httpDataplaneOverviewClient", func() {
 			}
 
 			// when
-			_, err := client.List(context.Background(), "mesh-1", map[string]string{}, false)
+			_, err := client.List(context.Background(), "mesh-1", map[string]string{}, false, false)
 
 			// then
 			Expect(err).To(MatchError("(400): some error from server"))
diff --git a/pkg/api-server/zone_overview_endpoints_test.go b/pkg/api-server/zone_overview_endpoints_test.go
index 37d0edb80..ba7bb70ca 100644
--- a/pkg/api-server/zone_overview_endpoints_test.go
+++ b/pkg/api-server/zone_overview_endpoints_test.go
@@ -79,17 +79,11 @@ var _ = Describe("Zone Overview Endpoints", func() {
 	}
 
 	BeforeEach(func() {
-		createZoneWithInsights("zone-1", system_proto.Zone{
-			Ingress: &system_proto.Zone_Ingress{Address: "10.20.1.1:10001"},
-		})
+		createZoneWithInsights("zone-1", system_proto.Zone{})
 
-		createZoneWithInsights("zone-2", system_proto.Zone{
-			Ingress: &system_proto.Zone_Ingress{Address: "10.20.1.2:10002"},
-		})
+		createZoneWithInsights("zone-2", system_proto.Zone{})
 
-		createZoneWithInsights("zone-3", system_proto.Zone{
-			Ingress: &system_proto.Zone_Ingress{Address: "10.20.1.3:10003"},
-		})
+		createZoneWithInsights("zone-3", system_proto.Zone{})
 	})
 
 	zone1Json := `
@@ -99,9 +93,6 @@ var _ = Describe("Zone Overview Endpoints", func() {
  "creationTime": "2018-07-17T16:05:36.995Z",
  "modificationTime": "2018-07-17T16:05:36.995Z",
  "zone": {
-  "ingress": {
-   "address": "10.20.1.1:10001"
-  }
  },
  "zoneInsight": {
   "subscriptions": [
@@ -124,9 +115,6 @@ var _ = Describe("Zone Overview Endpoints", func() {
  "creationTime": "2018-07-17T16:05:36.995Z",
  "modificationTime": "2018-07-17T16:05:36.995Z",
  "zone": {
-  "ingress": {
-   "address": "10.20.1.2:10002"
-  }
  },
  "zoneInsight": {
   "subscriptions": [
@@ -149,9 +137,6 @@ var _ = Describe("Zone Overview Endpoints", func() {
  "creationTime": "2018-07-17T16:05:36.995Z",
  "modificationTime": "2018-07-17T16:05:36.995Z",
  "zone": {
-  "ingress": {
-   "address": "10.20.1.3:10003"
-  }
  },
  "zoneInsight": {
   "subscriptions": [
diff --git a/pkg/core/resources/apis/mesh/dataplane_helpers_test.go b/pkg/core/resources/apis/mesh/dataplane_helpers_test.go
index 021eb4d79..589a0e8de 100644
--- a/pkg/core/resources/apis/mesh/dataplane_helpers_test.go
+++ b/pkg/core/resources/apis/mesh/dataplane_helpers_test.go
@@ -468,6 +468,10 @@ var _ = Describe("ParseProtocol()", func() {
 			tag:      "grpc",
 			expected: ProtocolGRPC,
 		}),
+		Entry("kafka", testCase{
+			tag:      "kafka",
+			expected: ProtocolKafka,
+		}),
 		Entry("mongo", testCase{
 			tag:      "mongo",
 			expected: ProtocolUnknown,
diff --git a/pkg/core/resources/apis/mesh/dataplane_overview_test.go b/pkg/core/resources/apis/mesh/dataplane_overview_test.go
index 95919ad25..98d16a7ea 100644
--- a/pkg/core/resources/apis/mesh/dataplane_overview_test.go
+++ b/pkg/core/resources/apis/mesh/dataplane_overview_test.go
@@ -148,7 +148,7 @@ var _ = Describe("DataplaneOverview", func() {
 			},
 		}
 		It("should retain gateway overviews", func() {
-			dataplanes.RetainGatewayDataplanes()
+			dataplanes.RetainGatewayDataplanes("true")
 			Expect(dataplanes).To(Equal(gatewayDataplanes))
 		})
 	})
diff --git a/pkg/core/resources/apis/mesh/dataplane_validator_test.go b/pkg/core/resources/apis/mesh/dataplane_validator_test.go
index 89255dbda..2c9380ef6 100644
--- a/pkg/core/resources/apis/mesh/dataplane_validator_test.go
+++ b/pkg/core/resources/apis/mesh/dataplane_validator_test.go
@@ -112,13 +112,15 @@ var _ = Describe("Dataplane", func() {
                   tags:
                     kuma.io/service: redis`,
 		),
-		Entry("dataplane in ingress mode", `
+		Entry("dataplane in ingress mode with public address and port", `
             type: Dataplane
             name: dp-1
             mesh: default
             networking:
                 address: 192.168.0.1
                 ingress:
+                  publicAddress: 10.0.0.1
+                  publicPort: 1234
                   availableServices:
                     - tags:
                         kuma.io/service: backend
@@ -131,6 +133,18 @@ var _ = Describe("Dataplane", func() {
                 inbound:
                   - port: 10001`,
 		),
+		// no public address and port is valid because we may be waiting for Kubernetes to reconcile it
+		Entry("dataplane in ingress mode without public address and port", `
+            type: Dataplane
+            name: dp-1
+            mesh: default
+            networking:
+                address: 192.168.0.1
+                ingress:
+                  availableServices: []
+                inbound:
+                  - port: 10001`,
+		),
 		Entry("dataplane domain name in the address", `
             type: Dataplane
             name: dp-1
@@ -411,7 +425,7 @@ var _ = Describe("Dataplane", func() {
 			expected: `
                 violations:
                 - field: 'networking.inbound[0].tags["kuma.io/protocol"]'
-                  message: 'tag "kuma.io/protocol" has an invalid value "". Allowed values: grpc, http, http2, tcp'
+                  message: 'tag "kuma.io/protocol" has an invalid value "". Allowed values: grpc, http, http2, kafka, tcp'
                 - field: 'networking.inbound[0].tags["kuma.io/protocol"]'
                   message: tag value cannot be empty`,
 		}),
@@ -433,7 +447,7 @@ var _ = Describe("Dataplane", func() {
 			expected: `
                 violations:
                 - field: 'networking.inbound[0].tags["kuma.io/protocol"]'
-                  message: 'tag "kuma.io/protocol" has an invalid value "not-yet-supported-protocol". Allowed values: grpc, http, http2, tcp'`,
+                  message: 'tag "kuma.io/protocol" has an invalid value "not-yet-supported-protocol". Allowed values: grpc, http, http2, kafka, tcp'`,
 		}),
 		Entry("networking.gateway: empty service tag", testCase{
 			dataplane: `
@@ -742,6 +756,36 @@ var _ = Describe("Dataplane", func() {
                 - field: networking.inbound[0].address
                   message: cannot be defined in the ingress mode`,
 		}),
+		Entry("networking.ingress: invalid public address and port", testCase{
+			dataplane: `
+                type: Dataplane
+                name: dp-1
+                mesh: default
+                networking:
+                  address: 192.168.0.1
+                  ingress:
+                    publicAddress: "!@#$"
+                    publicPort: 100000
+                    availableServices:
+                      - tags: 
+                          kuma.io/service: backend
+                          version: "1"
+                          region: us
+                      - tags:
+                          kuma.io/service: web
+                          version: v2
+                          region: eu
+                  inbound:
+                    - port: 10001
+                      tags:
+                        name: ingress-dp`,
+			expected: `
+                violations:
+                - field: networking.ingress.publicAddress.address
+                  message: address has to be valid IP address or domain name
+                - field: networking.ingress.publicPort
+                  message: port has to be in range of [1, 65535]`,
+		}),
 		Entry("inbound service address", testCase{
 			dataplane: `
                 type: Dataplane
diff --git a/pkg/core/resources/apis/mesh/externalservice_validator_test.go b/pkg/core/resources/apis/mesh/externalservice_validator_test.go
index 6ba44ead1..70f841d0e 100644
--- a/pkg/core/resources/apis/mesh/externalservice_validator_test.go
+++ b/pkg/core/resources/apis/mesh/externalservice_validator_test.go
@@ -208,7 +208,7 @@ var _ = Describe("ExternalService", func() {
                 - field: tags["kuma.io/protocol"]
                   message: tag value cannot be empty
                 - field: tags["kuma.io/protocol"]
-                  message: 'tag "kuma.io/protocol" has an invalid value "". Allowed values: grpc, http, http2, tcp'
+                  message: 'tag "kuma.io/protocol" has an invalid value "". Allowed values: grpc, http, http2, kafka, tcp'
 `,
 		}),
 		Entry("tags: `protocol` tag with unsupported value", testCase{
@@ -224,7 +224,7 @@ var _ = Describe("ExternalService", func() {
 			expected: `
                 violations:
                 - field: tags["kuma.io/protocol"]
-                  message: 'tag "kuma.io/protocol" has an invalid value "not-yet-supported-protocol". Allowed values: grpc, http, http2, tcp'`,
+                  message: 'tag "kuma.io/protocol" has an invalid value "not-yet-supported-protocol". Allowed values: grpc, http, http2, kafka, tcp'`,
 		}),
 		Entry("tags: tag name with invalid characters", testCase{
 			dataplane: `
diff --git a/pkg/core/resources/apis/system/zone_validator_test.go b/pkg/core/resources/apis/system/zone_validator_test.go
deleted file mode 100644
index 482778666..000000000
--- a/pkg/core/resources/apis/system/zone_validator_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package system_test
-
-import (
-	"fmt"
-
-	"github.com/ghodss/yaml"
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/ginkgo/extensions/table"
-	. "github.com/onsi/gomega"
-
-	"github.com/kumahq/kuma/pkg/core/resources/apis/system"
-
-	util_proto "github.com/kumahq/kuma/pkg/util/proto"
-)
-
-var _ = Describe("Zone", func() {
-	Describe("Validate()", func() {
-		DescribeTable("should pass validation",
-			func(zoneYAML string) {
-				// setup
-				zone := system.ZoneResource{}
-
-				// when
-				err := util_proto.FromYAML([]byte(zoneYAML), &zone.Spec)
-				// then
-				Expect(err).ToNot(HaveOccurred())
-				fmt.Printf("%v", zone.Spec)
-
-				// when
-				verr := zone.Validate()
-				// then
-				Expect(verr).ToNot(HaveOccurred())
-			},
-			Entry("valid zone", `
-            ingress:
-              address: 192.168.0.2:10001`),
-		)
-
-		type testCase struct {
-			zone     string
-			expected string
-		}
-		DescribeTable("should validate all fields and return as much individual errors as possible",
-			func(given testCase) {
-				// setup
-				zone := system.ZoneResource{}
-
-				// when
-				err := util_proto.FromYAML([]byte(given.zone), &zone.Spec)
-				// then
-				Expect(err).ToNot(HaveOccurred())
-
-				// when
-				verr := zone.Validate()
-				// and
-				actual, err := yaml.Marshal(verr)
-
-				// then
-				Expect(err).ToNot(HaveOccurred())
-				// and
-				Expect(actual).To(MatchYAML(given.expected))
-			},
-			Entry("spec: empty", testCase{
-				zone: ``,
-				expected: `
-               violations:
-                 - field: address
-                   message: cannot be empty`}),
-			Entry("wrong format", testCase{
-				zone: `
-               ingress:
-                 address: 192.168.0.2`,
-				expected: `
-               violations:
-                 - field: address
-                   message: "invalid address: address 192.168.0.2: missing port in address"`}),
-			Entry("spec: empty", testCase{
-				zone: ``,
-				expected: `
-               violations:
-                 - field: address
-                   message: cannot be empty`}),
-			Entry("url instead of address", testCase{
-				zone: `
-               ingress:
-                 address: grpcs://192.168.0.2:1234`,
-				expected: `
-               violations:
-                 - field: address
-                   message: should not be URL. Expected format is hostname:port`}),
-		)
-	})
-})
diff --git a/pkg/kds/global/components_test.go b/pkg/kds/global/components_test.go
index b06b19e8e..a3ecfb7cb 100644
--- a/pkg/kds/global/components_test.go
+++ b/pkg/kds/global/components_test.go
@@ -54,11 +54,7 @@ var _ = Describe("Global Sync", func() {
 			clientStreams = append(clientStreams, ss.ClientStream(stopCh))
 		}
 		zone := &system.ZoneResource{
-			Spec: system_proto.Zone{
-				Ingress: &system_proto.Zone_Ingress{
-					Address: "192.168.0.2:10001",
-				},
-			},
+			Spec: system_proto.Zone{},
 		}
 		kds_setup.StartClient(clientStreams, []model.ResourceType{mesh.DataplaneType}, stopCh, global.Callbacks(globalSyncer, false, zone))
 
diff --git a/pkg/plugins/runtime/k8s/controllers/pod_converter_test.go b/pkg/plugins/runtime/k8s/controllers/pod_converter_test.go
index 873078c90..ad01570d4 100644
--- a/pkg/plugins/runtime/k8s/controllers/pod_converter_test.go
+++ b/pkg/plugins/runtime/k8s/controllers/pod_converter_test.go
@@ -103,6 +103,7 @@ var _ = Describe("PodToDataplane(..)", func() {
 		servicesForPod  string
 		otherDataplanes string
 		otherServices   string
+		node            string
 		dataplane       string
 	}
 	DescribeTable("should convert Pod into a Dataplane YAML version",
@@ -130,7 +131,7 @@ var _ = Describe("PodToDataplane(..)", func() {
 				YAMLs := util_yaml.SplitYAML(string(bytes))
 				services, err := ParseServices(YAMLs)
 				Expect(err).ToNot(HaveOccurred())
-				reader, err := newFakeReader(services)
+				reader, err := newFakeServiceReader(services)
 				Expect(err).ToNot(HaveOccurred())
 				serviceGetter = reader
 			}
@@ -224,6 +225,84 @@ var _ = Describe("PodToDataplane(..)", func() {
 		}),
 	)
 
+	DescribeTable("should convert Pod into a Dataplane YAML version",
+		func(given testCase) {
+			// given
+			// pod
+			pod := &kube_core.Pod{}
+			bytes, err := ioutil.ReadFile(filepath.Join("testdata", "ingress", given.pod))
+			Expect(err).ToNot(HaveOccurred())
+			err = yaml.Unmarshal(bytes, pod)
+			Expect(err).ToNot(HaveOccurred())
+
+			// services for pod
+			bytes, err = ioutil.ReadFile(filepath.Join("testdata", "ingress", given.servicesForPod))
+			Expect(err).ToNot(HaveOccurred())
+			YAMLs := util_yaml.SplitYAML(string(bytes))
+			services, err := ParseServices(YAMLs)
+			Expect(err).ToNot(HaveOccurred())
+
+			// node
+			var nodeGetter kube_client.Reader
+			if given.node != "" {
+				bytes, err = ioutil.ReadFile(filepath.Join("testdata", "ingress", given.node))
+				Expect(err).ToNot(HaveOccurred())
+				nodeGetter = fakeNodeReader(bytes)
+			}
+
+			converter := PodConverter{
+				ServiceGetter: nil,
+				NodeGetter:    nodeGetter,
+				Zone:          "zone-1",
+			}
+
+			// when
+			dataplane := &mesh_k8s.Dataplane{}
+			err = converter.PodToIngress(dataplane, pod, services)
+
+			// then
+			Expect(err).ToNot(HaveOccurred())
+
+			actual, err := json.Marshal(dataplane)
+			Expect(err).ToNot(HaveOccurred())
+			expected, err := ioutil.ReadFile(filepath.Join("testdata", "ingress", given.dataplane))
+			Expect(err).ToNot(HaveOccurred())
+			Expect(actual).To(MatchYAML(expected))
+		},
+		Entry("01. Ingress with load balancer service and hostname", testCase{ // AWS use case
+			pod:            "01.pod.yaml",
+			servicesForPod: "01.services-for-pod.yaml",
+			dataplane:      "01.dataplane.yaml",
+		}),
+		Entry("02. Ingress with load balancer and ip", testCase{ // GCP use case
+			pod:            "02.pod.yaml",
+			servicesForPod: "02.services-for-pod.yaml",
+			dataplane:      "02.dataplane.yaml",
+		}),
+		Entry("03. Ingress with load balancer without public ip", testCase{
+			pod:            "03.pod.yaml",
+			servicesForPod: "03.services-for-pod.yaml",
+			dataplane:      "03.dataplane.yaml",
+		}),
+		Entry("04. Ingress with node port external IP", testCase{ // Real deployment use case
+			pod:            "04.pod.yaml",
+			servicesForPod: "04.services-for-pod.yaml",
+			dataplane:      "04.dataplane.yaml",
+			node:           "04.node.yaml",
+		}),
+		Entry("05. Ingress with node port internal IP", testCase{ // KIND / Minikube use case
+			pod:            "05.pod.yaml",
+			servicesForPod: "05.services-for-pod.yaml",
+			dataplane:      "05.dataplane.yaml",
+			node:           "05.node.yaml",
+		}),
+		Entry("06. Ingress with annotations override", testCase{
+			pod:            "06.pod.yaml",
+			servicesForPod: "06.services-for-pod.yaml",
+			dataplane:      "06.dataplane.yaml",
+		}),
+	)
+
 	Context("when Dataplane cannot be generated", func() {
 		type testCase struct {
 			pod         string
@@ -570,9 +649,9 @@ var _ = Describe("ProtocolTagFor(..)", func() {
 	)
 })
 
-type fakeReader map[string]string
+type fakeServiceReader map[string]string
 
-func newFakeReader(services []*kube_core.Service) (fakeReader, error) {
+func newFakeServiceReader(services []*kube_core.Service) (fakeServiceReader, error) {
 	servicesMap := map[string]string{}
 	for _, service := range services {
 		bytes, err := yaml.Marshal(service)
@@ -584,9 +663,9 @@ func newFakeReader(services []*kube_core.Service) (fakeReader, error) {
 	return servicesMap, nil
 }
 
-var _ kube_client.Reader = fakeReader{}
+var _ kube_client.Reader = fakeServiceReader{}
 
-func (r fakeReader) Get(ctx context.Context, key kube_client.ObjectKey, obj kube_runtime.Object) error {
+func (r fakeServiceReader) Get(ctx context.Context, key kube_client.ObjectKey, obj kube_runtime.Object) error {
 	data, ok := r[fmt.Sprintf("%s/%s", key.Namespace, key.Name)]
 	if !ok {
 		return errors.New("not found")
@@ -594,6 +673,23 @@ func (r fakeReader) Get(ctx context.Context, key kube_client.ObjectKey, obj kube
 	return yaml.Unmarshal([]byte(data), obj)
 }
 
-func (f fakeReader) List(ctx context.Context, list kube_runtime.Object, opts ...kube_client.ListOption) error {
+func (f fakeServiceReader) List(ctx context.Context, list kube_runtime.Object, opts ...kube_client.ListOption) error {
 	return errors.New("not implemented")
 }
+
+type fakeNodeReader string
+
+func (r fakeNodeReader) Get(ctx context.Context, key kube_client.ObjectKey, obj kube_runtime.Object) error {
+	return errors.New("not implemented")
+}
+
+func (f fakeNodeReader) List(ctx context.Context, list kube_runtime.Object, opts ...kube_client.ListOption) error {
+	node := kube_core.Node{}
+	err := yaml.Unmarshal([]byte(f), &node)
+	if err != nil {
+		return err
+	}
+	l := list.(*kube_core.NodeList)
+	l.Items = append(l.Items, node)
+	return nil
+}
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.dataplane.yaml
new file mode 100644
index 000000000..cdd6bbf2a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.dataplane.yaml
@@ -0,0 +1,16 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress:
+      publicAddress: kuma-ingress.com
+      publicPort: 10001
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.pod.yaml
new file mode 100644
index 000000000..3e169b57a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.pod.yaml
@@ -0,0 +1,13 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.services-for-pod.yaml
new file mode 100644
index 000000000..6fe389206
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/01.services-for-pod.yaml
@@ -0,0 +1,15 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: LoadBalancer
+  ports:
+    - port: 10001
+      targetPort: 10001
+  selector:
+    app: kuma-ingress
+status:
+  loadBalancer:
+    ingress:
+      - hostname: "kuma-ingress.com"
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.dataplane.yaml
new file mode 100644
index 000000000..ef8199ed8
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.dataplane.yaml
@@ -0,0 +1,16 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress:
+      publicAddress: 192.168.100.1
+      publicPort: 10001
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.pod.yaml
new file mode 100644
index 000000000..3e169b57a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.pod.yaml
@@ -0,0 +1,13 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.services-for-pod.yaml
new file mode 100644
index 000000000..5094495da
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/02.services-for-pod.yaml
@@ -0,0 +1,15 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: LoadBalancer
+  ports:
+    - port: 10001
+      targetPort: 10001
+  selector:
+    app: kuma-ingress
+status:
+  loadBalancer:
+    ingress:
+      - ip: 192.168.100.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.dataplane.yaml
new file mode 100644
index 000000000..91aa67cb5
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.dataplane.yaml
@@ -0,0 +1,14 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress: {}
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.pod.yaml
new file mode 100644
index 000000000..3e169b57a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.pod.yaml
@@ -0,0 +1,13 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.services-for-pod.yaml
new file mode 100644
index 000000000..92c5f762d
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/03.services-for-pod.yaml
@@ -0,0 +1,11 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: LoadBalancer
+  ports:
+    - port: 10001
+      targetPort: 10001
+  selector:
+    app: kuma-ingress
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.dataplane.yaml
new file mode 100644
index 000000000..304ef417e
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.dataplane.yaml
@@ -0,0 +1,16 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress:
+      publicAddress: 34.72.129.131
+      publicPort: 12345
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.node.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.node.yaml
new file mode 100644
index 000000000..c734059a3
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.node.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Node
+metadata:
+  name: sample-node
+status:
+  addresses:
+    - address: 10.128.15.193
+      type: InternalIP
+    - address: 34.72.129.131
+      type: ExternalIP
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.pod.yaml
new file mode 100644
index 000000000..3e169b57a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.pod.yaml
@@ -0,0 +1,13 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.services-for-pod.yaml
new file mode 100644
index 000000000..c18b60526
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/04.services-for-pod.yaml
@@ -0,0 +1,12 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: NodePort
+  ports:
+    - port: 10001
+      targetPort: 10001
+      nodePort: 12345
+  selector:
+    app: kuma-ingress
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.dataplane.yaml
new file mode 100644
index 000000000..046ed3795
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.dataplane.yaml
@@ -0,0 +1,16 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress:
+      publicAddress: 10.128.15.193
+      publicPort: 12345
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.node.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.node.yaml
new file mode 100644
index 000000000..bdb9e22d8
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.node.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Node
+metadata:
+  name: sample-node
+status:
+  addresses:
+    - address: 10.128.15.193
+      type: InternalIP
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.pod.yaml
new file mode 100644
index 000000000..3e169b57a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.pod.yaml
@@ -0,0 +1,13 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.services-for-pod.yaml
new file mode 100644
index 000000000..c18b60526
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/05.services-for-pod.yaml
@@ -0,0 +1,12 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: NodePort
+  ports:
+    - port: 10001
+      targetPort: 10001
+      nodePort: 12345
+  selector:
+    app: kuma-ingress
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.dataplane.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.dataplane.yaml
new file mode 100644
index 000000000..e2c72a7da
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.dataplane.yaml
@@ -0,0 +1,16 @@
+mesh: default
+metadata:
+  creationTimestamp: null
+spec:
+  networking:
+    address: 192.168.0.1
+    inbound:
+      - port: 10001
+        tags:
+          app: kuma-ingress
+          kuma.io/protocol: tcp
+          kuma.io/service: kuma-ingress_kuma-system_svc_10001
+          kuma.io/zone: zone-1
+    ingress:
+      publicAddress: custom-address.com
+      publicPort: 1234
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.pod.yaml
new file mode 100644
index 000000000..d90abc2d4
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.pod.yaml
@@ -0,0 +1,15 @@
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+  labels:
+    app: kuma-ingress
+  annotations:
+    kuma.io/ingress: enabled
+    kuma.io/ingress-public-address: custom-address.com
+    kuma.io/ingress-public-port: 1234
+spec:
+  containers:
+    - ports:
+        - containerPort: 10001
+status:
+  podIP: 192.168.0.1
diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.services-for-pod.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.services-for-pod.yaml
new file mode 100644
index 000000000..6fe389206
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/controllers/testdata/ingress/06.services-for-pod.yaml
@@ -0,0 +1,15 @@
+---
+metadata:
+  namespace: kuma-system
+  name: kuma-ingress
+spec:
+  type: LoadBalancer
+  ports:
+    - port: 10001
+      targetPort: 10001
+  selector:
+    app: kuma-ingress
+status:
+  loadBalancer:
+    ingress:
+      - hostname: "kuma-ingress.com"
diff --git a/pkg/plugins/runtime/k8s/webhooks/service_validator_test.go b/pkg/plugins/runtime/k8s/webhooks/service_validator_test.go
index da307ee57..87925096d 100644
--- a/pkg/plugins/runtime/k8s/webhooks/service_validator_test.go
+++ b/pkg/plugins/runtime/k8s/webhooks/service_validator_test.go
@@ -168,15 +168,15 @@ var _ = Describe("ServiceValidator", func() {
               details:
                 causes:
                 - field: metadata.annotations["8081.service.kuma.io/protocol"]
-                  message: 'value "" is not valid. Allowed values: grpc, http, http2, tcp'
+                  message: 'value "" is not valid. Allowed values: grpc, http, http2, kafka, tcp'
                   reason: FieldValueInvalid
                 - field: metadata.annotations["8082.service.kuma.io/protocol"]
-                  message: 'value "not-yet-supported-protocol" is not valid. Allowed values: grpc, http, http2, tcp'
+                  message: 'value "not-yet-supported-protocol" is not valid. Allowed values: grpc, http, http2, kafka, tcp'
                   reason: FieldValueInvalid
                 kind: Service
               message: 'metadata.annotations["8081.service.kuma.io/protocol"]: value "" is
-                not valid. Allowed values: grpc, http, http2, tcp; metadata.annotations["8082.service.kuma.io/protocol"]:
-                value "not-yet-supported-protocol" is not valid. Allowed values: grpc, http, http2, tcp'
+                not valid. Allowed values: grpc, http, http2, kafka, tcp; metadata.annotations["8082.service.kuma.io/protocol"]:
+                value "not-yet-supported-protocol" is not valid. Allowed values: grpc, http, http2, kafka, tcp'
               metadata: {}
               reason: Invalid
               status: Failure
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
index 9d1a833af..cd0e23907 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.k8s.golden.yaml
@@ -44,6 +44,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
index 3cc695316..245485b05 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.overridden.golden.yaml
@@ -51,6 +51,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
diff --git a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
index 0893e8273..281e09249 100644
--- a/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/bootstrap.universal.golden.yaml
@@ -44,6 +44,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
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 7e24bfce9..d0b06650b 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
@@ -46,6 +46,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
diff --git a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
index 1d181fe22..95b34aac8 100644
--- a/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.custom-config.golden.yaml
@@ -56,6 +56,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
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 330187f03..6bc8d5b09 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
@@ -38,6 +38,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
diff --git a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
index 8865b8b7b..442c8cb62 100644
--- a/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
+++ b/pkg/xds/bootstrap/testdata/generator.default-config.golden.yaml
@@ -55,6 +55,10 @@ statsConfig:
       tagName: name
     - regex: ^grpc.*streams_closed(_([0-9]+))
       tagName: status
+    - regex: ^kafka(\.(\S*[0-9]))\.
+      tagName: kafka_name
+    - regex: ^kafka\..*\.(.*)
+      tagName: kafka_type
     - regex: (worker_([0-9]+)\.)
       tagName: worker
     - regex: ((.+?)\.)rbac\.
diff --git a/pkg/xds/envoy/listeners/kafka_configurer_test.go b/pkg/xds/envoy/listeners/kafka_configurer_test.go
new file mode 100644
index 000000000..7aec71b5d
--- /dev/null
+++ b/pkg/xds/envoy/listeners/kafka_configurer_test.go
@@ -0,0 +1,109 @@
+package listeners_test
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/gomega"
+
+	. "github.com/kumahq/kuma/pkg/xds/envoy/listeners"
+
+	util_proto "github.com/kumahq/kuma/pkg/util/proto"
+	envoy_common "github.com/kumahq/kuma/pkg/xds/envoy"
+)
+
+var _ = Describe("TcpProxyConfigurer", func() {
+
+	type testCase struct {
+		listenerName    string
+		listenerAddress string
+		listenerPort    uint32
+		statsName       string
+		clusters        []envoy_common.ClusterSubset
+		expected        string
+	}
+
+	DescribeTable("should generate proper Envoy config",
+		func(given testCase) {
+			// when
+			listener, err := NewListenerBuilder().
+				Configure(InboundListener(given.listenerName, given.listenerAddress, given.listenerPort)).
+				Configure(FilterChain(NewFilterChainBuilder().
+					Configure(TcpProxy(given.statsName, given.clusters...)))).
+				Build()
+			// then
+			Expect(err).ToNot(HaveOccurred())
+
+			// when
+			actual, err := util_proto.ToYAML(listener)
+			Expect(err).ToNot(HaveOccurred())
+			// and
+			Expect(actual).To(MatchYAML(given.expected))
+		},
+		Entry("basic tcp_proxy with a single destination cluster", testCase{
+			listenerName:    "inbound:192.168.0.1:8080",
+			listenerAddress: "192.168.0.1",
+			listenerPort:    8080,
+			statsName:       "localhost:8080",
+			clusters: []envoy_common.ClusterSubset{
+				{ClusterName: "localhost:8080", Weight: 200},
+			},
+			expected: `
+        name: inbound:192.168.0.1:8080
+        trafficDirection: INBOUND
+        address:
+          socketAddress:
+            address: 192.168.0.1
+            portValue: 8080
+        filterChains:
+        - filters:
+          - name: envoy.tcp_proxy
+            typedConfig:
+              '@type': type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy
+              cluster: localhost:8080
+              statPrefix: localhost_8080
+`,
+		}),
+		Entry("basic tcp_proxy with weighted destination clusters", testCase{
+			listenerName:    "inbound:127.0.0.1:5432",
+			listenerAddress: "127.0.0.1",
+			listenerPort:    5432,
+			statsName:       "db",
+			clusters: []envoy_common.ClusterSubset{{
+				ClusterName: "db",
+				Weight:      10,
+				Tags:        map[string]string{"kuma.io/service": "db", "version": "v1"},
+			}, {
+				ClusterName: "db",
+				Weight:      90,
+				Tags:        map[string]string{"kuma.io/service": "db", "version": "v2"},
+			}},
+			expected: `
+            address:
+              socketAddress:
+                address: 127.0.0.1
+                portValue: 5432
+            filterChains:
+            - filters:
+              - name: envoy.tcp_proxy
+                typedConfig:
+                  '@type': type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy
+                  statPrefix: db
+                  weightedClusters:
+                    clusters:
+                    - metadataMatch:
+                        filterMetadata:
+                          envoy.lb:
+                            version: v1
+                      name: db
+                      weight: 10
+                    - metadataMatch:
+                        filterMetadata:
+                          envoy.lb:
+                            version: v2
+                      name: db
+                      weight: 90
+            name: inbound:127.0.0.1:5432
+            trafficDirection: INBOUND`,
+		}),
+	)
+})
diff --git a/pkg/xds/generator/protocol_private_test.go b/pkg/xds/generator/protocol_private_test.go
index f8213f85a..5da5ece4a 100644
--- a/pkg/xds/generator/protocol_private_test.go
+++ b/pkg/xds/generator/protocol_private_test.go
@@ -102,5 +102,10 @@ var _ = Describe("getCommonProtocol()", func() {
 			another:  mesh_core.ProtocolTCP,
 			expected: mesh_core.ProtocolTCP,
 		}),
+		Entry("`kafka` and `tcp`", testCase{
+			one:      mesh_core.ProtocolKafka,
+			another:  mesh_core.ProtocolTCP,
+			expected: mesh_core.ProtocolTCP,
+		}),
 	)
 })
diff --git a/pkg/xds/generator/protocol_test.go b/pkg/xds/generator/protocol_test.go
index 5a6b49bd4..fda1fe5d5 100644
--- a/pkg/xds/generator/protocol_test.go
+++ b/pkg/xds/generator/protocol_test.go
@@ -47,6 +47,12 @@ var _ = Describe("InferServiceProtocol()", func() {
 			},
 			expected: mesh_core.ProtocolHTTP2,
 		}),
+		Entry("one-item list: `kuma.io/protocol: kafka`", testCase{
+			endpoints: []core_xds.Endpoint{
+				{Tags: map[string]string{"kuma.io/service": "kafka-broker", "kuma.io/protocol": "kafka"}},
+			},
+			expected: mesh_core.ProtocolKafka,
+		}),
 		Entry("one-item list: `kuma.io/protocol: tcp`", testCase{
 			endpoints: []core_xds.Endpoint{
 				{Tags: map[string]string{"kuma.io/service": "backend", "kuma.io/protocol": "tcp"}},
diff --git a/pkg/xds/topology/outbound_test.go b/pkg/xds/topology/outbound_test.go
index 6990b731a..7177a13cd 100644
--- a/pkg/xds/topology/outbound_test.go
+++ b/pkg/xds/topology/outbound_test.go
@@ -270,6 +270,66 @@ var _ = Describe("TrafficRoute", func() {
 									},
 								},
 								Ingress: &mesh_proto.Dataplane_Networking_Ingress{
+									PublicAddress: "192.168.0.100",
+									PublicPort:    12345,
+									AvailableServices: []*mesh_proto.Dataplane_Networking_Ingress_AvailableService{
+										{
+											Instances: 2,
+											Mesh:      defaultMeshName,
+											Tags:      map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
+										},
+										{
+											Instances: 3,
+											Mesh:      defaultMeshName,
+											Tags:      map[string]string{mesh_proto.ServiceTag: "redis", "version": "v3"},
+										},
+									},
+								},
+							},
+						},
+					},
+					{
+						Spec: mesh_proto.Dataplane{
+							Networking: &mesh_proto.Dataplane_Networking{
+								Address: "10.20.1.3", // another instance of the same ingress will be ignored
+								Inbound: []*mesh_proto.Dataplane_Networking_Inbound{
+									{
+										Tags: map[string]string{mesh_proto.ServiceTag: "ingress", mesh_proto.ZoneTag: "zone-2"},
+										Port: 10001,
+									},
+								},
+								Ingress: &mesh_proto.Dataplane_Networking_Ingress{
+									PublicAddress: "192.168.0.100",
+									PublicPort:    12345,
+									AvailableServices: []*mesh_proto.Dataplane_Networking_Ingress_AvailableService{
+										{
+											Instances: 2,
+											Mesh:      defaultMeshName,
+											Tags:      map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
+										},
+										{
+											Instances: 3,
+											Mesh:      defaultMeshName,
+											Tags:      map[string]string{mesh_proto.ServiceTag: "redis", "version": "v3"},
+										},
+									},
+								},
+							},
+						},
+					},
+					{
+						Spec: mesh_proto.Dataplane{
+							Networking: &mesh_proto.Dataplane_Networking{
+								Address: "10.20.1.4",
+								Inbound: []*mesh_proto.Dataplane_Networking_Inbound{
+									{
+										Tags: map[string]string{mesh_proto.ServiceTag: "ingress", mesh_proto.ZoneTag: "zone-2"},
+										Port: 10001,
+									},
+								},
+								Ingress: &mesh_proto.Dataplane_Networking_Ingress{
+									PublicAddress: "192.168.0.101", // instance of the ingress with different public coordinates
+									PublicPort:    12345,
 									AvailableServices: []*mesh_proto.Dataplane_Networking_Ingress_AvailableService{
 										{
 											Instances: 2,
@@ -291,23 +351,35 @@ var _ = Describe("TrafficRoute", func() {
 				expected: core_xds.EndpointMap{
 					"redis": []core_xds.Endpoint{
 						{
-							Target: "192.168.0.1",
-							Port:   6379,
-							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v1"},
-							Weight: 1,
+							Target: "192.168.0.100",
+							Port:   12345,
+							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
+							Weight: 2,
+						},
+						{
+							Target: "192.168.0.100",
+							Port:   12345,
+							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v3"},
+							Weight: 3,
 						},
 						{
-							Target: "10.20.1.2",
-							Port:   10001,
+							Target: "192.168.0.101",
+							Port:   12345,
 							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
 							Weight: 2,
 						},
 						{
-							Target: "10.20.1.2",
-							Port:   10001,
+							Target: "192.168.0.101",
+							Port:   12345,
 							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v3"},
 							Weight: 3,
 						},
+						{
+							Target: "192.168.0.1",
+							Port:   6379,
+							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v1"},
+							Weight: 2, // local weight is bumped to 2 to factor two instances of Ingresses
+						},
 					},
 				},
 			}),
@@ -339,6 +411,8 @@ var _ = Describe("TrafficRoute", func() {
 									},
 								},
 								Ingress: &mesh_proto.Dataplane_Networking_Ingress{
+									PublicAddress: "192.168.0.100",
+									PublicPort:    12345,
 									AvailableServices: []*mesh_proto.Dataplane_Networking_Ingress_AvailableService{
 										{
 											Instances: 2,
@@ -359,18 +433,18 @@ var _ = Describe("TrafficRoute", func() {
 				mesh: defaultMeshWithMTLS,
 				expected: core_xds.EndpointMap{
 					"redis": []core_xds.Endpoint{
+						{
+							Target: "192.168.0.100",
+							Port:   12345,
+							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
+							Weight: 2,
+						},
 						{
 							Target: "192.168.0.1",
 							Port:   6379,
 							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v1"},
 							Weight: 1,
 						},
-						{
-							Target: "10.20.1.2",
-							Port:   10001,
-							Tags:   map[string]string{mesh_proto.ServiceTag: "redis", "version": "v2", mesh_proto.RegionTag: "eu"},
-							Weight: 2,
-						},
 					},
 				},
 			}),
diff --git a/test/e2e/kuma_deploy_global_remote_test.go b/test/e2e/kuma_deploy_global_remote_test.go
index f8764dff1..4f93ecb47 100644
--- a/test/e2e/kuma_deploy_global_remote_test.go
+++ b/test/e2e/kuma_deploy_global_remote_test.go
@@ -83,12 +83,6 @@ metadata:
 		// then
 		Expect(err).ToNot(HaveOccurred())
 
-		err = k8s.KubectlApplyFromStringE(c1.GetTesting(), c1.GetKubectlOptions(),
-			fmt.Sprintf(ZoneTemplateK8s,
-				remote.GetName(),
-				remote.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
 		// then
 		logs1, err := global.GetKumaCPLogs()
 		Expect(err).ToNot(HaveOccurred())
@@ -131,15 +125,13 @@ metadata:
 		}, time.Minute, DefaultTimeout).Should(BeTrue())
 
 		// then remote is online
-		found := false
+		active := true
 		for _, cluster := range clustersStatus {
-			if cluster.Address == remote.GetIngressAddress() {
-				Expect(cluster.Active).To(BeTrue())
-				found = true
-				break
+			if !cluster.Active {
+				active = false
 			}
 		}
-		Expect(found).To(BeTrue())
+		Expect(active).To(BeTrue())
 
 		// and dataplanes are synced to global
 		Eventually(func() string {
diff --git a/test/e2e/kuma_deploy_hybrid_kube_global_test.go b/test/e2e/kuma_deploy_hybrid_kube_global_test.go
index 1829cc560..03891162a 100644
--- a/test/e2e/kuma_deploy_hybrid_kube_global_test.go
+++ b/test/e2e/kuma_deploy_hybrid_kube_global_test.go
@@ -1,10 +1,8 @@
 package e2e
 
 import (
-	"fmt"
 	"strings"
 
-	"github.com/gruntwork-io/terratest/modules/k8s"
 	"github.com/gruntwork-io/terratest/modules/retry"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
@@ -64,13 +62,6 @@ var _ = Describe("Test Kubernetes/Universal deployment when Global is on K8S", f
 		Expect(err).ToNot(HaveOccurred())
 		err = remoteCluster.VerifyKuma()
 		Expect(err).ToNot(HaveOccurred())
-
-		// connect Remote with Global
-		err = k8s.KubectlApplyFromStringE(globalCluster.GetTesting(), globalCluster.GetKubectlOptions(),
-			fmt.Sprintf(ZoneTemplateK8s,
-				Kuma3,
-				remoteCluster.GetKuma().GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
 	})
 
 	AfterEach(func() {
diff --git a/test/e2e/kuma_deploy_hybrid_test.go b/test/e2e/kuma_deploy_hybrid_test.go
index 3e486819a..b58109693 100644
--- a/test/e2e/kuma_deploy_hybrid_test.go
+++ b/test/e2e/kuma_deploy_hybrid_test.go
@@ -161,35 +161,6 @@ metadata:
 		err = remote_4.VerifyKuma()
 		Expect(err).ToNot(HaveOccurred())
 
-		remote_1CP := remote_1.GetKuma()
-		remote_2CP := remote_2.GetKuma()
-		remote_3CP := remote_3.GetKuma()
-		remote_4CP := remote_4.GetKuma()
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal,
-				remote_1CP.GetName(),
-				remote_1CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal,
-				remote_2CP.GetName(),
-				remote_2CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal,
-				Kuma3,
-				remote_3CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal,
-				Kuma4,
-				remote_4CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
 		err = YamlUniversal(meshDefaulMtlsOn)(global)
 		Expect(err).ToNot(HaveOccurred())
 
diff --git a/test/e2e/kuma_deploy_universal_test.go b/test/e2e/kuma_deploy_universal_test.go
index ecaa5e1bf..3ab811204 100644
--- a/test/e2e/kuma_deploy_universal_test.go
+++ b/test/e2e/kuma_deploy_universal_test.go
@@ -101,17 +101,6 @@ destinations:
 		err = remote_2.VerifyKuma()
 		Expect(err).ToNot(HaveOccurred())
 
-		remote_1CP := remote_1.GetKuma()
-		remote_2CP := remote_2.GetKuma()
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal, Kuma2, remote_1CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
-		err = global.GetKumactlOptions().KumactlApplyFromString(
-			fmt.Sprintf(ZoneTemplateUniversal, Kuma3, remote_2CP.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
 		err = YamlUniversal(fmt.Sprintf(meshDefaulMtlsOn, "false"))(global)
 		Expect(err).ToNot(HaveOccurred())
 
diff --git a/test/e2e/kuma_helm_deploy_global_remote_test.go b/test/e2e/kuma_helm_deploy_global_remote_test.go
index cd0cb1d13..d561d3fc4 100644
--- a/test/e2e/kuma_helm_deploy_global_remote_test.go
+++ b/test/e2e/kuma_helm_deploy_global_remote_test.go
@@ -98,12 +98,6 @@ metadata:
 		// then
 		Expect(err).ToNot(HaveOccurred())
 
-		err = k8s.KubectlApplyFromStringE(c1.GetTesting(), c1.GetKubectlOptions(),
-			fmt.Sprintf(ZoneTemplateK8s,
-				remote.GetName(),
-				remote.GetIngressAddress()))
-		Expect(err).ToNot(HaveOccurred())
-
 		// then
 		logs1, err := global.GetKumaCPLogs()
 		Expect(err).ToNot(HaveOccurred())
@@ -144,15 +138,13 @@ metadata:
 		}, time.Minute, DefaultTimeout).Should(BeTrue())
 
 		// then
-		found := false
+		active := true
 		for _, cluster := range clustersStatus {
-			if cluster.Address == remote.GetIngressAddress() {
-				Expect(cluster.Active).To(BeTrue())
-				found = true
-				break
+			if !cluster.Active {
+				active = false
 			}
 		}
-		Expect(found).To(BeTrue())
+		Expect(active).To(BeTrue())
 
 		// and dataplanes are synced to global
 		Eventually(func() string {
diff --git a/test/framework/constants.go b/test/framework/constants.go
index 92f1e4412..f396be96f 100644
--- a/test/framework/constants.go
+++ b/test/framework/constants.go
@@ -20,24 +20,6 @@ const (
 	KumaUniversalImage = "kuma-universal"
 
 	kdsPort = 30685
-
-	ZoneTemplateK8s = `
-apiVersion: kuma.io/v1alpha1
-kind: Zone
-mesh: default
-metadata:
-  name: %s
-spec:
-  ingress:
-    address: %s
-`
-	ZoneTemplateUniversal = `
-type: Zone
-mesh: default
-name: %s
-ingress:
-  address: %s
-`
 )
 
 const (
diff --git a/test/framework/interface.go b/test/framework/interface.go
index 1033ca4dc..a90b1aa81 100644
--- a/test/framework/interface.go
+++ b/test/framework/interface.go
@@ -156,7 +156,6 @@ type ControlPlane interface {
 	GetName() string
 	GetKumaCPLogs() (string, error)
 	GetKDSServerAddress() string
-	GetIngressAddress() string
 	GetGlobaStatusAPI() string
 	GenerateDpToken(appname string) (string, error)
 }
diff --git a/test/framework/k8s_controlplane.go b/test/framework/k8s_controlplane.go
index 408cdd8a1..a1b50594a 100644
--- a/test/framework/k8s_controlplane.go
+++ b/test/framework/k8s_controlplane.go
@@ -1,7 +1,6 @@
 package framework
 
 import (
-	"context"
 	"crypto/tls"
 	"fmt"
 	"net/http"
@@ -205,32 +204,6 @@ func (c *K8sControlPlane) GetKDSServerAddress() string {
 	return "grpcs://" + pod.Status.HostIP + ":" + strconv.FormatUint(uint64(kdsPort), 10)
 }
 
-func (c *K8sControlPlane) GetIngressAddress() string {
-	ctx := context.Background()
-	cs, err := k8s.GetKubernetesClientFromOptionsE(c.t, c.GetKubectlOptions())
-	if err != nil {
-		return "invalid"
-	}
-	ingressSvc, err := cs.CoreV1().Services(KumaNamespace).Get(ctx, "kuma-ingress", metav1.GetOptions{})
-	if err != nil {
-		return "invalid"
-	}
-	port := ingressSvc.Spec.Ports[0].NodePort
-
-	nodes, err := cs.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
-	if err != nil {
-		return "invalid"
-	}
-	// assume that we have single node cluster
-	for _, addr := range nodes.Items[0].Status.Addresses {
-		if addr.Type == v1.NodeInternalIP {
-			return addr.Address + ":" + strconv.Itoa(int(port))
-		}
-	}
-
-	return "invalid"
-}
-
 func (c *K8sControlPlane) GetGlobaStatusAPI() string {
 	return "http://localhost:" + strconv.FormatUint(uint64(c.portFwd.localAPIPort), 10) + "/status/zones"
 }
diff --git a/test/framework/setup.go b/test/framework/setup.go
index 526c55e4b..a4f3999ff 100644
--- a/test/framework/setup.go
+++ b/test/framework/setup.go
@@ -153,7 +153,8 @@ func IngressUniversal(token string) InstallFunc {
 		}
 		uniCluster.apps[AppIngress] = app
 
-		dpyaml := fmt.Sprintf(IngressDataplane, kdsPort)
+		publicAddress := uniCluster.apps[AppIngress].ip
+		dpyaml := fmt.Sprintf(IngressDataplane, publicAddress, kdsPort, kdsPort)
 		return uniCluster.CreateDP(app, "ingress", app.ip, dpyaml, token)
 	}
 }
diff --git a/test/framework/universal_app.go b/test/framework/universal_app.go
index 5c08bcf12..a86118885 100644
--- a/test/framework/universal_app.go
+++ b/test/framework/universal_app.go
@@ -33,9 +33,11 @@ mesh: default
 name: dp-ingress
 networking:
   address: {{ address }}
-  ingress: {}
+  ingress:
+    publicAddress: %s
+    publicPort: %d
   inbound:
-  - port: %d	
+  - port: %d
     tags:
       kuma.io/service: ingress
 `
diff --git a/test/framework/universal_controlplane.go b/test/framework/universal_controlplane.go
index 07936bfa5..efbe86c76 100644
--- a/test/framework/universal_controlplane.go
+++ b/test/framework/universal_controlplane.go
@@ -2,7 +2,6 @@ package framework
 
 import (
 	"fmt"
-	"strconv"
 
 	"github.com/gruntwork-io/terratest/modules/retry"
 	"github.com/pkg/errors"
@@ -49,10 +48,6 @@ func (c *UniversalControlPlane) GetKDSServerAddress() string {
 	return "grpcs://" + c.cluster.apps[AppModeCP].ip + ":5685"
 }
 
-func (c *UniversalControlPlane) GetIngressAddress() string {
-	return c.cluster.apps[AppIngress].ip + ":" + strconv.FormatUint(uint64(kdsPort), 10)
-}
-
 func (c *UniversalControlPlane) GetGlobaStatusAPI() string {
 	panic("not implemented")
 }