Repository: kumahq/kuma
Pull request #1122 (2020-11-02 10:52:52)

feat(kuma-cp) new multicluster flow
### Summary

This PR introduces a new multicluster flow.

#### Before
When user want to connect Global with Remote they had to
* Deploy Global
* Extract public IP of global and use it in Deploy Remote command
* Wait for Remote to be deployed
* Extract Remote Ingress address
* Apply zone with Ingress address
* 🎉

#### After
When user want to connect Global with Remote they have to
* Deploy Global
* Extract public IP of global and use it in Deploy Remote command
* 🎉

### Full changelog

* Introduced publicAddress and publicPort to Ingress data plane that indicates the address and port that is accessible to other clusters
* Removed flattening of Ingresses, therefore you don't have to have LB for them. Every ingress can have separate public IP
* On Kubernetes, automatically resolve publicAddress and publicPort. It works with both LoadBalancer services and NodePort.
  When LoadBalancer Service waits for its address, we still have an Ingress synced but without public coordinates, which means it won't be used.
  When LoadBalancer Service receives IP, it's automatically updated by Kubernetes controlled, synced to Global, and synced to other Remotes.
  You can override the address and port with annotations if you wish.
* Zone is now automatically created when Remote initiate a stream to Global (which is symmetric with DP that connects to CP creating Dataplane definition)
* Remove Ingress from zones tab in the GUI https://github.com/kumahq/kuma-gui/pull/81

### Documentation

- [ ] In progress



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_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/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/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/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_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/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/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_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/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_validator_test.go b/pkg/core/resources/apis/mesh/dataplane_validator_test.go
index 89255dbda..02b1e4135 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
@@ -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/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/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")
 }