Repository: kumahq/kuma
Pull request #2352 (2021-07-12 11:16:17)

chore(kumactl) improve flags description, add extra validation
### Summary

Some minor chores for `kumactl install transparent-proxy` command.

### Full changelog

* fix typo in the class name
* delete flag `--modify-iptables`, correct me if I'm wrong but what's the point running `kumactl install transparent-proxy` with `--modify-iptables=false`
* add validation to avoid `--redirect-dns` and `--redirect-all-dns-traffic` passed at the same time
* improve descriptions for the flags

### Issues resolved

Fix #XXX

### Documentation

- [ ] Link to the website [documentation PR](https://github.com/kumahq/kuma-website/pull/XXX)

### Testing

- [X] Unit tests
- [ ] E2E tests
- [ ] Manual testing on Universal
- [ ] Manual testing on Kubernetes 

### Backwards compatibility

- [ ] Add `backport-to-stable` label if the code is backwards compatible. Otherwise, list breaking changes.



Patch:
diff --git a/api/Makefile b/api/Makefile
index 2ebe6814e..6bee61938 100644
--- a/api/Makefile
+++ b/api/Makefile
@@ -22,9 +22,9 @@ endef
 PROTOC_VERSION := 3.14.0
 PROTOC_PGV_VERSION := v0.4.1
 GOLANG_PROTOBUF_VERSION := v1.5.2
-DATAPLANE_API_LATEST_VERSION := master
+DATAPLANE_API_LATEST_VERSION := main
 DATAPLANE_API_ACTUAL_VERSION := $(shell $(call go_mod_latest_version,github.com/envoyproxy,data-plane-api))
-UDPA_LATEST_VERSION := master
+UDPA_LATEST_VERSION := main
 UDPA_ACTUAL_VERSION := $(shell $(call go_mod_latest_version,github.com/cncf,udpa))
 GOOGLEAPIS_LATEST_VERSION := master
 GOOGLEAPIS_ACTUAL_VERSION := $(shell $(call go_mod_latest_version,github.com/googleapis,googleapis))
@@ -42,33 +42,34 @@ protoc_search_go_packages := \
 protoc_search_go_paths := $(foreach go_package,$(protoc_search_go_packages),--proto_path=$(GOPATH_DIR)/pkg/mod/$(go_package))
 
 go_import_mapping_entries := \
-	google/protobuf/any.proto=google.golang.org/protobuf/types/known/anypb \
-	google/protobuf/duration.proto=google.golang.org/protobuf/types/known/durationpb \
-	google/protobuf/struct.proto=google.golang.org/protobuf/types/known/structpb \
-	google/protobuf/timestamp.proto=google.golang.org/protobuf/types/known/timestamppb \
-	google/protobuf/wrappers.proto=google.golang.org/protobuf/types/known/wrapperspb \
-	envoy/api/v2/discovery.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2 \
-	envoy/service/discovery/v3/discovery.proto=github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3 \
-	udpa/annotations/migrate.proto=github.com/cncf/udpa/go/udpa/annotations \
-	udpa/annotations/status.proto=github.com/cncf/udpa/go/udpa/annotations \
-	udpa/annotations/versioning.proto=github.com/cncf/udpa/go/udpa/annotations \
-	envoy/api/v2/core/socket_option.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
+	envoy/annotations/deprecation.proto=github.com/envoyproxy/go-control-plane/envoy/annotations \
 	envoy/api/v2/core/address.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
 	envoy/api/v2/core/backoff.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
-	envoy/api/v2/core/http_uri.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
 	envoy/api/v2/core/base.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
 	envoy/api/v2/core/http_uri.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
-	envoy/type/percent.proto=github.com/envoyproxy/go-control-plane/envoy/type \
-	envoy/type/semantic_version.proto=github.com/envoyproxy/go-control-plane/envoy/type \
-	envoy/type/http_status.proto=github.com/envoyproxy/go-control-plane/envoy/type \
-	envoy/config/core/v3/socket_option.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
+	envoy/api/v2/core/http_uri.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
+	envoy/api/v2/core/socket_option.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2/core \
+	envoy/api/v2/discovery.proto=github.com/envoyproxy/go-control-plane/envoy/api/v2 \
 	envoy/config/core/v3/address.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
 	envoy/config/core/v3/backoff.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
+	envoy/config/core/v3/base.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
 	envoy/config/core/v3/http_uri.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
+	envoy/config/core/v3/socket_option.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3 \
+	envoy/service/discovery/v3/discovery.proto=github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3 \
+	envoy/type/http_status.proto=github.com/envoyproxy/go-control-plane/envoy/type \
+	envoy/type/percent.proto=github.com/envoyproxy/go-control-plane/envoy/type \
+	envoy/type/semantic_version.proto=github.com/envoyproxy/go-control-plane/envoy/type \
 	envoy/type/v3/percent.proto=github.com/envoyproxy/go-control-plane/envoy/type/v3 \
 	envoy/type/v3/semantic_version.proto=github.com/envoyproxy/go-control-plane/envoy/type/v3 \
-	envoy/config/core/v3/base.proto=github.com/envoyproxy/go-control-plane/envoy/config/core/v3
-
+	google/protobuf/any.proto=google.golang.org/protobuf/types/known/anypb \
+	google/protobuf/duration.proto=google.golang.org/protobuf/types/known/durationpb \
+	google/protobuf/struct.proto=google.golang.org/protobuf/types/known/structpb \
+	google/protobuf/timestamp.proto=google.golang.org/protobuf/types/known/timestamppb \
+	google/protobuf/wrappers.proto=google.golang.org/protobuf/types/known/wrapperspb \
+	udpa/annotations/migrate.proto=github.com/cncf/udpa/go/udpa/annotations \
+	udpa/annotations/status.proto=github.com/cncf/udpa/go/udpa/annotations \
+	udpa/annotations/versioning.proto=github.com/cncf/udpa/go/udpa/annotations \
+	xds/core/v3/context_params.proto=github.com/cncf/udpa/go/xds/core/v3
 
 # see https://makefiletutorial.com/
 comma := ,
diff --git a/api/mesh/v1alpha1/dataplane.pb.go b/api/mesh/v1alpha1/dataplane.pb.go
index f503a1ad6..7a9ecce8a 100644
--- a/api/mesh/v1alpha1/dataplane.pb.go
+++ b/api/mesh/v1alpha1/dataplane.pb.go
@@ -968,7 +968,7 @@ var file_mesh_v1alpha1_dataplane_proto_rawDesc = []byte{
 	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70,
 	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76,
-	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe7, 0x16,
+	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf3, 0x16,
 	0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x12, 0x48, 0x0a, 0x0a, 0x6e,
 	0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
 	0x28, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
@@ -1148,13 +1148,14 @@ var file_mesh_v1alpha1_dataplane_proto_rawDesc = []byte{
 	0x50, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f,
 	0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x62, 0x6f,
 	0x75, 0x6e, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x3a, 0x2a, 0xaa, 0x8c, 0x89,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x3a, 0x36, 0xaa, 0x8c, 0x89,
 	0xa6, 0x01, 0x13, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x52, 0x65,
 	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x0b, 0x12, 0x09, 0x44, 0x61,
-	0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
-	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x68, 0x71, 0x2f, 0x6b, 0x75, 0x6d,
-	0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
-	0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x06, 0x22, 0x04, 0x6d,
+	0x65, 0x73, 0x68, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x68, 0x71, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70,
+	0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62,
+	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/api/mesh/v1alpha1/dataplane.proto b/api/mesh/v1alpha1/dataplane.proto
index ec1821592..a22fe0f4a 100644
--- a/api/mesh/v1alpha1/dataplane.proto
+++ b/api/mesh/v1alpha1/dataplane.proto
@@ -15,6 +15,7 @@ message Dataplane {
 
   option (kuma.mesh.resource).name = "DataplaneResource";
   option (kuma.mesh.resource).type = "Dataplane";
+  option (kuma.mesh.resource).package = "mesh";
 
   // Networking describes inbound and outbound interfaces of a dataplane.
   message Networking {
diff --git a/api/mesh/v1alpha1/health_check.pb.go b/api/mesh/v1alpha1/health_check.pb.go
index 66918cd9e..d6f653af1 100644
--- a/api/mesh/v1alpha1/health_check.pb.go
+++ b/api/mesh/v1alpha1/health_check.pb.go
@@ -8,6 +8,7 @@ package v1alpha1
 
 import (
 	_ "github.com/envoyproxy/protoc-gen-validate/validate"
+	_ "github.com/kumahq/kuma/api/mesh"
 	_ "github.com/kumahq/protoc-gen-kumadoc/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
@@ -547,126 +548,131 @@ var file_mesh_v1alpha1_health_check_proto_rawDesc = []byte{
 	0x0a, 0x20, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f,
 	0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x12, 0x12, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31,
-	0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x1c, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61,
-	0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76,
-	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x63,
-	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf0, 0x0d, 0x0a, 0x0b,
-	0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x40, 0x0a, 0x07, 0x73,
-	0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b,
-	0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
-	0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92,
-	0x01, 0x02, 0x08, 0x01, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x4a, 0x0a,
-	0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e,
-	0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
-	0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0c, 0x64, 0x65, 0x73,
-	0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a, 0x04, 0x63, 0x6f, 0x6e,
-	0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d,
-	0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61,
-	0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x04, 0x63,
-	0x6f, 0x6e, 0x66, 0x1a, 0x98, 0x0c, 0x0a, 0x04, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x41, 0x0a, 0x08,
-	0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0xaa, 0x01,
-	0x04, 0x08, 0x01, 0x2a, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12,
-	0x3f, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0xfa, 0x42, 0x07,
-	0xaa, 0x01, 0x04, 0x08, 0x01, 0x2a, 0x00, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
-	0x12, 0x38, 0x0a, 0x13, 0x75, 0x6e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x74, 0x68,
-	0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa,
-	0x42, 0x04, 0x2a, 0x02, 0x20, 0x00, 0x52, 0x12, 0x75, 0x6e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
-	0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x34, 0x0a, 0x11, 0x68, 0x65,
-	0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18,
-	0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x20, 0x00, 0x52, 0x10,
-	0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64,
-	0x12, 0x40, 0x0a, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6a, 0x69, 0x74, 0x74,
-	0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
-	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4a, 0x69, 0x74, 0x74,
-	0x65, 0x72, 0x12, 0x42, 0x0a, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6a,
-	0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
-	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
-	0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x17, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
-	0x61, 0x6c, 0x5f, 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
-	0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
-	0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x53,
-	0x0a, 0x17, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x5f,
-	0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x68, 0x65,
-	0x61, 0x6c, 0x74, 0x68, 0x79, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68,
-	0x6f, 0x6c, 0x64, 0x12, 0x4d, 0x0a, 0x15, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x74, 0x72, 0x61, 0x66,
-	0x66, 0x69, 0x63, 0x5f, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x6e, 0x69, 0x63, 0x18, 0x0b, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12,
-	0x66, 0x61, 0x69, 0x6c, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x4f, 0x6e, 0x50, 0x61, 0x6e,
-	0x69, 0x63, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x5f,
-	0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e,
-	0x74, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x62, 0x0a, 0x20, 0x61, 0x6c, 0x77, 0x61,
-	0x79, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x63, 0x68,
-	0x65, 0x63, 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1c,
-	0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x4c, 0x6f, 0x67, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43,
-	0x68, 0x65, 0x63, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x13,
-	0x6e, 0x6f, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72,
-	0x76, 0x61, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
-	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6e, 0x6f, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x49,
-	0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x03, 0x74, 0x63, 0x70, 0x18, 0x05,
-	0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68,
-	0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
-	0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x54, 0x63, 0x70, 0x52, 0x03,
-	0x74, 0x63, 0x70, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31,
-	0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65,
-	0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x52, 0x04, 0x68, 0x74,
-	0x74, 0x70, 0x12, 0x45, 0x0a, 0x10, 0x72, 0x65, 0x75, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e,
-	0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
-	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42,
-	0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x72, 0x65, 0x75, 0x73, 0x65, 0x43,
-	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6d, 0x0a, 0x03, 0x54, 0x63, 0x70,
-	0x12, 0x2f, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x73, 0x65, 0x6e,
-	0x64, 0x12, 0x35, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
-	0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x1a, 0xb3, 0x03, 0x0a, 0x04, 0x48, 0x74, 0x74,
-	0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x70, 0x0a, 0x16, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x18,
-	0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73,
-	0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74,
-	0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x48, 0x74, 0x74, 0x70,
-	0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69,
-	0x6f, 0x6e, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65,
-	0x72, 0x73, 0x54, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x65, 0x78, 0x70, 0x65, 0x63,
-	0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65,
-	0x42, 0x0a, 0xfa, 0x42, 0x07, 0x2a, 0x05, 0x10, 0xd8, 0x04, 0x28, 0x64, 0x52, 0x10, 0x65, 0x78,
-	0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x1a, 0x35,
-	0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a,
-	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
-	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
-	0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x96, 0x01, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
-	0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x06, 0x68,
-	0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6b, 0x75,
+	0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x12, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x6f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x6d, 0x65, 0x73, 0x68,
+	0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
+	0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65,
+	0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
+	0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x1a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
+	0xac, 0x0e, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12,
+	0x40, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x1c, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61,
+	0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x08,
+	0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d,
+	0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x6c,
+	0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52,
+	0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a,
+	0x04, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x75,
 	0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
 	0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e,
-	0x66, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c,
-	0x75, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x06, 0x61, 0x70,
-	0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
-	0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f,
-	0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x42, 0x4d,
+	0x66, 0x52, 0x04, 0x63, 0x6f, 0x6e, 0x66, 0x1a, 0x98, 0x0c, 0x0a, 0x04, 0x43, 0x6f, 0x6e, 0x66,
+	0x12, 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0xfa,
+	0x42, 0x07, 0xaa, 0x01, 0x04, 0x08, 0x01, 0x2a, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72,
+	0x76, 0x61, 0x6c, 0x12, 0x3f, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42,
+	0x0a, 0xfa, 0x42, 0x07, 0xaa, 0x01, 0x04, 0x08, 0x01, 0x2a, 0x00, 0x52, 0x07, 0x74, 0x69, 0x6d,
+	0x65, 0x6f, 0x75, 0x74, 0x12, 0x38, 0x0a, 0x13, 0x75, 0x6e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
+	0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x20, 0x00, 0x52, 0x12, 0x75, 0x6e, 0x68, 0x65,
+	0x61, 0x6c, 0x74, 0x68, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x34,
+	0x0a, 0x11, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68,
+	0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02,
+	0x20, 0x00, 0x52, 0x10, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73,
+	0x68, 0x6f, 0x6c, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f,
+	0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
+	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c,
+	0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
+	0x61, 0x6c, 0x5f, 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+	0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65,
+	0x72, 0x76, 0x61, 0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x17, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65,
+	0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x76, 0x61, 0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x50, 0x65, 0x72, 0x63, 0x65,
+	0x6e, 0x74, 0x12, 0x53, 0x0a, 0x17, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x70, 0x61,
+	0x6e, 0x69, 0x63, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x0a, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
+	0x52, 0x15, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x54, 0x68,
+	0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x4d, 0x0a, 0x15, 0x66, 0x61, 0x69, 0x6c, 0x5f,
+	0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x6e, 0x69, 0x63,
+	0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c,
+	0x75, 0x65, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x4f,
+	0x6e, 0x50, 0x61, 0x6e, 0x69, 0x63, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f,
+	0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x65, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x62, 0x0a, 0x20,
+	0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74,
+	0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73,
+	0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c,
+	0x75, 0x65, 0x52, 0x1c, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x4c, 0x6f, 0x67, 0x48, 0x65, 0x61,
+	0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73,
+	0x12, 0x49, 0x0a, 0x13, 0x6e, 0x6f, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69,
+	0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6e, 0x6f, 0x54, 0x72, 0x61, 0x66,
+	0x66, 0x69, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x03, 0x74,
+	0x63, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e,
+	0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65,
+	0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x54,
+	0x63, 0x70, 0x52, 0x03, 0x74, 0x63, 0x70, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73,
+	0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74,
+	0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x48, 0x74, 0x74, 0x70,
+	0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x45, 0x0a, 0x10, 0x72, 0x65, 0x75, 0x73, 0x65, 0x5f,
+	0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+	0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x72, 0x65,
+	0x75, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6d, 0x0a,
+	0x03, 0x54, 0x63, 0x70, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
+	0x04, 0x73, 0x65, 0x6e, 0x64, 0x12, 0x35, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
+	0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x1a, 0xb3, 0x03, 0x0a,
+	0x04, 0x48, 0x74, 0x74, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x70, 0x0a, 0x16, 0x72, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5f, 0x74, 0x6f, 0x5f,
+	0x61, 0x64, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x6b, 0x75, 0x6d, 0x61,
+	0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48,
+	0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e,
+	0x48, 0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65,
+	0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48,
+	0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x65,
+	0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56,
+	0x61, 0x6c, 0x75, 0x65, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x2a, 0x05, 0x10, 0xd8, 0x04, 0x28, 0x64,
+	0x52, 0x10, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x65, 0x73, 0x1a, 0x35, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+	0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x96, 0x01, 0x0a, 0x11, 0x48, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+	0x4d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x35, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
+	0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b,
+	0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65,
+	0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32,
+	0x0a, 0x06, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x61, 0x70, 0x70, 0x65,
+	0x6e, 0x64, 0x3a, 0x3a, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x15, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c,
+	0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xaa,
+	0x8c, 0x89, 0xa6, 0x01, 0x0d, 0x12, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65,
+	0x63, 0x6b, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x06, 0x22, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x42, 0x4d,
 	0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x75, 0x6d,
 	0x61, 0x68, 0x71, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73,
 	0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x8a, 0xb5, 0x18, 0x1f, 0x50, 0x01,
diff --git a/api/mesh/v1alpha1/health_check.proto b/api/mesh/v1alpha1/health_check.proto
index 5d867e956..9ba09737e 100644
--- a/api/mesh/v1alpha1/health_check.proto
+++ b/api/mesh/v1alpha1/health_check.proto
@@ -4,8 +4,8 @@ package kuma.mesh.v1alpha1;
 
 option go_package = "github.com/kumahq/kuma/api/mesh/v1alpha1";
 
+import "mesh/options.proto";
 import "mesh/v1alpha1/selector.proto";
-
 import "google/protobuf/duration.proto";
 import "google/protobuf/wrappers.proto";
 import "validate/validate.proto";
@@ -19,6 +19,11 @@ option (doc.config) = {
 
 // HealthCheck defines configuration for health checking.
 message HealthCheck {
+
+  option (kuma.mesh.resource).name = "HealthCheckResource";
+  option (kuma.mesh.resource).type = "HealthCheck";
+  option (kuma.mesh.resource).package = "mesh";
+
   // List of selectors to match dataplanes that should be configured to do
   // health checks.
   repeated Selector sources = 1 [ (validate.rules).repeated .min_items = 1 ];
diff --git a/api/mesh/v1alpha1/zone_ingress_insight.pb.go b/api/mesh/v1alpha1/zone_ingress_insight.pb.go
index b47f4aa2d..7f036c8f2 100644
--- a/api/mesh/v1alpha1/zone_ingress_insight.pb.go
+++ b/api/mesh/v1alpha1/zone_ingress_insight.pb.go
@@ -7,6 +7,7 @@
 package v1alpha1
 
 import (
+	_ "github.com/kumahq/kuma/api/mesh"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -75,19 +76,26 @@ var file_mesh_v1alpha1_zone_ingress_insight_proto_rawDesc = []byte{
 	0x0a, 0x28, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f,
 	0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x6e, 0x73,
 	0x69, 0x67, 0x68, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x6b, 0x75, 0x6d, 0x61,
-	0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x25,
-	0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x64, 0x61,
-	0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x65, 0x0a, 0x12, 0x5a, 0x6f, 0x6e, 0x65, 0x49, 0x6e, 0x67,
-	0x72, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x12, 0x4f, 0x0a, 0x0d, 0x73,
-	0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76,
-	0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72,
-	0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73,
-	0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x2a, 0x5a, 0x28,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x68,
-	0x71, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f,
-	0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x12,
+	0x6d, 0x65, 0x73, 0x68, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x1a, 0x25, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
+	0x31, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x69,
+	0x67, 0x68, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbf, 0x01, 0x0a, 0x12, 0x5a, 0x6f,
+	0x6e, 0x65, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74,
+	0x12, 0x4f, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x2e, 0x6d,
+	0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x69, 0x73,
+	0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x3a, 0x58, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x1c, 0x0a, 0x1a, 0x5a, 0x6f, 0x6e, 0x65, 0x49,
+	0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x14, 0x12, 0x12, 0x5a, 0x6f, 0x6e,
+	0x65, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0xaa,
+	0x8c, 0x89, 0xa6, 0x01, 0x06, 0x22, 0x04, 0x6d, 0x65, 0x73, 0x68, 0xaa, 0x8c, 0x89, 0xa6, 0x01,
+	0x02, 0x18, 0x01, 0xaa, 0x8c, 0x89, 0xa6, 0x01, 0x02, 0x28, 0x01, 0x42, 0x2a, 0x5a, 0x28, 0x67,
+	0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x68, 0x71,
+	0x2f, 0x6b, 0x75, 0x6d, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76,
+	0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/api/mesh/v1alpha1/zone_ingress_insight.proto b/api/mesh/v1alpha1/zone_ingress_insight.proto
index fbfedbfcb..4fcbd3b02 100644
--- a/api/mesh/v1alpha1/zone_ingress_insight.proto
+++ b/api/mesh/v1alpha1/zone_ingress_insight.proto
@@ -4,11 +4,18 @@ package kuma.mesh.v1alpha1;
 
 option go_package = "github.com/kumahq/kuma/api/mesh/v1alpha1";
 
+import "mesh/options.proto";
 import "mesh/v1alpha1/dataplane_insight.proto";
 
 // ZoneIngressInsight defines the observed state of a Zone Ingress.
 message ZoneIngressInsight {
 
+  option (kuma.mesh.resource).name = "ZoneIngressInsightResource";
+  option (kuma.mesh.resource).type = "ZoneIngressInsight";
+  option (kuma.mesh.resource).package = "mesh";
+  option (kuma.mesh.resource).global = true;
+  option (kuma.mesh.resource).skip_validation = true;
+
   // List of ADS subscriptions created by a given Zone Kuma CP.
   repeated DiscoverySubscription subscriptions = 1;
 }
diff --git a/app/kumactl/cmd/install/install_transparent_proxy.go b/app/kumactl/cmd/install/install_transparent_proxy.go
index f38e0cb0d..0d3ab3907 100644
--- a/app/kumactl/cmd/install/install_transparent_proxy.go
+++ b/app/kumactl/cmd/install/install_transparent_proxy.go
@@ -19,10 +19,9 @@ import (
 	"github.com/kumahq/kuma/pkg/transparentproxy/config"
 )
 
-type transparenProxyArgs struct {
+type transparentProxyArgs struct {
 	DryRun                 bool
 	Verbose                bool
-	ModifyIptables         bool
 	RedirectPortOutBound   string
 	RedirectInbound        bool
 	RedirectPortInBound    string
@@ -43,10 +42,9 @@ type transparenProxyArgs struct {
 var defaultCpIP = net.IPv4(0, 0, 0, 0)
 
 func newInstallTransparentProxy() *cobra.Command {
-	args := transparenProxyArgs{
+	args := transparentProxyArgs{
 		DryRun:                 false,
 		Verbose:                false,
-		ModifyIptables:         true,
 		RedirectPortOutBound:   "15001",
 		RedirectInbound:        true,
 		RedirectPortInBound:    "15006",
@@ -123,10 +121,14 @@ runuser -u kuma-dp -- \
 				return errors.Errorf("transparent proxy will work only on Linux OSes")
 			}
 
-			if args.ModifyIptables && args.User == "" && args.UID == "" {
+			if args.User == "" && args.UID == "" {
 				return errors.Errorf("--kuma-dp-user or --kuma-dp-uid should be supplied")
 			}
 
+			if args.RedirectAllDNSTraffic && args.RedirectDNS {
+				return errors.Errorf("one of --redirect-dns or --redirect-all-dns-traffic should be specified")
+			}
+
 			if args.RedirectAllDNSTraffic {
 				args.RedirectDNS = true
 			}
@@ -139,10 +141,8 @@ runuser -u kuma-dp -- \
 				return errors.Errorf("please supply a valid --kuma-cp-ip")
 			}
 
-			if args.ModifyIptables {
-				if err := modifyIpTables(cmd, &args); err != nil {
-					return err
-				}
+			if err := modifyIpTables(cmd, &args); err != nil {
+				return err
 			}
 
 			if !args.SkipResolvConf {
@@ -158,7 +158,6 @@ runuser -u kuma-dp -- \
 
 	cmd.Flags().BoolVar(&args.DryRun, "dry-run", args.DryRun, "dry run")
 	cmd.Flags().BoolVar(&args.Verbose, "verbose", args.Verbose, "verbose")
-	cmd.Flags().BoolVar(&args.ModifyIptables, "modify-iptables", args.ModifyIptables, "modify the host iptables to redirect the traffic to Envoy")
 	cmd.Flags().StringVar(&args.RedirectPortOutBound, "redirect-outbound-port", args.RedirectPortOutBound, "outbound port redirected to Envoy, as specified in dataplane's `networking.transparentProxying.redirectPortOutbound`")
 	cmd.Flags().BoolVar(&args.RedirectInbound, "redirect-inbound", args.RedirectInbound, "redirect the inbound traffic to the Envoy. Should be disabled for Gateway data plane proxies.")
 	cmd.Flags().StringVar(&args.RedirectPortInBound, "redirect-inbound-port", args.RedirectPortInBound, "inbound port redirected to Envoy, as specified in dataplane's `networking.transparentProxying.redirectPortInbound`")
@@ -167,8 +166,8 @@ runuser -u kuma-dp -- \
 	cmd.Flags().StringVar(&args.ExcludeOutboundPorts, "exclude-outbound-ports", args.ExcludeOutboundPorts, "a comma separated list of outbound ports to exclude from redirect to Envoy")
 	cmd.Flags().StringVar(&args.User, "kuma-dp-user", args.UID, "the user that will run kuma-dp")
 	cmd.Flags().StringVar(&args.UID, "kuma-dp-uid", args.UID, "the UID of the user that will run kuma-dp")
-	cmd.Flags().BoolVar(&args.RedirectDNS, "redirect-dns", args.RedirectDNS, "redirect all DNS requests to the servers in /etc/resolv.conf to a specified port")
-	cmd.Flags().BoolVar(&args.RedirectAllDNSTraffic, "redirect-all-dns-traffic", args.RedirectAllDNSTraffic, "redirect all DNS requests to a specified port. Implies --redirect-dns.")
+	cmd.Flags().BoolVar(&args.RedirectDNS, "redirect-dns", args.RedirectDNS, "redirect only DNS requests targeted to the servers listed in /etc/resolv.conf to a specified port")
+	cmd.Flags().BoolVar(&args.RedirectAllDNSTraffic, "redirect-all-dns-traffic", args.RedirectAllDNSTraffic, "redirect all DNS requests to a specified port")
 	cmd.Flags().StringVar(&args.AgentDNSListenerPort, "redirect-dns-port", args.AgentDNSListenerPort, "the port where the DNS agent is listening")
 	cmd.Flags().StringVar(&args.DNSUpstreamTargetChain, "redirect-dns-upstream-target-chain", args.DNSUpstreamTargetChain, "(optional) the iptables chain where the upstream DNS requests should be directed to. It is only applied for IP V4. Use with care.")
 	cmd.Flags().BoolVar(&args.SkipResolvConf, "skip-resolv-conf", args.SkipResolvConf, "skip modifying the host `/etc/resolv.conf`")
@@ -198,7 +197,7 @@ func findUidGid(uid, user string) (string, string, error) {
 	return u.Uid, u.Gid, nil
 }
 
-func modifyIpTables(cmd *cobra.Command, args *transparenProxyArgs) error {
+func modifyIpTables(cmd *cobra.Command, args *transparentProxyArgs) error {
 	tp := transparentproxy.DefaultTransparentProxy()
 
 	// best effort cleanup before we apply the rules (again?)
@@ -251,7 +250,7 @@ func modifyIpTables(cmd *cobra.Command, args *transparenProxyArgs) error {
 	return nil
 }
 
-func storeFirewalld(cmd *cobra.Command, args *transparenProxyArgs, output string) error {
+func storeFirewalld(cmd *cobra.Command, args *transparentProxyArgs, output string) error {
 	translator := firewalld.NewFirewalldIptablesTranslator(args.DryRun)
 	parser := regexp.MustCompile(`\* (?P<table>\w*)`)
 	rules := map[string][]string{}
@@ -292,7 +291,7 @@ func storeFirewalld(cmd *cobra.Command, args *transparenProxyArgs, output string
 	return nil
 }
 
-func modifyResolvConf(cmd *cobra.Command, args *transparenProxyArgs) error {
+func modifyResolvConf(cmd *cobra.Command, args *transparentProxyArgs) error {
 	kumaCPLine := fmt.Sprintf("nameserver %s", args.KumaCpIP.String())
 	content, err := ioutil.ReadFile("/etc/resolv.conf")
 	if err != nil {
diff --git a/docs/cmd/kumactl/kumactl_install_transparent-proxy.md b/docs/cmd/kumactl/kumactl_install_transparent-proxy.md
index 590d02faf..cd0bd7d53 100644
--- a/docs/cmd/kumactl/kumactl_install_transparent-proxy.md
+++ b/docs/cmd/kumactl/kumactl_install_transparent-proxy.md
@@ -71,9 +71,8 @@ kumactl install transparent-proxy [flags]
       --kuma-cp-ip ip                                                                   the IP address of the Kuma CP which exposes the DNS service on port 53. (default 0.0.0.0)
       --kuma-dp-uid string                                                              the UID of the user that will run kuma-dp
       --kuma-dp-user string                                                             the user that will run kuma-dp
-      --modify-iptables                                                                 modify the host iptables to redirect the traffic to Envoy (default true)
-      --redirect-all-dns-traffic                                                        redirect all DNS requests to a specified port. Implies --redirect-dns.
-      --redirect-dns                                                                    redirect all DNS requests to the servers in /etc/resolv.conf to a specified port
+      --redirect-all-dns-traffic                                                        redirect all DNS requests to a specified port
+      --redirect-dns                                                                    redirect only DNS requests targeted to the servers listed in /etc/resolv.conf to a specified port
       --redirect-dns-port string                                                        the port where the DNS agent is listening (default "15053")
       --redirect-dns-upstream-target-chain string                                       (optional) the iptables chain where the upstream DNS requests should be directed to. It is only applied for IP V4. Use with care. (default "RETURN")
       --redirect-inbound                                                                redirect the inbound traffic to the Envoy. Should be disabled for Gateway data plane proxies. (default true)
diff --git a/pkg/core/resources/apis/mesh/dataplane.go b/pkg/core/resources/apis/mesh/dataplane.go
deleted file mode 100644
index 79735567a..000000000
--- a/pkg/core/resources/apis/mesh/dataplane.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package mesh
-
-import (
-	"errors"
-
-	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
-	"github.com/kumahq/kuma/pkg/core/resources/model"
-	"github.com/kumahq/kuma/pkg/core/resources/registry"
-)
-
-const (
-	DataplaneType model.ResourceType = "Dataplane"
-)
-
-var _ model.Resource = &DataplaneResource{}
-
-type DataplaneResource struct {
-	Meta model.ResourceMeta
-	Spec *mesh_proto.Dataplane
-}
-
-func NewDataplaneResource() *DataplaneResource {
-	return &DataplaneResource{
-		Spec: &mesh_proto.Dataplane{},
-	}
-}
-
-func (t *DataplaneResource) GetType() model.ResourceType {
-	return DataplaneType
-}
-
-func (t *DataplaneResource) GetMeta() model.ResourceMeta {
-	return t.Meta
-}
-
-func (t *DataplaneResource) SetMeta(m model.ResourceMeta) {
-	t.Meta = m
-}
-
-func (t *DataplaneResource) GetSpec() model.ResourceSpec {
-	return t.Spec
-}
-
-func (t *DataplaneResource) SetSpec(spec model.ResourceSpec) error {
-	dataplane, ok := spec.(*mesh_proto.Dataplane)
-	if !ok {
-		return errors.New("invalid type of spec")
-	} else {
-		t.Spec = dataplane
-		return nil
-	}
-}
-
-func (t *DataplaneResource) Scope() model.ResourceScope {
-	return model.ScopeMesh
-}
-
-var _ model.ResourceList = &DataplaneResourceList{}
-
-type DataplaneResourceList struct {
-	Items      []*DataplaneResource
-	Pagination model.Pagination
-}
-
-func (l *DataplaneResourceList) GetItems() []model.Resource {
-	res := make([]model.Resource, len(l.Items))
-	for i, elem := range l.Items {
-		res[i] = elem
-	}
-	return res
-}
-
-func (l *DataplaneResourceList) GetItemType() model.ResourceType {
-	return DataplaneType
-}
-
-func (l *DataplaneResourceList) NewItem() model.Resource {
-	return NewDataplaneResource()
-}
-
-func (l *DataplaneResourceList) AddItem(r model.Resource) error {
-	if trr, ok := r.(*DataplaneResource); ok {
-		l.Items = append(l.Items, trr)
-		return nil
-	} else {
-		return model.ErrorInvalidItemType((*DataplaneResource)(nil), r)
-	}
-}
-
-func (l *DataplaneResourceList) GetPagination() *model.Pagination {
-	return &l.Pagination
-}
-
-func init() {
-	registry.RegisterType(NewDataplaneResource())
-	registry.RegistryListType(&DataplaneResourceList{})
-}
diff --git a/pkg/core/resources/apis/mesh/health_check.go b/pkg/core/resources/apis/mesh/health_check.go
deleted file mode 100644
index dad1ee30c..000000000
--- a/pkg/core/resources/apis/mesh/health_check.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package mesh
-
-import (
-	"github.com/pkg/errors"
-
-	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
-	"github.com/kumahq/kuma/pkg/core/resources/model"
-	"github.com/kumahq/kuma/pkg/core/resources/registry"
-)
-
-const (
-	HealthCheckType model.ResourceType = "HealthCheck"
-)
-
-var _ model.Resource = &HealthCheckResource{}
-
-type HealthCheckResource struct {
-	Meta model.ResourceMeta
-	Spec *mesh_proto.HealthCheck
-}
-
-func NewHealthCheckResource() *HealthCheckResource {
-	return &HealthCheckResource{
-		Spec: &mesh_proto.HealthCheck{},
-	}
-}
-
-func (r *HealthCheckResource) GetType() model.ResourceType {
-	return HealthCheckType
-}
-func (r *HealthCheckResource) GetMeta() model.ResourceMeta {
-	return r.Meta
-}
-func (r *HealthCheckResource) SetMeta(m model.ResourceMeta) {
-	r.Meta = m
-}
-func (r *HealthCheckResource) GetSpec() model.ResourceSpec {
-	return r.Spec
-}
-func (r *HealthCheckResource) SetSpec(value model.ResourceSpec) error {
-	spec, ok := value.(*mesh_proto.HealthCheck)
-	if !ok {
-		return errors.New("invalid type of spec")
-	} else {
-		r.Spec = spec
-		return nil
-	}
-}
-func (t *HealthCheckResource) Sources() []*mesh_proto.Selector {
-	return t.Spec.GetSources()
-}
-func (t *HealthCheckResource) Destinations() []*mesh_proto.Selector {
-	return t.Spec.GetDestinations()
-}
-func (t *HealthCheckResource) Scope() model.ResourceScope {
-	return model.ScopeMesh
-}
-
-var _ model.ResourceList = &HealthCheckResourceList{}
-
-type HealthCheckResourceList struct {
-	Items      []*HealthCheckResource
-	Pagination model.Pagination
-}
-
-func (l *HealthCheckResourceList) GetItems() []model.Resource {
-	res := make([]model.Resource, len(l.Items))
-	for i, elem := range l.Items {
-		res[i] = elem
-	}
-	return res
-}
-func (l *HealthCheckResourceList) GetItemType() model.ResourceType {
-	return HealthCheckType
-}
-func (l *HealthCheckResourceList) NewItem() model.Resource {
-	return NewHealthCheckResource()
-}
-func (l *HealthCheckResourceList) AddItem(r model.Resource) error {
-	if item, ok := r.(*HealthCheckResource); ok {
-		l.Items = append(l.Items, item)
-		return nil
-	} else {
-		return model.ErrorInvalidItemType((*HealthCheckResource)(nil), r)
-	}
-}
-func (l *HealthCheckResourceList) GetPagination() *model.Pagination {
-	return &l.Pagination
-}
-
-func init() {
-	registry.RegisterType(NewHealthCheckResource())
-	registry.RegistryListType(&HealthCheckResourceList{})
-}
diff --git a/pkg/core/resources/apis/mesh/resources.go b/pkg/core/resources/apis/mesh/resources.go
index ecdb74f0c..80651551e 100644
--- a/pkg/core/resources/apis/mesh/resources.go
+++ b/pkg/core/resources/apis/mesh/resources.go
@@ -110,6 +110,96 @@ func init() {
 	registry.RegistryListType(&CircuitBreakerResourceList{})
 }
 
+const (
+	DataplaneType model.ResourceType = "Dataplane"
+)
+
+var _ model.Resource = &DataplaneResource{}
+
+type DataplaneResource struct {
+	Meta model.ResourceMeta
+	Spec *mesh_proto.Dataplane
+}
+
+func NewDataplaneResource() *DataplaneResource {
+	return &DataplaneResource{
+		Spec: &mesh_proto.Dataplane{},
+	}
+}
+
+func (t *DataplaneResource) GetType() model.ResourceType {
+	return DataplaneType
+}
+
+func (t *DataplaneResource) GetMeta() model.ResourceMeta {
+	return t.Meta
+}
+
+func (t *DataplaneResource) SetMeta(m model.ResourceMeta) {
+	t.Meta = m
+}
+
+func (t *DataplaneResource) GetSpec() model.ResourceSpec {
+	return t.Spec
+}
+
+func (t *DataplaneResource) SetSpec(spec model.ResourceSpec) error {
+	protoType, ok := spec.(*mesh_proto.Dataplane)
+	if !ok {
+		return fmt.Errorf("invalid type %T for Spec", spec)
+	} else {
+		t.Spec = protoType
+		return nil
+	}
+}
+
+func (t *DataplaneResource) Scope() model.ResourceScope {
+
+	return model.ScopeMesh
+
+}
+
+var _ model.ResourceList = &DataplaneResourceList{}
+
+type DataplaneResourceList struct {
+	Items      []*DataplaneResource
+	Pagination model.Pagination
+}
+
+func (l *DataplaneResourceList) GetItems() []model.Resource {
+	res := make([]model.Resource, len(l.Items))
+	for i, elem := range l.Items {
+		res[i] = elem
+	}
+	return res
+}
+
+func (l *DataplaneResourceList) GetItemType() model.ResourceType {
+	return DataplaneType
+}
+
+func (l *DataplaneResourceList) NewItem() model.Resource {
+	return NewDataplaneResource()
+}
+
+func (l *DataplaneResourceList) AddItem(r model.Resource) error {
+	if trr, ok := r.(*DataplaneResource); ok {
+		l.Items = append(l.Items, trr)
+		return nil
+	} else {
+		return model.ErrorInvalidItemType((*DataplaneResource)(nil), r)
+	}
+}
+
+func (l *DataplaneResourceList) GetPagination() *model.Pagination {
+	return &l.Pagination
+}
+
+func init() {
+	registry.RegisterType(NewDataplaneResource())
+	registry.RegistryListType(&DataplaneResourceList{})
+}
+
 const (
 	DataplaneInsightType model.ResourceType = "DataplaneInsight"
 )
@@ -481,6 +571,104 @@ func init() {
 	registry.RegistryListType(&FaultInjectionResourceList{})
 }
 
+const (
+	HealthCheckType model.ResourceType = "HealthCheck"
+)
+
+var _ model.Resource = &HealthCheckResource{}
+
+type HealthCheckResource struct {
+	Meta model.ResourceMeta
+	Spec *mesh_proto.HealthCheck
+}
+
+func NewHealthCheckResource() *HealthCheckResource {
+	return &HealthCheckResource{
+		Spec: &mesh_proto.HealthCheck{},
+	}
+}
+
+func (t *HealthCheckResource) GetType() model.ResourceType {
+	return HealthCheckType
+}
+
+func (t *HealthCheckResource) GetMeta() model.ResourceMeta {
+	return t.Meta
+}
+
+func (t *HealthCheckResource) SetMeta(m model.ResourceMeta) {
+	t.Meta = m
+}
+
+func (t *HealthCheckResource) GetSpec() model.ResourceSpec {
+	return t.Spec
+}
+
+func (t *HealthCheckResource) Sources() []*mesh_proto.Selector {
+	return t.Spec.GetSources()
+}
+
+func (t *HealthCheckResource) Destinations() []*mesh_proto.Selector {
+	return t.Spec.GetDestinations()
+}
+
+func (t *HealthCheckResource) SetSpec(spec model.ResourceSpec) error {
+	protoType, ok := spec.(*mesh_proto.HealthCheck)
+	if !ok {
+		return fmt.Errorf("invalid type %T for Spec", spec)
+	} else {
+		t.Spec = protoType
+		return nil
+	}
+}
+
+func (t *HealthCheckResource) Scope() model.ResourceScope {
+
+	return model.ScopeMesh
+
+}
+
+var _ model.ResourceList = &HealthCheckResourceList{}
+
+type HealthCheckResourceList struct {
+	Items      []*HealthCheckResource
+	Pagination model.Pagination
+}
+
+func (l *HealthCheckResourceList) GetItems() []model.Resource {
+	res := make([]model.Resource, len(l.Items))
+	for i, elem := range l.Items {
+		res[i] = elem
+	}
+	return res
+}
+
+func (l *HealthCheckResourceList) GetItemType() model.ResourceType {
+	return HealthCheckType
+}
+
+func (l *HealthCheckResourceList) NewItem() model.Resource {
+	return NewHealthCheckResource()
+}
+
+func (l *HealthCheckResourceList) AddItem(r model.Resource) error {
+	if trr, ok := r.(*HealthCheckResource); ok {
+		l.Items = append(l.Items, trr)
+		return nil
+	} else {
+		return model.ErrorInvalidItemType((*HealthCheckResource)(nil), r)
+	}
+}
+
+func (l *HealthCheckResourceList) GetPagination() *model.Pagination {
+	return &l.Pagination
+}
+
+func init() {
+	registry.RegisterType(NewHealthCheckResource())
+	registry.RegistryListType(&HealthCheckResourceList{})
+}
+
 const (
 	MeshType model.ResourceType = "Mesh"
 )
@@ -1714,6 +1902,100 @@ func init() {
 	registry.RegistryListType(&ZoneIngressResourceList{})
 }
 
+const (
+	ZoneIngressInsightType model.ResourceType = "ZoneIngressInsight"
+)
+
+var _ model.Resource = &ZoneIngressInsightResource{}
+
+type ZoneIngressInsightResource struct {
+	Meta model.ResourceMeta
+	Spec *mesh_proto.ZoneIngressInsight
+}
+
+func NewZoneIngressInsightResource() *ZoneIngressInsightResource {
+	return &ZoneIngressInsightResource{
+		Spec: &mesh_proto.ZoneIngressInsight{},
+	}
+}
+
+func (t *ZoneIngressInsightResource) GetType() model.ResourceType {
+	return ZoneIngressInsightType
+}
+
+func (t *ZoneIngressInsightResource) GetMeta() model.ResourceMeta {
+	return t.Meta
+}
+
+func (t *ZoneIngressInsightResource) SetMeta(m model.ResourceMeta) {
+	t.Meta = m
+}
+
+func (t *ZoneIngressInsightResource) GetSpec() model.ResourceSpec {
+	return t.Spec
+}
+
+func (t *ZoneIngressInsightResource) Validate() error {
+	return nil
+}
+
+func (t *ZoneIngressInsightResource) SetSpec(spec model.ResourceSpec) error {
+	protoType, ok := spec.(*mesh_proto.ZoneIngressInsight)
+	if !ok {
+		return fmt.Errorf("invalid type %T for Spec", spec)
+	} else {
+		t.Spec = protoType
+		return nil
+	}
+}
+
+func (t *ZoneIngressInsightResource) Scope() model.ResourceScope {
+
+	return model.ScopeGlobal
+
+}
+
+var _ model.ResourceList = &ZoneIngressInsightResourceList{}
+
+type ZoneIngressInsightResourceList struct {
+	Items      []*ZoneIngressInsightResource
+	Pagination model.Pagination
+}
+
+func (l *ZoneIngressInsightResourceList) GetItems() []model.Resource {
+	res := make([]model.Resource, len(l.Items))
+	for i, elem := range l.Items {
+		res[i] = elem
+	}
+	return res
+}
+
+func (l *ZoneIngressInsightResourceList) GetItemType() model.ResourceType {
+	return ZoneIngressInsightType
+}
+
+func (l *ZoneIngressInsightResourceList) NewItem() model.Resource {
+	return NewZoneIngressInsightResource()
+}
+
+func (l *ZoneIngressInsightResourceList) AddItem(r model.Resource) error {
+	if trr, ok := r.(*ZoneIngressInsightResource); ok {
+		l.Items = append(l.Items, trr)
+		return nil
+	} else {
+		return model.ErrorInvalidItemType((*ZoneIngressInsightResource)(nil), r)
+	}
+}
+
+func (l *ZoneIngressInsightResourceList) GetPagination() *model.Pagination {
+	return &l.Pagination
+}
+
+func init() {
+	registry.RegisterType(NewZoneIngressInsightResource())
+	registry.RegistryListType(&ZoneIngressInsightResourceList{})
+}
+
 const (
 	ZoneIngressOverviewType model.ResourceType = "ZoneIngressOverview"
 )
diff --git a/pkg/core/resources/apis/mesh/zoneingres_insight.go b/pkg/core/resources/apis/mesh/zoneingres_insight.go
deleted file mode 100644
index 9d84df135..000000000
--- a/pkg/core/resources/apis/mesh/zoneingres_insight.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package mesh
-
-import (
-	"errors"
-
-	"github.com/kumahq/kuma/pkg/core/resources/registry"
-
-	mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
-	"github.com/kumahq/kuma/pkg/core/resources/model"
-)
-
-const (
-	ZoneIngressInsightType model.ResourceType = "ZoneIngressInsight"
-)
-
-var _ model.Resource = &ZoneIngressInsightResource{}
-
-type ZoneIngressInsightResource struct {
-	Meta model.ResourceMeta
-	Spec *mesh_proto.ZoneIngressInsight
-}
-
-func NewZoneIngressInsightResource() *ZoneIngressInsightResource {
-	return &ZoneIngressInsightResource{
-		Spec: &mesh_proto.ZoneIngressInsight{},
-	}
-}
-
-func (t *ZoneIngressInsightResource) GetType() model.ResourceType {
-	return ZoneIngressInsightType
-}
-func (t *ZoneIngressInsightResource) GetMeta() model.ResourceMeta {
-	return t.Meta
-}
-func (t *ZoneIngressInsightResource) SetMeta(m model.ResourceMeta) {
-	t.Meta = m
-}
-func (t *ZoneIngressInsightResource) GetSpec() model.ResourceSpec {
-	return t.Spec
-}
-func (t *ZoneIngressInsightResource) SetSpec(spec model.ResourceSpec) error {
-	status, ok := spec.(*mesh_proto.ZoneIngressInsight)
-	if !ok {
-		return errors.New("invalid type of spec")
-	} else {
-		t.Spec = status
-		return nil
-	}
-}
-func (t *ZoneIngressInsightResource) Validate() error {
-	return nil
-}
-func (t *ZoneIngressInsightResource) Scope() model.ResourceScope {
-	return model.ScopeGlobal
-}
-
-var _ model.ResourceList = &ZoneIngressInsightResourceList{}
-
-type ZoneIngressInsightResourceList struct {
-	Items      []*ZoneIngressInsightResource
-	Pagination model.Pagination
-}
-
-func (l *ZoneIngressInsightResourceList) GetItems() []model.Resource {
-	res := make([]model.Resource, len(l.Items))
-	for i, elem := range l.Items {
-		res[i] = elem
-	}
-	return res
-}
-func (l *ZoneIngressInsightResourceList) GetItemType() model.ResourceType {
-	return ZoneIngressInsightType
-}
-func (l *ZoneIngressInsightResourceList) NewItem() model.Resource {
-	return NewZoneIngressInsightResource()
-}
-func (l *ZoneIngressInsightResourceList) AddItem(r model.Resource) error {
-	if trr, ok := r.(*ZoneIngressInsightResource); ok {
-		l.Items = append(l.Items, trr)
-		return nil
-	} else {
-		return model.ErrorInvalidItemType((*ZoneIngressInsightResource)(nil), r)
-	}
-}
-
-func (l *ZoneIngressInsightResourceList) GetPagination() *model.Pagination {
-	return &l.Pagination
-}
-
-func init() {
-	registry.RegisterType(NewZoneIngressInsightResource())
-	registry.RegistryListType(&ZoneIngressInsightResourceList{})
-}
diff --git a/pkg/log/logger.go b/pkg/log/logger.go
index fe99d5e17..6f6d025be 100644
--- a/pkg/log/logger.go
+++ b/pkg/log/logger.go
@@ -69,7 +69,11 @@ func newZapLoggerTo(destWriter io.Writer, level LogLevel, opts ...zap.Option) *z
 	case OffLevel:
 		return zap.NewNop()
 	case DebugLevel:
-		lvl = zap.NewAtomicLevelAt(zap.DebugLevel)
+		// The value we pass here is the most verbose level that
+		// will end up being emitted through the `V(level int)`
+		// accessor. Passing -10 ensures that levels up to `V(10)`
+		// will work, which seems like plenty.
+		lvl = zap.NewAtomicLevelAt(-10)
 		opts = append(opts, zap.Development(), zap.AddStacktrace(zap.ErrorLevel))
 	default:
 		lvl = zap.NewAtomicLevelAt(zap.InfoLevel)
diff --git a/pkg/sds/server/v3/server.go b/pkg/sds/server/v3/server.go
index 834807eaa..693ab64bc 100644
--- a/pkg/sds/server/v3/server.go
+++ b/pkg/sds/server/v3/server.go
@@ -11,6 +11,7 @@ import (
 	"github.com/go-logr/logr"
 
 	"github.com/kumahq/kuma/pkg/core"
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_runtime "github.com/kumahq/kuma/pkg/core/runtime"
 	core_xds "github.com/kumahq/kuma/pkg/core/xds"
 	sds_ca "github.com/kumahq/kuma/pkg/sds/ca"
@@ -72,7 +73,8 @@ func RegisterSDS(rt core_runtime.Runtime, sdsMetrics *sds_metrics.Metrics) error
 }
 
 func syncTracker(reconciler *DataplaneReconciler, refresh time.Duration, sdsMetrics *sds_metrics.Metrics) (util_xds.Callbacks, error) {
-	return xds_callbacks.NewDataplaneSyncTracker(func(proxyId *core_xds.ProxyId, streamId int64) util_watchdog.Watchdog {
+	return xds_callbacks.DataplaneCallbacksToXdsCallbacks(xds_callbacks.NewDataplaneSyncTracker(func(key core_model.ResourceKey) util_watchdog.Watchdog {
+		proxyId := core_xds.FromResourceKey(key)
 		return &util_watchdog.SimpleWatchdog{
 			NewTicker: func() *time.Ticker {
 				sdsMetrics.IncrementActiveWatchdogs(envoy_common.APIV3)
@@ -83,20 +85,20 @@ func syncTracker(reconciler *DataplaneReconciler, refresh time.Duration, sdsMetr
 				defer func() {
 					sdsMetrics.SdsGeneration(envoy_common.APIV3).Observe(float64(core.Now().Sub(start).Milliseconds()))
 				}()
-				return reconciler.Reconcile(proxyId)
+				return reconciler.Reconcile(&proxyId)
 			},
 			OnError: func(err error) {
 				sdsMetrics.SdsGenerationsErrors(envoy_common.APIV3).Inc()
 				sdsServerLog.Error(err, "OnTick() failed")
 			},
 			OnStop: func() {
-				if err := reconciler.Cleanup(proxyId); err != nil {
-					sdsServerLog.Error(err, "could not cleanup sync", "dataplane", proxyId.ToResourceKey())
+				if err := reconciler.Cleanup(&proxyId); err != nil {
+					sdsServerLog.Error(err, "could not cleanup sync", "dataplane", key)
 				}
 				sdsMetrics.DecrementActiveWatchdogs(envoy_common.APIV3)
 			},
 		}
-	}), nil
+	})), nil
 }
 
 type hasher struct {
diff --git a/pkg/xds/server/callbacks/connection_info_tracker.go b/pkg/xds/server/callbacks/connection_info_tracker.go
index edacd2700..346072809 100644
--- a/pkg/xds/server/callbacks/connection_info_tracker.go
+++ b/pkg/xds/server/callbacks/connection_info_tracker.go
@@ -7,8 +7,8 @@ import (
 	"github.com/pkg/errors"
 	"google.golang.org/grpc/metadata"
 
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_xds "github.com/kumahq/kuma/pkg/core/xds"
-	util_xds "github.com/kumahq/kuma/pkg/util/xds"
 	xds_context "github.com/kumahq/kuma/pkg/xds/context"
 )
 
@@ -16,26 +16,33 @@ const authorityHeader = ":authority"
 
 // ConnectionInfoTracker tracks the information about the connection itself from the data plane to the control plane
 type ConnectionInfoTracker struct {
-	util_xds.NoopCallbacks
 	sync.RWMutex
-	connectionInfos map[core_xds.StreamID]xds_context.ConnectionInfo
+	connectionInfos map[core_model.ResourceKey]*xds_context.ConnectionInfo
 }
 
-var _ util_xds.Callbacks = &ConnectionInfoTracker{}
+var _ DataplaneCallbacks = &ConnectionInfoTracker{}
 
 func NewConnectionInfoTracker() *ConnectionInfoTracker {
 	return &ConnectionInfoTracker{
-		connectionInfos: map[core_xds.StreamID]xds_context.ConnectionInfo{},
+		connectionInfos: map[core_model.ResourceKey]*xds_context.ConnectionInfo{},
 	}
 }
 
-func (c *ConnectionInfoTracker) ConnectionInfo(streamID core_xds.StreamID) xds_context.ConnectionInfo {
+func (c *ConnectionInfoTracker) ConnectionInfo(dpKey core_model.ResourceKey) *xds_context.ConnectionInfo {
 	c.RLock()
 	defer c.RUnlock()
-	return c.connectionInfos[streamID]
+	return c.connectionInfos[dpKey]
 }
 
-func (c *ConnectionInfoTracker) OnStreamOpen(ctx context.Context, streamID core_xds.StreamID, _ string) error {
+func (c *ConnectionInfoTracker) OnProxyReconnected(_ core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, _ core_xds.DataplaneMetadata) error {
+	return c.processConnectionInfo(dpKey, ctx)
+}
+
+func (c *ConnectionInfoTracker) OnProxyConnected(_ core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, _ core_xds.DataplaneMetadata) error {
+	return c.processConnectionInfo(dpKey, ctx)
+}
+
+func (c *ConnectionInfoTracker) processConnectionInfo(dpKey core_model.ResourceKey, ctx context.Context) error {
 	metadata, ok := metadata.FromIncomingContext(ctx)
 	if !ok {
 		return errors.New("request has no metadata")
@@ -48,13 +55,13 @@ func (c *ConnectionInfoTracker) OnStreamOpen(ctx context.Context, streamID core_
 	connInfo := xds_context.ConnectionInfo{
 		Authority: values[0],
 	}
-	c.connectionInfos[streamID] = connInfo
+	c.connectionInfos[dpKey] = &connInfo
 	c.Unlock()
 	return nil
 }
 
-func (c *ConnectionInfoTracker) OnStreamClosed(streamID core_xds.StreamID) {
+func (c *ConnectionInfoTracker) OnProxyDisconnected(_ core_xds.StreamID, dpKey core_model.ResourceKey) {
 	c.Lock()
-	delete(c.connectionInfos, streamID)
+	delete(c.connectionInfos, dpKey)
 	c.Unlock()
 }
diff --git a/pkg/xds/server/callbacks/dataplane_callbacks.go b/pkg/xds/server/callbacks/dataplane_callbacks.go
new file mode 100644
index 000000000..4f6554d3d
--- /dev/null
+++ b/pkg/xds/server/callbacks/dataplane_callbacks.go
@@ -0,0 +1,154 @@
+package callbacks
+
+import (
+	"context"
+	"sync"
+
+	"github.com/pkg/errors"
+
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
+	core_xds "github.com/kumahq/kuma/pkg/core/xds"
+	util_xds "github.com/kumahq/kuma/pkg/util/xds"
+)
+
+// DataplaneCallbacks are XDS callbacks that keep the context of Kuma Dataplane.
+// In the ideal world we could assume that one Dataplane has one xDS stream.
+// Due to race network latencies etc. there might be a situation when one Dataplane has many xDS streams for the short period of time.
+// Those callbacks helps us to deal with such situation.
+//
+// Keep in mind that it does not solve many xDS streams across many instances of the Control Plane.
+// If there are many instances of the Control Plane and Dataplane reconnects, there might be an old stream
+// in one instance of CP and a new stream in a new instance of CP.
+//
+// Those callbacks may be also used with SDS. In case of SDS, at this moment Envoy creates many SDS streams to the Control Plane.
+type DataplaneCallbacks interface {
+	// OnProxyConnected is executed when proxy is connected after it was disconnected before.
+	OnProxyConnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, metadata core_xds.DataplaneMetadata) error
+	// OnProxyReconnected is executed when proxy is already connected, but there is another stream.
+	// This can happen when there is a delay with closing the old connection from the proxy to the control plane.
+	OnProxyReconnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, metadata core_xds.DataplaneMetadata) error
+	// OnProxyDisconnected is executed only when the last stream of the proxy disconnects.
+	OnProxyDisconnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey)
+}
+
+type xdsCallbacks struct {
+	callbacks DataplaneCallbacks
+	util_xds.NoopCallbacks
+
+	sync.RWMutex
+	dpStreams     map[core_xds.StreamID]dpStream
+	activeStreams map[core_model.ResourceKey]int
+}
+
+func DataplaneCallbacksToXdsCallbacks(callbacks DataplaneCallbacks) util_xds.Callbacks {
+	return &xdsCallbacks{
+		callbacks:     callbacks,
+		dpStreams:     map[core_xds.StreamID]dpStream{},
+		activeStreams: map[core_model.ResourceKey]int{},
+	}
+}
+
+type dpStream struct {
+	dp  *core_model.ResourceKey
+	ctx context.Context
+}
+
+var _ util_xds.Callbacks = &xdsCallbacks{}
+
+func (d *xdsCallbacks) OnStreamClosed(streamID core_xds.StreamID) {
+	d.Lock()
+	defer d.Unlock()
+	dpStream := d.dpStreams[streamID]
+	if dpKey := dpStream.dp; dpKey != nil {
+		d.activeStreams[*dpKey]--
+		if d.activeStreams[*dpKey] == 0 {
+			d.callbacks.OnProxyDisconnected(streamID, *dpKey)
+			delete(d.activeStreams, *dpKey)
+		}
+	}
+	delete(d.dpStreams, streamID)
+}
+
+func (d *xdsCallbacks) OnStreamRequest(streamID core_xds.StreamID, request util_xds.DiscoveryRequest) error {
+	if request.NodeId() == "" {
+		// from https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#ack-nack-and-versioning:
+		// Only the first request on a stream is guaranteed to carry the node identifier.
+		// The subsequent discovery requests on the same stream may carry an empty node identifier.
+		// This holds true regardless of the acceptance of the discovery responses on the same stream.
+		// The node identifier should always be identical if present more than once on the stream.
+		// It is sufficient to only check the first message for the node identifier as a result.
+		return nil
+	}
+
+	d.RLock()
+	alreadyProcessed := d.dpStreams[streamID].dp != nil
+	d.RUnlock()
+	if alreadyProcessed {
+		return nil
+	}
+
+	proxyId, err := core_xds.ParseProxyIdFromString(request.NodeId())
+	if err != nil {
+		return errors.Wrap(err, "invalid node ID")
+	}
+	dpKey := proxyId.ToResourceKey()
+	metadata := core_xds.DataplaneMetadataFromXdsMetadata(request.Metadata())
+	if metadata == nil {
+		return errors.New("metadata in xDS Node cannot be nil")
+	}
+
+	d.Lock()
+	// in case client will open 2 concurrent request for the same streamID then
+	// we don't to increment the counter twice, so checking once again that stream
+	// wasn't processed
+	alreadyProcessed = d.dpStreams[streamID].dp != nil
+	if alreadyProcessed {
+		return nil
+	}
+
+	dpStream := d.dpStreams[streamID]
+	dpStream.dp = &dpKey
+	d.dpStreams[streamID] = dpStream
+
+	activeStreams := d.activeStreams[dpKey]
+	d.activeStreams[dpKey]++
+	d.Unlock()
+
+	if activeStreams == 0 {
+		if err := d.callbacks.OnProxyConnected(streamID, dpKey, dpStream.ctx, *metadata); err != nil {
+			return err
+		}
+	} else {
+		if err := d.callbacks.OnProxyReconnected(streamID, dpKey, dpStream.ctx, *metadata); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (d *xdsCallbacks) OnStreamOpen(ctx context.Context, streamID core_xds.StreamID, _ string) error {
+	d.Lock()
+	defer d.Unlock()
+	dps := dpStream{
+		ctx: ctx,
+	}
+	d.dpStreams[streamID] = dps
+	return nil
+}
+
+// NoopDataplaneCallbacks are empty callbacks that helps to implement DataplaneCallbacks without need to implement every function.
+type NoopDataplaneCallbacks struct {
+}
+
+func (n *NoopDataplaneCallbacks) OnProxyReconnected(core_xds.StreamID, core_model.ResourceKey, context.Context, core_xds.DataplaneMetadata) error {
+	return nil
+}
+
+func (n *NoopDataplaneCallbacks) OnProxyConnected(core_xds.StreamID, core_model.ResourceKey, context.Context, core_xds.DataplaneMetadata) error {
+	return nil
+}
+
+func (n *NoopDataplaneCallbacks) OnProxyDisconnected(core_xds.StreamID, core_model.ResourceKey) {
+}
+
+var _ DataplaneCallbacks = &NoopDataplaneCallbacks{}
diff --git a/pkg/xds/server/callbacks/dataplane_lifecycle.go b/pkg/xds/server/callbacks/dataplane_lifecycle.go
index 8d06e1baf..b021d5aee 100644
--- a/pkg/xds/server/callbacks/dataplane_lifecycle.go
+++ b/pkg/xds/server/callbacks/dataplane_lifecycle.go
@@ -13,8 +13,7 @@ import (
 	"github.com/kumahq/kuma/pkg/core/resources/manager"
 	"github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/core/resources/store"
-	"github.com/kumahq/kuma/pkg/core/xds"
-	util_xds "github.com/kumahq/kuma/pkg/util/xds"
+	core_xds "github.com/kumahq/kuma/pkg/core/xds"
 )
 
 var lifecycleLog = core.Log.WithName("xds").WithName("dp-lifecycle")
@@ -29,28 +28,45 @@ var lifecycleLog = core.Log.WithName("xds").WithName("dp-lifecycle")
 //
 // This flow is optional, you may still want to go with 1. an example of this is Kubernetes deployment.
 type DataplaneLifecycle struct {
-	util_xds.NoopCallbacks
 	resManager manager.ResourceManager
-	// createdDpForStream stores map from StreamID to created ResourceKey of Dataplane.
-	// we store nil values for streams without Dataplane in metadata to avoid accessing metadata with every DiscoveryRequest
-	createdDpForStream map[xds.StreamID]*model.ResourceKey
-	proxyTypeForStream map[xds.StreamID]mesh_proto.ProxyType
-	sync.RWMutex       // protects createdDpForStream
-	shutdownCh         <-chan struct{}
+
+	sync.RWMutex         // protects createdDpByCallbacks
+	createdDpByCallbacks map[model.ResourceKey]mesh_proto.ProxyType
+	shutdownCh           <-chan struct{}
 }
 
-var _ util_xds.Callbacks = &DataplaneLifecycle{}
+func (d *DataplaneLifecycle) OnProxyConnected(streamID core_xds.StreamID, dpKey model.ResourceKey, _ context.Context, md core_xds.DataplaneMetadata) error {
+	return d.register(streamID, dpKey, md)
+}
 
-func NewDataplaneLifecycle(resManager manager.ResourceManager, shutdownCh <-chan struct{}) *DataplaneLifecycle {
-	return &DataplaneLifecycle{
-		resManager:         resManager,
-		createdDpForStream: map[xds.StreamID]*model.ResourceKey{},
-		proxyTypeForStream: map[xds.StreamID]mesh_proto.ProxyType{},
-		shutdownCh:         shutdownCh,
+func (d *DataplaneLifecycle) OnProxyReconnected(streamID core_xds.StreamID, dpKey model.ResourceKey, _ context.Context, md core_xds.DataplaneMetadata) error {
+	return d.register(streamID, dpKey, md)
+}
+
+func (d *DataplaneLifecycle) register(streamID core_xds.StreamID, dpKey model.ResourceKey, md core_xds.DataplaneMetadata) error {
+	if md.GetProxyType() == mesh_proto.DataplaneProxyType && md.GetDataplaneResource() != nil {
+		dp := md.GetDataplaneResource()
+		lifecycleLog.Info("registering dataplane", "dataplane", dp, "dataplaneKey", dpKey, "streamID", streamID)
+		if err := d.registerDataplane(dp); err != nil {
+			return errors.Wrap(err, "could not register dataplane passed in kuma-dp run")
+		}
+		d.createdDpByCallbacks[dpKey] = mesh_proto.DataplaneProxyType
+		return nil
+	}
+
+	if md.GetProxyType() == mesh_proto.IngressProxyType && md.GetZoneIngressResource() != nil {
+		zi := md.GetZoneIngressResource()
+		lifecycleLog.Info("registering zone ingress", "zoneIngress", zi, "zoneIngressKey", dpKey, "streamID", streamID)
+		if err := d.registerZoneIngress(zi); err != nil {
+			return errors.Wrap(err, "could not register zone ingress passed in kuma-dp run")
+		}
+		d.createdDpByCallbacks[dpKey] = mesh_proto.IngressProxyType
+		return nil
 	}
+	return nil
 }
 
-func (d *DataplaneLifecycle) OnStreamClosed(streamID int64) {
+func (d *DataplaneLifecycle) OnProxyDisconnected(streamID core_xds.StreamID, dpKey model.ResourceKey) {
 	// OnStreamClosed method could be called either in case data plane proxy is down or
 	// Kuma CP is gracefully shutting down. If Kuma CP is gracefully shutting down we
 	// must not delete Dataplane resource, data plane proxy will be reconnected to another
@@ -64,79 +80,37 @@ func (d *DataplaneLifecycle) OnStreamClosed(streamID int64) {
 
 	d.Lock()
 	defer d.Unlock()
-	key := d.createdDpForStream[streamID]
-	proxyType := d.proxyTypeForStream[streamID]
-	delete(d.createdDpForStream, streamID)
-	delete(d.proxyTypeForStream, streamID)
-
-	if key == nil {
+	proxyType, createdByCallbacks := d.createdDpByCallbacks[dpKey]
+	if !createdByCallbacks {
 		return
 	}
+	delete(d.createdDpByCallbacks, dpKey)
 
 	if proxyType == mesh_proto.DataplaneProxyType {
-		lifecycleLog.Info("unregistering dataplane", "dataplaneKey", key, "streamID", streamID)
-		if err := d.unregisterDataplane(*key); err != nil {
+		lifecycleLog.Info("unregistering dataplane", "dataplaneKey", dpKey, "streamID", streamID)
+		if err := d.unregisterDataplane(dpKey); err != nil {
 			lifecycleLog.Error(err, "could not unregister dataplane")
 		}
 		return
 	}
 
 	if proxyType == mesh_proto.IngressProxyType {
-		lifecycleLog.Info("unregistering zone ingress", "zoneIngressKey", key, "streamID", streamID)
-		if err := d.unregisterZoneIngress(*key); err != nil {
+		lifecycleLog.Info("unregistering zone ingress", "zoneIngressKey", dpKey, "streamID", streamID)
+		if err := d.unregisterZoneIngress(dpKey); err != nil {
 			lifecycleLog.Error(err, "could not unregister zone ingress")
 		}
 		return
 	}
 }
 
-func (d *DataplaneLifecycle) OnStreamRequest(streamID int64, request util_xds.DiscoveryRequest) error {
-	if request.NodeId() == "" { // Only the first request on a stream is guaranteed to carry the node identifier.
-		return nil
-	}
+var _ DataplaneCallbacks = &DataplaneLifecycle{}
 
-	if d.streamProcessed(streamID) {
-		return nil
-	}
-
-	d.Lock()
-	defer d.Unlock()
-
-	md := xds.DataplaneMetadataFromXdsMetadata(request.Metadata())
-
-	if md.GetProxyType() == mesh_proto.DataplaneProxyType && md.GetDataplaneResource() != nil {
-		dp := md.GetDataplaneResource()
-		lifecycleLog.Info("registering dataplane", "dataplane", dp, "streamID", streamID, "nodeID", request.NodeId())
-		if err := d.registerDataplane(dp); err != nil {
-			return errors.Wrap(err, "could not register dataplane passed in kuma-dp run")
-		}
-		key := model.MetaToResourceKey(dp.GetMeta())
-		d.createdDpForStream[streamID] = &key
-		d.proxyTypeForStream[streamID] = mesh_proto.DataplaneProxyType
-		return nil
-	}
-
-	if md.GetProxyType() == mesh_proto.IngressProxyType && md.GetZoneIngressResource() != nil {
-		zi := md.GetZoneIngressResource()
-		lifecycleLog.Info("registering zone ingress", "zoneIngress", zi, "streamID", streamID, "nodeID", request.NodeId())
-		if err := d.registerZoneIngress(zi); err != nil {
-			return errors.Wrap(err, "could not register zone ingress passed in kuma-dp run")
-		}
-		key := model.MetaToResourceKey(zi.GetMeta())
-		d.createdDpForStream[streamID] = &key
-		d.proxyTypeForStream[streamID] = mesh_proto.IngressProxyType
-		return nil
+func NewDataplaneLifecycle(resManager manager.ResourceManager, shutdownCh <-chan struct{}) *DataplaneLifecycle {
+	return &DataplaneLifecycle{
+		resManager:           resManager,
+		createdDpByCallbacks: map[model.ResourceKey]mesh_proto.ProxyType{},
+		shutdownCh:           shutdownCh,
 	}
-
-	d.createdDpForStream[streamID] = nil // put nil so we don't have to read metadata every time
-	return nil
-}
-
-func (d *DataplaneLifecycle) streamProcessed(streamID int64) bool {
-	d.RLock()
-	defer d.RUnlock()
-	_, ok := d.createdDpForStream[streamID]
-	return ok
 }
 
 func (d *DataplaneLifecycle) registerDataplane(dp *core_mesh.DataplaneResource) error {
diff --git a/pkg/xds/server/callbacks/dataplane_metadata_tracker.go b/pkg/xds/server/callbacks/dataplane_metadata_tracker.go
index 98631ed61..74a034cd3 100644
--- a/pkg/xds/server/callbacks/dataplane_metadata_tracker.go
+++ b/pkg/xds/server/callbacks/dataplane_metadata_tracker.go
@@ -1,57 +1,50 @@
 package callbacks
 
 import (
+	"context"
 	"sync"
 
-	"github.com/kumahq/kuma/pkg/core/xds"
-	util_xds "github.com/kumahq/kuma/pkg/util/xds"
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
+	core_xds "github.com/kumahq/kuma/pkg/core/xds"
 )
 
 type DataplaneMetadataTracker struct {
-	util_xds.NoopCallbacks
-	mutex             sync.RWMutex
-	metadataForStream map[int64]*xds.DataplaneMetadata
+	sync.RWMutex
+	metadataForDp map[core_model.ResourceKey]*core_xds.DataplaneMetadata
 }
 
+var _ DataplaneCallbacks = &DataplaneMetadataTracker{}
+
 func NewDataplaneMetadataTracker() *DataplaneMetadataTracker {
 	return &DataplaneMetadataTracker{
-		mutex:             sync.RWMutex{},
-		metadataForStream: map[int64]*xds.DataplaneMetadata{},
+		metadataForDp: map[core_model.ResourceKey]*core_xds.DataplaneMetadata{},
 	}
 }
 
-func (d *DataplaneMetadataTracker) Metadata(streamId int64) *xds.DataplaneMetadata {
-	d.mutex.RLock()
-	defer d.mutex.RUnlock()
-	metadata, found := d.metadataForStream[streamId]
-	if found {
-		return metadata
-	} else {
-		return &xds.DataplaneMetadata{}
-	}
+func (d *DataplaneMetadataTracker) Metadata(dpKey core_model.ResourceKey) *core_xds.DataplaneMetadata {
+	d.RLock()
+	defer d.RUnlock()
+	return d.metadataForDp[dpKey]
 }
 
-var _ util_xds.Callbacks = &DataplaneMetadataTracker{}
+func (d *DataplaneMetadataTracker) OnProxyReconnected(_ core_xds.StreamID, dpKey core_model.ResourceKey, _ context.Context, metadata core_xds.DataplaneMetadata) error {
+	d.storeMetadata(dpKey, metadata)
+	return nil
+}
 
-func (d *DataplaneMetadataTracker) OnStreamClosed(stream int64) {
-	d.mutex.Lock()
-	defer d.mutex.Unlock()
-	delete(d.metadataForStream, stream)
+func (d *DataplaneMetadataTracker) OnProxyConnected(_ core_xds.StreamID, dpKey core_model.ResourceKey, _ context.Context, metadata core_xds.DataplaneMetadata) error {
+	d.storeMetadata(dpKey, metadata)
+	return nil
 }
 
-func (d *DataplaneMetadataTracker) OnStreamRequest(stream int64, req util_xds.DiscoveryRequest) error {
-	if req.NodeId() == "" {
-		// from https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#ack-nack-and-versioning:
-		// Only the first request on a stream is guaranteed to carry the node identifier.
-		// The subsequent discovery requests on the same stream may carry an empty node identifier.
-		// This holds true regardless of the acceptance of the discovery responses on the same stream.
-		// The node identifier should always be identical if present more than once on the stream.
-		// It is sufficient to only check the first message for the node identifier as a result.
-		return nil
-	}
+func (d *DataplaneMetadataTracker) storeMetadata(dpKey core_model.ResourceKey, metadata core_xds.DataplaneMetadata) {
+	d.Lock()
+	defer d.Unlock()
+	d.metadataForDp[dpKey] = &metadata
+}
 
-	d.mutex.Lock()
-	defer d.mutex.Unlock()
-	d.metadataForStream[stream] = xds.DataplaneMetadataFromXdsMetadata(req.Metadata())
-	return nil
+func (d *DataplaneMetadataTracker) OnProxyDisconnected(_ core_xds.StreamID, dpKey core_model.ResourceKey) {
+	d.Lock()
+	defer d.Unlock()
+	delete(d.metadataForDp, dpKey)
 }
diff --git a/pkg/xds/server/callbacks/dataplane_sync_tracker.go b/pkg/xds/server/callbacks/dataplane_sync_tracker.go
index 5de6ae83a..7f819e00a 100644
--- a/pkg/xds/server/callbacks/dataplane_sync_tracker.go
+++ b/pkg/xds/server/callbacks/dataplane_sync_tracker.go
@@ -8,29 +8,22 @@ import (
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_xds "github.com/kumahq/kuma/pkg/core/xds"
 	util_watchdog "github.com/kumahq/kuma/pkg/util/watchdog"
-	util_xds "github.com/kumahq/kuma/pkg/util/xds"
 )
 
 var (
 	dataplaneSyncTrackerLog = core.Log.WithName("xds-server").WithName("dataplane-sync-tracker")
 )
 
-type NewDataplaneWatchdogFunc func(proxyId *core_xds.ProxyId, streamId core_xds.StreamID) util_watchdog.Watchdog
+type NewDataplaneWatchdogFunc func(key core_model.ResourceKey) util_watchdog.Watchdog
 
-func NewDataplaneSyncTracker(factoryFunc NewDataplaneWatchdogFunc) util_xds.Callbacks {
+func NewDataplaneSyncTracker(factoryFunc NewDataplaneWatchdogFunc) DataplaneCallbacks {
 	return &dataplaneSyncTracker{
 		newDataplaneWatchdog: factoryFunc,
-		streamsAssociation:   make(map[core_xds.StreamID]core_model.ResourceKey),
-		dpStreams:            make(map[core_model.ResourceKey]streams),
+		watchdogs:            map[core_model.ResourceKey]context.CancelFunc{},
 	}
 }
 
-var _ util_xds.Callbacks = &dataplaneSyncTracker{}
-
-type streams struct {
-	watchdogCancel context.CancelFunc
-	activeStreams  map[core_xds.StreamID]bool
-}
+var _ DataplaneCallbacks = &dataplaneSyncTracker{}
 
 // dataplaneSyncTracker tracks XDS streams that are connected to the CP and fire up a watchdog.
 // Watchdog should be run only once for given dataplane regardless of the number of streams.
@@ -39,77 +32,35 @@ type streams struct {
 // Node info can be (but does not have to be) carried only on the first XDS request. That's why need streamsAssociation map
 // that indicates that the stream was already associated
 type dataplaneSyncTracker struct {
-	newDataplaneWatchdog NewDataplaneWatchdogFunc
+	NoopDataplaneCallbacks
 
-	stdsync.RWMutex    // protects access to the fields below
-	streamsAssociation map[core_xds.StreamID]core_model.ResourceKey
-	dpStreams          map[core_model.ResourceKey]streams
-}
+	newDataplaneWatchdog NewDataplaneWatchdogFunc
 
-// OnStreamOpen is called once an xDS stream is open with a stream ID and the type URL (or "" for ADS).
-// Returning an error will end processing and close the stream. OnStreamClosed will still be called.
-func (t *dataplaneSyncTracker) OnStreamOpen(ctx context.Context, streamID core_xds.StreamID, typ string) error {
-	return nil
+	stdsync.RWMutex // protects access to the fields below
+	watchdogs       map[core_model.ResourceKey]context.CancelFunc
 }
 
-// OnStreamClosed is called immediately prior to closing an xDS stream with a stream ID.
-func (t *dataplaneSyncTracker) OnStreamClosed(streamID core_xds.StreamID) {
+func (t *dataplaneSyncTracker) OnProxyConnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey, _ context.Context, _ core_xds.DataplaneMetadata) error {
+	// We use OnProxyConnected because there should be only one watchdog for given dataplane.
 	t.Lock()
 	defer t.Unlock()
 
-	dp, hasAssociation := t.streamsAssociation[streamID]
-	if hasAssociation {
-		delete(t.streamsAssociation, streamID)
-
-		streams := t.dpStreams[dp]
-		delete(streams.activeStreams, streamID)
-		if len(streams.activeStreams) == 0 { // no stream is active, cancel watchdog
-			if streams.watchdogCancel != nil {
-				streams.watchdogCancel()
-			}
-			delete(t.dpStreams, dp)
-		}
-	}
-}
-
-// OnStreamRequest is called once a request is received on a stream.
-// Returning an error will end processing and close the stream. OnStreamClosed will still be called.
-func (t *dataplaneSyncTracker) OnStreamRequest(streamID core_xds.StreamID, req util_xds.DiscoveryRequest) error {
-	t.RLock()
-	_, alreadyAssociated := t.streamsAssociation[streamID]
-	t.RUnlock()
-
-	if alreadyAssociated {
-		return nil
-	}
+	stopCh := make(chan struct{})
 
-	if proxyId, err := core_xds.ParseProxyIdFromString(req.NodeId()); err == nil {
-		dataplaneKey := proxyId.ToResourceKey()
-		t.Lock()
-		defer t.Unlock()
-		streams := t.dpStreams[dataplaneKey]
-		if streams.activeStreams == nil {
-			streams.activeStreams = map[core_xds.StreamID]bool{}
-		}
-		streams.activeStreams[streamID] = true
-		if streams.watchdogCancel == nil { // watchdog was not started yet
-			stopCh := make(chan struct{})
-			streams.watchdogCancel = func() {
-				close(stopCh)
-			}
-			// kick off watchdog for that Dataplane
-			go t.newDataplaneWatchdog(proxyId, streamID).Start(stopCh)
-			dataplaneSyncTrackerLog.V(1).Info("started Watchdog for a Dataplane", "streamid", streamID, "proxyId", proxyId, "dataplaneKey", dataplaneKey)
-		}
-		t.dpStreams[dataplaneKey] = streams
-		t.streamsAssociation[streamID] = dataplaneKey
-	} else {
-		dataplaneSyncTrackerLog.Error(err, "failed to parse Dataplane Id out of DiscoveryRequest", "streamid", streamID, "req", req)
+	t.watchdogs[dpKey] = func() {
+		dataplaneSyncTrackerLog.V(1).Info("stopping Watchdog for a Dataplane", "dpKey", dpKey, "streamID", streamID)
+		close(stopCh)
 	}
-
+	dataplaneSyncTrackerLog.V(1).Info("starting Watchdog for a Dataplane", "dpKey", dpKey, "streamID", streamID)
+	go t.newDataplaneWatchdog(dpKey).Start(stopCh)
 	return nil
 }
 
-// OnStreamResponse is called immediately prior to sending a response on a stream.
-func (t *dataplaneSyncTracker) OnStreamResponse(streamID core_xds.StreamID, req util_xds.DiscoveryRequest, resp util_xds.DiscoveryResponse) {
+func (t *dataplaneSyncTracker) OnProxyDisconnected(_ core_xds.StreamID, dpKey core_model.ResourceKey) {
+	t.Lock()
+	defer t.Unlock()
+	if cancelFn := t.watchdogs[dpKey]; cancelFn != nil {
+		cancelFn()
+	}
+	delete(t.watchdogs, dpKey)
 }
diff --git a/pkg/xds/server/v3/components.go b/pkg/xds/server/v3/components.go
index 66052f0ae..d35ec7f76 100644
--- a/pkg/xds/server/v3/components.go
+++ b/pkg/xds/server/v3/components.go
@@ -53,11 +53,11 @@ func RegisterXDS(
 	callbacks := util_xds_v3.CallbacksChain{
 		util_xds_v3.NewControlPlaneIdCallbacks(rt.GetInstanceId()),
 		util_xds_v3.AdaptCallbacks(statsCallbacks),
-		util_xds_v3.AdaptCallbacks(connectionInfoTracker),
+		util_xds_v3.AdaptCallbacks(xds_callbacks.DataplaneCallbacksToXdsCallbacks(connectionInfoTracker)),
 		util_xds_v3.AdaptCallbacks(authCallbacks),
-		util_xds_v3.AdaptCallbacks(xds_callbacks.NewDataplaneSyncTracker(watchdogFactory.New)),
-		util_xds_v3.AdaptCallbacks(metadataTracker),
-		util_xds_v3.AdaptCallbacks(xds_callbacks.NewDataplaneLifecycle(rt.ResourceManager(), rt.ShutdownCh())),
+		util_xds_v3.AdaptCallbacks(xds_callbacks.DataplaneCallbacksToXdsCallbacks(xds_callbacks.NewDataplaneSyncTracker(watchdogFactory.New))),
+		util_xds_v3.AdaptCallbacks(xds_callbacks.DataplaneCallbacksToXdsCallbacks(metadataTracker)),
+		util_xds_v3.AdaptCallbacks(xds_callbacks.DataplaneCallbacksToXdsCallbacks(xds_callbacks.NewDataplaneLifecycle(rt.ResourceManager(), rt.ShutdownCh()))),
 		util_xds_v3.AdaptCallbacks(DefaultDataplaneStatusTracker(rt)),
 		util_xds_v3.AdaptCallbacks(xds_callbacks.NewNackBackoff(rt.Config().XdsServer.NACKBackoff)),
 		newResourceWarmingForcer(xdsContext.Cache(), xdsContext.Hasher()),
diff --git a/pkg/xds/sync/dataplane_proxy_builder.go b/pkg/xds/sync/dataplane_proxy_builder.go
index 7e359ab75..597e3a107 100644
--- a/pkg/xds/sync/dataplane_proxy_builder.go
+++ b/pkg/xds/sync/dataplane_proxy_builder.go
@@ -39,7 +39,7 @@ type DataplaneProxyBuilder struct {
 	apiVersion envoy.APIVersion
 }
 
-func (p *DataplaneProxyBuilder) build(key core_model.ResourceKey, streamId int64, meshCtx *xds_context.MeshContext) (*xds.Proxy, error) {
+func (p *DataplaneProxyBuilder) build(key core_model.ResourceKey, meshCtx *xds_context.MeshContext) (*xds.Proxy, error) {
 	ctx := context.Background()
 
 	dp, err := p.resolveDataplane(ctx, key)
@@ -61,7 +61,7 @@ func (p *DataplaneProxyBuilder) build(key core_model.ResourceKey, streamId int64
 		Id:         xds.FromResourceKey(key),
 		APIVersion: p.apiVersion,
 		Dataplane:  dp,
-		Metadata:   p.MetadataTracker.Metadata(streamId),
+		Metadata:   p.MetadataTracker.Metadata(key),
 		Routing:    *routing,
 		Policies:   *matchedPolicies,
 	}
diff --git a/pkg/xds/sync/dataplane_watchdog.go b/pkg/xds/sync/dataplane_watchdog.go
index 72a7c7a8e..f84ba2951 100644
--- a/pkg/xds/sync/dataplane_watchdog.go
+++ b/pkg/xds/sync/dataplane_watchdog.go
@@ -4,6 +4,7 @@ import (
 	"context"
 
 	"github.com/go-logr/logr"
+	"github.com/pkg/errors"
 
 	mesh_core "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	"github.com/kumahq/kuma/pkg/core/resources/store"
@@ -29,9 +30,8 @@ type DataplaneWatchdogDependencies struct {
 
 type DataplaneWatchdog struct {
 	DataplaneWatchdogDependencies
-	key      core_model.ResourceKey
-	streamId int64
-	log      logr.Logger
+	key core_model.ResourceKey
+	log logr.Logger
 
 	// state of watchdog
 	lastHash         string // last Mesh hash that was used to **successfully** generate Reconcile Envoy config
@@ -39,21 +39,24 @@ type DataplaneWatchdog struct {
 	proxyTypeSettled bool
 }
 
-func NewDataplaneWatchdog(deps DataplaneWatchdogDependencies, proxyId *core_xds.ProxyId, streamId int64) *DataplaneWatchdog {
+func NewDataplaneWatchdog(deps DataplaneWatchdogDependencies, dpKey core_model.ResourceKey) *DataplaneWatchdog {
 	return &DataplaneWatchdog{
 		DataplaneWatchdogDependencies: deps,
-		key:                           proxyId.ToResourceKey(),
-		streamId:                      streamId,
-		log:                           core.Log.WithValues("key", proxyId.ToResourceKey(), "streamID", streamId),
+		key:                           dpKey,
+		log:                           core.Log.WithValues("key", dpKey),
 		proxyTypeSettled:              false,
 	}
 }
 
 func (d *DataplaneWatchdog) Sync() error {
 	ctx := context.Background()
+	metadata := d.metadataTracker.Metadata(d.key)
+	if metadata == nil {
+		return errors.New("metadata cannot be nil")
+	}
 
 	if d.dpType == "" {
-		d.dpType = d.metadataTracker.Metadata(d.streamId).GetProxyType()
+		d.dpType = metadata.GetProxyType()
 	}
 	// backwards compatibility
 	if d.dpType == mesh_proto.DataplaneProxyType && !d.proxyTypeSettled {
@@ -102,11 +105,11 @@ func (d *DataplaneWatchdog) syncDataplane() error {
 	}
 	d.log.V(1).Info("snapshot hash updated, reconcile", "prev", d.lastHash, "current", snapshotHash)
 
-	envoyCtx, err := d.xdsContextBuilder.buildMeshedContext(d.streamId, d.key.Mesh, d.lastHash)
+	envoyCtx, err := d.xdsContextBuilder.buildMeshedContext(d.key, d.lastHash)
 	if err != nil {
 		return err
 	}
-	proxy, err := d.dataplaneProxyBuilder.build(d.key, d.streamId, &envoyCtx.Mesh)
+	proxy, err := d.dataplaneProxyBuilder.build(d.key, &envoyCtx.Mesh)
 	if err != nil {
 		return err
 	}
@@ -119,8 +122,8 @@ func (d *DataplaneWatchdog) syncDataplane() error {
 
 // syncIngress synces state of Ingress Dataplane. Notice that it does not use Mesh Hash yet because Ingress supports many Meshes.
 func (d *DataplaneWatchdog) syncIngress() error {
-	envoyCtx := d.xdsContextBuilder.buildContext(d.streamId)
-	proxy, err := d.ingressProxyBuilder.build(d.key, d.streamId)
+	envoyCtx := d.xdsContextBuilder.buildContext(d.key)
+	proxy, err := d.ingressProxyBuilder.build(d.key)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/xds/sync/dataplane_watchdog_factory.go b/pkg/xds/sync/dataplane_watchdog_factory.go
index e7b06eada..c5f3aded3 100644
--- a/pkg/xds/sync/dataplane_watchdog_factory.go
+++ b/pkg/xds/sync/dataplane_watchdog_factory.go
@@ -4,7 +4,7 @@ import (
 	"time"
 
 	"github.com/kumahq/kuma/pkg/core"
-	core_xds "github.com/kumahq/kuma/pkg/core/xds"
+	"github.com/kumahq/kuma/pkg/core/resources/model"
 	util_watchdog "github.com/kumahq/kuma/pkg/util/watchdog"
 	xds_metrics "github.com/kumahq/kuma/pkg/xds/metrics"
 )
@@ -28,9 +28,9 @@ func NewDataplaneWatchdogFactory(
 	}, nil
 }
 
-func (d *dataplaneWatchdogFactory) New(proxyId *core_xds.ProxyId, streamId int64) util_watchdog.Watchdog {
-	log := xdsServerLog.WithName("dataplane-sync-watchdog").WithValues("dataplaneKey", proxyId.ToResourceKey())
-	dataplaneWatchdog := NewDataplaneWatchdog(d.deps, proxyId, streamId)
+func (d *dataplaneWatchdogFactory) New(dpKey model.ResourceKey) util_watchdog.Watchdog {
+	log := xdsServerLog.WithName("dataplane-sync-watchdog").WithValues("dataplaneKey", dpKey)
+	dataplaneWatchdog := NewDataplaneWatchdog(d.deps, dpKey)
 	return &util_watchdog.SimpleWatchdog{
 		NewTicker: func() *time.Ticker {
 			return time.NewTicker(d.refreshInterval)
diff --git a/pkg/xds/sync/ingress_proxy_builder.go b/pkg/xds/sync/ingress_proxy_builder.go
index 54cf7edc6..199b863b9 100644
--- a/pkg/xds/sync/ingress_proxy_builder.go
+++ b/pkg/xds/sync/ingress_proxy_builder.go
@@ -23,7 +23,7 @@ type IngressProxyBuilder struct {
 	apiVersion envoy.APIVersion
 }
 
-func (p *IngressProxyBuilder) build(key core_model.ResourceKey, streamId int64) (*xds.Proxy, error) {
+func (p *IngressProxyBuilder) build(key core_model.ResourceKey) (*xds.Proxy, error) {
 	ctx := context.Background()
 
 	zoneIngress, err := p.getZoneIngress(key)
@@ -50,7 +50,7 @@ func (p *IngressProxyBuilder) build(key core_model.ResourceKey, streamId int64)
 		Id:          xds.FromResourceKey(key),
 		APIVersion:  p.apiVersion,
 		ZoneIngress: zoneIngress,
-		Metadata:    p.MetadataTracker.Metadata(streamId),
+		Metadata:    p.MetadataTracker.Metadata(key),
 		Routing:     *routing,
 	}
 	return proxy, nil
diff --git a/pkg/xds/sync/interfaces.go b/pkg/xds/sync/interfaces.go
index 576801f2c..4b41647ba 100644
--- a/pkg/xds/sync/interfaces.go
+++ b/pkg/xds/sync/interfaces.go
@@ -1,17 +1,18 @@
 package sync
 
 import (
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_xds "github.com/kumahq/kuma/pkg/core/xds"
 	util_watchdog "github.com/kumahq/kuma/pkg/util/watchdog"
 	xds_context "github.com/kumahq/kuma/pkg/xds/context"
 )
 
 type DataplaneMetadataTracker interface {
-	Metadata(streamID core_xds.StreamID) *core_xds.DataplaneMetadata
+	Metadata(dpKey core_model.ResourceKey) *core_xds.DataplaneMetadata
 }
 
 type ConnectionInfoTracker interface {
-	ConnectionInfo(streamID core_xds.StreamID) xds_context.ConnectionInfo
+	ConnectionInfo(dpKey core_model.ResourceKey) *xds_context.ConnectionInfo
 }
 
 // SnapshotReconciler reconciles Envoy XDS configuration (Snapshot) by executing all generators (pkg/xds/generator)
@@ -22,5 +23,5 @@ type SnapshotReconciler interface {
 
 // DataplaneWatchdogFactory returns a Watchdog that creates a new XdsContext and Proxy and executes SnapshotReconciler if there is any change
 type DataplaneWatchdogFactory interface {
-	New(proxyId *core_xds.ProxyId, streamId int64) util_watchdog.Watchdog
+	New(dpKey core_model.ResourceKey) util_watchdog.Watchdog
 }
diff --git a/pkg/xds/sync/xds_context_builder.go b/pkg/xds/sync/xds_context_builder.go
index 091293085..37dee40ff 100644
--- a/pkg/xds/sync/xds_context_builder.go
+++ b/pkg/xds/sync/xds_context_builder.go
@@ -3,13 +3,12 @@ package sync
 import (
 	"context"
 
-	"github.com/kumahq/kuma/pkg/envoy/admin"
-
 	"github.com/kumahq/kuma/pkg/core/dns/lookup"
 	core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
 	"github.com/kumahq/kuma/pkg/core/resources/manager"
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	core_store "github.com/kumahq/kuma/pkg/core/resources/store"
+	"github.com/kumahq/kuma/pkg/envoy/admin"
 	xds_context "github.com/kumahq/kuma/pkg/xds/context"
 	xds_topology "github.com/kumahq/kuma/pkg/xds/topology"
 )
@@ -39,16 +38,16 @@ func newXDSContextBuilder(
 	}
 }
 
-func (c *xdsContextBuilder) buildMeshedContext(streamId int64, meshName string, meshHash string) (*xds_context.Context, error) {
+func (c *xdsContextBuilder) buildMeshedContext(dpKey core_model.ResourceKey, meshHash string) (*xds_context.Context, error) {
 	ctx := context.Background()
-	xdsCtx := c.buildContext(streamId)
+	xdsCtx := c.buildContext(dpKey)
 
 	mesh := core_mesh.NewMeshResource()
-	if err := c.resManager.Get(ctx, mesh, core_store.GetByKey(meshName, core_model.NoMesh)); err != nil {
+	if err := c.resManager.Get(ctx, mesh, core_store.GetByKey(dpKey.Mesh, core_model.NoMesh)); err != nil {
 		return nil, err
 	}
 
-	dataplanes, err := xds_topology.GetDataplanes(syncLog, context.Background(), c.resManager, c.lookupIP, meshName)
+	dataplanes, err := xds_topology.GetDataplanes(syncLog, context.Background(), c.resManager, c.lookupIP, dpKey.Mesh)
 	if err != nil {
 		return nil, err
 	}
@@ -60,10 +59,10 @@ func (c *xdsContextBuilder) buildMeshedContext(streamId int64, meshName string,
 	return xdsCtx, nil
 }
 
-func (c *xdsContextBuilder) buildContext(streamId int64) *xds_context.Context {
+func (c *xdsContextBuilder) buildContext(dpKey core_model.ResourceKey) *xds_context.Context {
 	return &xds_context.Context{
 		ControlPlane:     c.cpContext,
-		ConnectionInfo:   c.connectionInfoTracker.ConnectionInfo(streamId),
+		ConnectionInfo:   *c.connectionInfoTracker.ConnectionInfo(dpKey), // todo handle nil
 		Mesh:             xds_context.MeshContext{},
 		EnvoyAdminClient: c.envoyAdminClient,
 	}


Test patch:
diff --git a/app/kumactl/cmd/completion/testdata/bash.golden b/app/kumactl/cmd/completion/testdata/bash.golden
index 6ea47a745..8002d6421 100644
--- a/app/kumactl/cmd/completion/testdata/bash.golden
+++ b/app/kumactl/cmd/completion/testdata/bash.golden
@@ -2914,8 +2914,6 @@ _kumactl_install_transparent-proxy()
     two_word_flags+=("--kuma-dp-user")
     local_nonpersistent_flags+=("--kuma-dp-user")
     local_nonpersistent_flags+=("--kuma-dp-user=")
-    flags+=("--modify-iptables")
-    local_nonpersistent_flags+=("--modify-iptables")
     flags+=("--redirect-all-dns-traffic")
     local_nonpersistent_flags+=("--redirect-all-dns-traffic")
     flags+=("--redirect-dns")
diff --git a/app/kumactl/cmd/install/install_transparent_proxy_test.go b/app/kumactl/cmd/install/install_transparent_proxy_test.go
index d5640dccc..37735a41e 100644
--- a/app/kumactl/cmd/install/install_transparent_proxy_test.go
+++ b/app/kumactl/cmd/install/install_transparent_proxy_test.go
@@ -94,4 +94,29 @@ var _ = Describe("kumactl install tracing", func() {
 			goldenFile: "install-transparent-proxy.overrides.golden.txt",
 		}),
 	)
+
+	DescribeTable("should return error",
+		func(given testCase) {
+			// given
+			rootCmd := cmd.DefaultRootCmd()
+			rootCmd.SetArgs(append([]string{"install", "transparent-proxy", "--dry-run"}, given.extraArgs...))
+			rootCmd.SetOut(stdout)
+			rootCmd.SetErr(stderr)
+
+			// when
+			err := rootCmd.Execute()
+			// then
+			Expect(err).To(HaveOccurred())
+			// and
+			Expect(stderr.String()).To(ContainSubstring("one of --redirect-dns or --redirect-all-dns-traffic should be specified"))
+		},
+		Entry("should generate defaults with username", testCase{
+			extraArgs: []string{
+				"--kuma-dp-user", "root",
+				"--redirect-dns",
+				"--redirect-all-dns-traffic",
+			},
+			goldenFile: "install-transparent-proxy.defaults.golden.txt",
+		}),
+	)
 })
diff --git a/pkg/xds/server/callbacks/dataplane_callbacks_test.go b/pkg/xds/server/callbacks/dataplane_callbacks_test.go
new file mode 100644
index 000000000..536d59d2f
--- /dev/null
+++ b/pkg/xds/server/callbacks/dataplane_callbacks_test.go
@@ -0,0 +1,108 @@
+package callbacks_test
+
+import (
+	"context"
+
+	envoy_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
+	envoy_sd "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"google.golang.org/protobuf/types/known/structpb"
+
+	core_xds "github.com/kumahq/kuma/pkg/core/xds"
+	util_xds_v3 "github.com/kumahq/kuma/pkg/util/xds/v3"
+
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
+	. "github.com/kumahq/kuma/pkg/xds/server/callbacks"
+)
+
+type countingDpCallbacks struct {
+	OnProxyConnectedCounter    int
+	OnProxyReconnectedCounter  int
+	OnProxyDisconnectedCounter int
+}
+
+func (c *countingDpCallbacks) OnProxyConnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, metadata core_xds.DataplaneMetadata) error {
+	c.OnProxyConnectedCounter++
+	return nil
+}
+
+func (c *countingDpCallbacks) OnProxyReconnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey, ctx context.Context, metadata core_xds.DataplaneMetadata) error {
+	c.OnProxyReconnectedCounter++
+	return nil
+}
+
+func (c *countingDpCallbacks) OnProxyDisconnected(streamID core_xds.StreamID, dpKey core_model.ResourceKey) {
+	c.OnProxyDisconnectedCounter++
+}
+
+var _ DataplaneCallbacks = &countingDpCallbacks{}
+
+var _ = Describe("Dataplane Callbacks", func() {
+
+	countingCallbacks := &countingDpCallbacks{}
+	callbacks := util_xds_v3.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(countingCallbacks))
+
+	req := envoy_sd.DiscoveryRequest{
+		Node: &envoy_core.Node{
+			Id: "default.example",
+			Metadata: &structpb.Struct{
+				Fields: map[string]*structpb.Value{
+					"dataplane.token": &structpb.Value{
+						Kind: &structpb.Value_StringValue{
+							StringValue: "token",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	It("should call DataplaneCallbacks correctly", func() {
+		// when only OnStreamOpen is called
+		err := callbacks.OnStreamOpen(context.Background(), 1, "")
+		Expect(err).ToNot(HaveOccurred())
+
+		// then OnProxyConnected and OnProxyReconnected is not yet called
+		Expect(countingCallbacks.OnProxyConnectedCounter).To(Equal(0))
+		Expect(countingCallbacks.OnProxyReconnectedCounter).To(Equal(0))
+
+		// when OnStreamRequest is sent
+		err = callbacks.OnStreamRequest(1, &req)
+		Expect(err).ToNot(HaveOccurred())
+
+		// then only OnProxyConnected should be called
+		Expect(countingCallbacks.OnProxyConnectedCounter).To(Equal(1))
+		Expect(countingCallbacks.OnProxyReconnectedCounter).To(Equal(0))
+
+		// when next OnStreamRequest on the same stream is sent
+		err = callbacks.OnStreamRequest(1, &req)
+		Expect(err).ToNot(HaveOccurred())
+
+		// then OnProxyReconnected and OnProxyReconnected are not called again, they should be only called on the first DiscoveryRequest
+		Expect(countingCallbacks.OnProxyConnectedCounter).To(Equal(1))
+		Expect(countingCallbacks.OnProxyReconnectedCounter).To(Equal(0))
+
+		// when next stream for given data plane proxy is connected
+		err = callbacks.OnStreamOpen(context.Background(), 2, "")
+		Expect(err).ToNot(HaveOccurred())
+		err = callbacks.OnStreamRequest(2, &req)
+		Expect(err).ToNot(HaveOccurred())
+
+		// then only OnProxyReconnected should be called
+		Expect(countingCallbacks.OnProxyConnectedCounter).To(Equal(1))
+		Expect(countingCallbacks.OnProxyReconnectedCounter).To(Equal(1))
+
+		// when first stream is closed
+		callbacks.OnStreamClosed(1)
+
+		// then OnProxyDisconnected should not yet be called
+		Expect(countingCallbacks.OnProxyDisconnectedCounter).To(Equal(0))
+
+		// when last stream is closed
+		callbacks.OnStreamClosed(2)
+
+		// then OnProxyDisconnected should be called
+		Expect(countingCallbacks.OnProxyDisconnectedCounter).To(Equal(1))
+	})
+})
diff --git a/pkg/xds/server/callbacks/dataplane_lifecycle_test.go b/pkg/xds/server/callbacks/dataplane_lifecycle_test.go
index 42ff50a84..58b68ec1e 100644
--- a/pkg/xds/server/callbacks/dataplane_lifecycle_test.go
+++ b/pkg/xds/server/callbacks/dataplane_lifecycle_test.go
@@ -24,7 +24,6 @@ import (
 var _ = Describe("Dataplane Lifecycle", func() {
 
 	var resManager core_manager.ResourceManager
-	var dpLifecycle *DataplaneLifecycle
 	var callbacks envoy_server.Callbacks
 	var shutdown chan struct{}
 
@@ -32,8 +31,7 @@ var _ = Describe("Dataplane Lifecycle", func() {
 		store := memory.NewStore()
 		resManager = core_manager.NewResourceManager(store)
 		shutdown = make(chan struct{})
-		dpLifecycle = NewDataplaneLifecycle(resManager, shutdown)
-		callbacks = util_xds_v2.AdaptCallbacks(dpLifecycle)
+		callbacks = util_xds_v2.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(NewDataplaneLifecycle(resManager, shutdown)))
 
 		err := resManager.Create(context.Background(), core_mesh.NewMeshResource(), core_store.CreateByKey(core_model.DefaultMesh, core_model.NoMesh))
 		Expect(err).ToNot(HaveOccurred())
@@ -84,7 +82,7 @@ var _ = Describe("Dataplane Lifecycle", func() {
 		Expect(err).ToNot(HaveOccurred())
 
 		// when
-		dpLifecycle.OnStreamClosed(streamId)
+		callbacks.OnStreamClosed(streamId)
 
 		// then dataplane should be deleted
 		err = resManager.Get(context.Background(), core_mesh.NewDataplaneResource(), core_store.GetByKey("backend-01", "default"))
@@ -130,7 +128,7 @@ var _ = Describe("Dataplane Lifecycle", func() {
 		Expect(err).ToNot(HaveOccurred())
 
 		// when
-		dpLifecycle.OnStreamClosed(streamId)
+		callbacks.OnStreamClosed(streamId)
 
 		// then DP is not deleted because it was not carried in metadata
 		err = resManager.Get(context.Background(), core_mesh.NewDataplaneResource(), core_store.GetByKey("backend-01", "default"))
@@ -180,7 +178,7 @@ var _ = Describe("Dataplane Lifecycle", func() {
 
 		close(shutdown)
 		// when
-		dpLifecycle.OnStreamClosed(streamId)
+		callbacks.OnStreamClosed(streamId)
 
 		// then DP is not deleted because Kuma CP was shutting down
 		err = resManager.Get(context.Background(), core_mesh.NewDataplaneResource(), core_store.GetByKey("backend-01", "default"))
diff --git a/pkg/xds/server/callbacks/dataplane_metadata_tracker_test.go b/pkg/xds/server/callbacks/dataplane_metadata_tracker_test.go
index 265757849..a2086628f 100644
--- a/pkg/xds/server/callbacks/dataplane_metadata_tracker_test.go
+++ b/pkg/xds/server/callbacks/dataplane_metadata_tracker_test.go
@@ -7,7 +7,7 @@ import (
 	. "github.com/onsi/gomega"
 	"google.golang.org/protobuf/types/known/structpb"
 
-	"github.com/kumahq/kuma/pkg/core/xds"
+	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	util_xds_v2 "github.com/kumahq/kuma/pkg/util/xds/v2"
 	. "github.com/kumahq/kuma/pkg/xds/server/callbacks"
 )
@@ -15,8 +15,12 @@ import (
 var _ = Describe("Dataplane Metadata Tracker", func() {
 
 	tracker := NewDataplaneMetadataTracker()
-	callbacks := util_xds_v2.AdaptCallbacks(tracker)
+	callbacks := util_xds_v2.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(tracker))
 
+	dpKey := core_model.ResourceKey{
+		Mesh: "default",
+		Name: "example",
+	}
 	req := v2.DiscoveryRequest{
 		Node: &envoy_core.Node{
 			Id: "default.example",
@@ -41,17 +45,17 @@ var _ = Describe("Dataplane Metadata Tracker", func() {
 		Expect(err).ToNot(HaveOccurred())
 
 		// when
-		metadata := tracker.Metadata(streamId)
+		metadata := tracker.Metadata(dpKey)
 
 		// then
 		Expect(metadata.GetDataplaneToken()).To(Equal("token"))
 
 		// when
-		tracker.OnStreamClosed(streamId)
+		callbacks.OnStreamClosed(streamId)
 
 		// then metadata should be deleted
-		metadata = tracker.Metadata(streamId)
-		Expect(metadata).To(Equal(&xds.DataplaneMetadata{}))
+		metadata = tracker.Metadata(dpKey)
+		Expect(metadata).To(BeNil())
 	})
 
 	It("should track metadata with empty Node in consecutive DiscoveryRequests", func() {
@@ -68,7 +72,7 @@ var _ = Describe("Dataplane Metadata Tracker", func() {
 		Expect(err).ToNot(HaveOccurred())
 
 		// when
-		metadata := tracker.Metadata(streamId)
+		metadata := tracker.Metadata(dpKey)
 
 		// then
 		Expect(metadata.GetDataplaneToken()).To(Equal("token"))
diff --git a/pkg/xds/server/callbacks/dataplane_sync_tracker_test.go b/pkg/xds/server/callbacks/dataplane_sync_tracker_test.go
index c179aebf9..1b3819e49 100644
--- a/pkg/xds/server/callbacks/dataplane_sync_tracker_test.go
+++ b/pkg/xds/server/callbacks/dataplane_sync_tracker_test.go
@@ -8,8 +8,6 @@ import (
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 
-	core_xds "github.com/kumahq/kuma/pkg/core/xds"
-
 	core_model "github.com/kumahq/kuma/pkg/core/resources/model"
 	"github.com/kumahq/kuma/pkg/test"
 	util_watchdog "github.com/kumahq/kuma/pkg/util/watchdog"
@@ -25,7 +23,7 @@ var _ = Describe("Sync", func() {
 	Describe("dataplaneSyncTracker", func() {
 		It("should not fail when ADS stream is closed before Watchdog is even created", func() {
 			// setup
-			tracker := NewDataplaneSyncTracker(nil)
+			tracker := DataplaneCallbacksToXdsCallbacks(NewDataplaneSyncTracker(nil))
 
 			// given
 			ctx := context.Background()
@@ -49,7 +47,7 @@ var _ = Describe("Sync", func() {
 		It("should not fail when Envoy presents invalid Node ID", func() {
 			// setup
 			tracker := NewDataplaneSyncTracker(nil)
-			callbacks := util_xds_v2.AdaptCallbacks(tracker)
+			callbacks := util_xds_v2.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(tracker))
 
 			// given
 			ctx := context.Background()
@@ -81,14 +79,14 @@ var _ = Describe("Sync", func() {
 			watchdogCh := make(chan core_model.ResourceKey)
 
 			// setup
-			tracker := NewDataplaneSyncTracker(func(proxyId *core_xds.ProxyId, streamId int64) util_watchdog.Watchdog {
+			tracker := NewDataplaneSyncTracker(func(key core_model.ResourceKey) util_watchdog.Watchdog {
 				return WatchdogFunc(func(stop <-chan struct{}) {
-					watchdogCh <- proxyId.ToResourceKey()
+					watchdogCh <- key
 					<-stop
 					close(watchdogCh)
 				})
 			})
-			callbacks := util_xds_v2.AdaptCallbacks(tracker)
+			callbacks := util_xds_v2.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(tracker))
 
 			// given
 			ctx := context.Background()
@@ -138,14 +136,14 @@ var _ = Describe("Sync", func() {
 		It("should start only one watchdog per dataplane", func() {
 			// setup
 			var activeWatchdogs int32
-			tracker := NewDataplaneSyncTracker(func(proxyId *core_xds.ProxyId, streamId int64) util_watchdog.Watchdog {
+			tracker := NewDataplaneSyncTracker(func(key core_model.ResourceKey) util_watchdog.Watchdog {
 				return WatchdogFunc(func(stop <-chan struct{}) {
 					atomic.AddInt32(&activeWatchdogs, 1)
 					<-stop
 					atomic.AddInt32(&activeWatchdogs, -1)
 				})
 			})
-			callbacks := util_xds_v2.AdaptCallbacks(tracker)
+			callbacks := util_xds_v2.AdaptCallbacks(DataplaneCallbacksToXdsCallbacks(tracker))
 
 			// when one stream for backend-01 is connected and request is sent
 			streamID := int64(1)