Repository: openservicemesh/osm
Pull request #5185 (2022-10-03 20:01:02)

Merge the informer collection into the k8s client
This PR merges the informer collection into the k8s client, which will allow us to move towards abstracting the fact that the k8s client even uses an informer cache in the first place.

Part of [#5099](https://github.com/openservicemesh/osm/issues/5099)
Closes [#4863](https://github.com/openservicemesh/osm/issues/4863)

Signed-off-by: Sean Teeling <seanteeling@microsoft.com>

codecov-commenter: # [Codecov](https://codecov.io/gh/openservicemesh/osm/pull/5185?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#5185](https://codecov.io/gh/openservicemesh/osm/pull/5185?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (f2f9444) into [main](https://codecov.io/gh/openservicemesh/osm/commit/8cf4c941fb27470bd37acf2711d91e9c175606ec?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (8cf4c94) will **decrease** coverage by `0.53%`.
> The diff coverage is `55.25%`.

```diff
@@            Coverage Diff             @@
##             main    #5185      +/-   ##
==========================================
- Coverage   67.93%   67.40%   -0.54%     
==========================================
  Files         197      199       +2     
  Lines       16002    16207     +205     
==========================================
+ Hits        10871    10924      +53     
- Misses       5078     5230     +152     
  Partials       53       53              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `67.40% <55.25%> (-0.54%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/openservicemesh/osm/pull/5185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [cmd/osm-controller/osm-controller.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-Y21kL29zbS1jb250cm9sbGVyL29zbS1jb250cm9sbGVyLmdv) | `18.01% <0.00%> (+0.08%)` | :arrow_up: |
| [pkg/catalog/mock\_catalog\_generated.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NhdGFsb2cvbW9ja19jYXRhbG9nX2dlbmVyYXRlZC5nbw==) | `0.00% <0.00%> (ø)` | |
| [pkg/certificate/certificate.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NlcnRpZmljYXRlL2NlcnRpZmljYXRlLmdv) | `82.97% <ø> (ø)` | |
| [pkg/certificate/fake\_manager.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NlcnRpZmljYXRlL2Zha2VfbWFuYWdlci5nbw==) | `75.53% <0.00%> (-4.06%)` | :arrow_down: |
| [pkg/certificate/providers/compat.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NlcnRpZmljYXRlL3Byb3ZpZGVycy9jb21wYXQuZ28=) | `62.50% <0.00%> (-8.93%)` | :arrow_down: |
| [pkg/certificate/types.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NlcnRpZmljYXRlL3R5cGVzLmdv) | `100.00% <ø> (ø)` | |
| [pkg/k8s/mock\_controller\_generated.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2s4cy9tb2NrX2NvbnRyb2xsZXJfZ2VuZXJhdGVkLmdv) | `0.00% <0.00%> (-3.44%)` | :arrow_down: |
| [pkg/k8s/types.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2s4cy90eXBlcy5nbw==) | `100.00% <ø> (ø)` | |
| [pkg/utils/mesh\_config.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3V0aWxzL21lc2hfY29uZmlnLmdv) | `0.00% <0.00%> (ø)` | |
| [pkg/certificate/mrc\_reconciler.go](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL2NlcnRpZmljYXRlL21yY19yZWNvbmNpbGVyLmdv) | `13.63% <13.63%> (ø)` | |
| ... and [12 more](https://codecov.io/gh/openservicemesh/osm/pull/5185/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)


Patch:
diff --git a/cmd/osm-controller/osm-controller.go b/cmd/osm-controller/osm-controller.go
index bb39d486..400e788a 100644
--- a/cmd/osm-controller/osm-controller.go
+++ b/cmd/osm-controller/osm-controller.go
@@ -46,7 +46,6 @@ import (
 	"github.com/openservicemesh/osm/pkg/ingress"
 	"github.com/openservicemesh/osm/pkg/k8s"
 	"github.com/openservicemesh/osm/pkg/k8s/events"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/metricsstore"
@@ -188,18 +187,19 @@ func main() {
 	smiTrafficSpecClientSet := smiTrafficSpecClient.NewForConfigOrDie(kubeConfig)
 	smiTrafficTargetClientSet := smiAccessClient.NewForConfigOrDie(kubeConfig)
 
-	informerCollection, err := informers.NewInformerCollection(meshName, stop,
-		informers.WithKubeClient(kubeClient),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-		informers.WithConfigClient(configClient, osmMeshConfigName, osmNamespace),
-		informers.WithPolicyClient(policyClient),
-		informers.WithMCSClient(mcsClient),
+	k8sClient, err := k8s.NewClient(osmNamespace, osmMeshConfigName, msgBroker,
+		k8s.WithKubeClient(kubeClient, meshName),
+		k8s.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		k8s.WithConfigClient(configClient),
+		k8s.WithPolicyClient(policyClient),
+		k8s.WithMCSClient(mcsClient),
 	)
+
 	if err != nil {
-		events.GenericEventRecorder().FatalEvent(err, events.InitializationError, "Error creating informer collection")
+		events.GenericEventRecorder().FatalEvent(err, events.InitializationError, "Error creating kubernetes client")
 	}
 
-	k8sClient := k8s.NewClient(osmNamespace, osmMeshConfigName, informerCollection, kubeClient, policyClient, configClient, mcsClient, msgBroker)
+	computeClient := kube.NewClient(k8sClient)
 
 	certOpts, err := getCertOptions()
 	if err != nil {
@@ -210,22 +210,20 @@ func main() {
 	var certManager *certificate.Manager
 	if enableMeshRootCertificate {
 		certManager, err = providers.NewCertificateManagerFromMRC(ctx, kubeClient, kubeConfig, osmNamespace,
-			certOpts, k8sClient, informerCollection, 5*time.Second)
+			certOpts, computeClient, 5*time.Second)
 		if err != nil {
 			events.GenericEventRecorder().FatalEvent(err, events.InvalidCertificateManager,
 				"Error fetching certificate manager of kind %s from MRC", certProviderKind)
 		}
 	} else {
 		certManager, err = providers.NewCertificateManager(ctx, kubeClient, kubeConfig, osmNamespace,
-			certOpts, k8sClient, 5*time.Second, trustDomain)
+			certOpts, computeClient, 5*time.Second, trustDomain)
 		if err != nil {
 			events.GenericEventRecorder().FatalEvent(err, events.InvalidCertificateManager,
 				"Error fetching certificate manager of kind %s", certProviderKind)
 		}
 	}
 
-	computeClient := kube.NewClient(k8sClient)
-
 	ingress.Initialize(kubeClient, k8sClient, stop, certManager, msgBroker)
 
 	meshCatalog := catalog.NewMeshCatalog(
diff --git a/cmd/osm-injector/osm-injector.go b/cmd/osm-injector/osm-injector.go
index 93111b24..14cc410e 100644
--- a/cmd/osm-injector/osm-injector.go
+++ b/cmd/osm-injector/osm-injector.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"net/http"
 	"os"
+	"time"
 
 	smiAccessClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned"
 	smiTrafficSpecClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned"
@@ -37,7 +38,6 @@ import (
 	"github.com/openservicemesh/osm/pkg/injector"
 	"github.com/openservicemesh/osm/pkg/k8s"
 	"github.com/openservicemesh/osm/pkg/k8s/events"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/metricsstore"
@@ -188,20 +188,19 @@ func main() {
 	smiTrafficSpecClientSet := smiTrafficSpecClient.NewForConfigOrDie(kubeConfig)
 	smiTrafficTargetClientSet := smiAccessClient.NewForConfigOrDie(kubeConfig)
 
-	informerCollection, err := informers.NewInformerCollection(meshName, stop,
-		informers.WithKubeClient(kubeClient),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-		informers.WithConfigClient(configClient, osmMeshConfigName, osmNamespace),
-		informers.WithPolicyClient(policyClient),
-		informers.WithMCSClient(mcsClient),
+	// Initialize kubernetes.Controller to watch kubernetes resources
+	kubeController, err := k8s.NewClient(osmNamespace, osmMeshConfigName, msgBroker,
+		k8s.WithKubeClient(kubeClient, meshName),
+		k8s.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		k8s.WithConfigClient(configClient),
+		k8s.WithPolicyClient(policyClient),
+		k8s.WithMCSClient(mcsClient),
 	)
 
 	if err != nil {
-		events.GenericEventRecorder().FatalEvent(err, events.InitializationError, "Error creating informer collection")
+		events.GenericEventRecorder().FatalEvent(err, events.InitializationError, "Error creating kubernetes client")
 	}
 
-	// Initialize kubernetes.Controller to watch kubernetes resources
-	kubeController := k8s.NewClient(osmNamespace, osmMeshConfigName, informerCollection, kubeClient, policyClient, configClient, mcsClient, msgBroker, informers.InformerKeyNamespace)
 	computeClient := kube.NewClient(kubeController)
 
 	certOpts, err := getCertOptions()
@@ -213,14 +212,14 @@ func main() {
 	var certManager *certificate.Manager
 	if enableMeshRootCertificate {
 		certManager, err = providers.NewCertificateManagerFromMRC(ctx, kubeClient, kubeConfig, osmNamespace,
-			certOpts, kubeController, informerCollection, constants.CertCheckInterval)
+			certOpts, computeClient, 5*time.Second)
 		if err != nil {
 			events.GenericEventRecorder().FatalEvent(err, events.InvalidCertificateManager,
 				"Error initializing certificate manager of kind %s from MRC", certProviderKind)
 		}
 	} else {
 		certManager, err = providers.NewCertificateManager(ctx, kubeClient, kubeConfig, osmNamespace,
-			certOpts, kubeController, constants.CertCheckInterval, trustDomain)
+			certOpts, computeClient, constants.CertCheckInterval, trustDomain)
 		if err != nil {
 			events.GenericEventRecorder().FatalEvent(err, events.InvalidCertificateManager,
 				"Error initializing certificate manager of kind %s", certProviderKind)
diff --git a/pkg/catalog/mock_catalog_generated.go b/pkg/catalog/mock_catalog_generated.go
index df20b626..6189aed5 100644
--- a/pkg/catalog/mock_catalog_generated.go
+++ b/pkg/catalog/mock_catalog_generated.go
@@ -20,6 +20,7 @@ import (
 	v1alpha4 "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha4"
 	v1alpha20 "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
 	types "k8s.io/apimachinery/pkg/types"
+	cache "k8s.io/client-go/tools/cache"
 	v1alpha10 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
 )
 
@@ -46,6 +47,18 @@ func (m *MockMeshCataloger) EXPECT() *MockMeshCatalogerMockRecorder {
 	return m.recorder
 }
 
+// AddMeshRootCertificateEventHandler mocks base method.
+func (m *MockMeshCataloger) AddMeshRootCertificateEventHandler(arg0 cache.ResourceEventHandler) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "AddMeshRootCertificateEventHandler", arg0)
+}
+
+// AddMeshRootCertificateEventHandler indicates an expected call of AddMeshRootCertificateEventHandler.
+func (mr *MockMeshCatalogerMockRecorder) AddMeshRootCertificateEventHandler(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMeshRootCertificateEventHandler", reflect.TypeOf((*MockMeshCataloger)(nil).AddMeshRootCertificateEventHandler), arg0)
+}
+
 // GetEgressClusterConfigs mocks base method.
 func (m *MockMeshCataloger) GetEgressClusterConfigs(arg0 identity.ServiceIdentity) ([]*trafficpolicy.EgressClusterConfig, error) {
 	m.ctrl.T.Helper()
diff --git a/pkg/certificate/fake_manager.go b/pkg/certificate/fake_manager.go
index e6cad570..5c5a669e 100644
--- a/pkg/certificate/fake_manager.go
+++ b/pkg/certificate/fake_manager.go
@@ -26,8 +26,8 @@ func (c *fakeMRCClient) GetCertIssuerForMRC(mrc *v1alpha2.MeshRootCertificate) (
 	return &fakeIssuer{}, pem.RootCertificate("rootCA"), nil
 }
 
-// List returns the single, pre-generated MRC. It is intended to implement the certificate.MRCClient interface.
-func (c *fakeMRCClient) List() ([]*v1alpha2.MeshRootCertificate, error) {
+// ListMeshRootCertificates returns the single, pre-generated MRC. It is intended to implement the certificate.MRCClient interface.
+func (c *fakeMRCClient) ListMeshRootCertificates() ([]*v1alpha2.MeshRootCertificate, error) {
 	// return single empty object in the list.
 	return []*v1alpha2.MeshRootCertificate{{
 		Spec: v1alpha2.MeshRootCertificateSpec{
diff --git a/pkg/certificate/providers/compat.go b/pkg/certificate/providers/compat.go
index e4f3ddeb..100ea0d2 100644
--- a/pkg/certificate/providers/compat.go
+++ b/pkg/certificate/providers/compat.go
@@ -8,8 +8,8 @@ import (
 	"github.com/openservicemesh/osm/pkg/certificate"
 )
 
-// List returns the single, pre-generated MRC. It is intended to implement the certificate.MRCClient interface.
-func (c *MRCCompatClient) List() ([]*v1alpha2.MeshRootCertificate, error) {
+// ListMeshRootCertificates returns the single, pre-generated MRC. It is intended to implement the certificate.MRCClient interface.
+func (c *MRCCompatClient) ListMeshRootCertificates() ([]*v1alpha2.MeshRootCertificate, error) {
 	return []*v1alpha2.MeshRootCertificate{
 		c.mrc,
 	}, nil
diff --git a/pkg/certificate/providers/config.go b/pkg/certificate/providers/config.go
index 341d0827..1294735b 100644
--- a/pkg/certificate/providers/config.go
+++ b/pkg/certificate/providers/config.go
@@ -20,9 +20,8 @@ import (
 	"github.com/openservicemesh/osm/pkg/certificate/providers/certmanager"
 	"github.com/openservicemesh/osm/pkg/certificate/providers/tresor"
 	"github.com/openservicemesh/osm/pkg/certificate/providers/vault"
+	"github.com/openservicemesh/osm/pkg/compute"
 	"github.com/openservicemesh/osm/pkg/constants"
-	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/utils"
 )
 
@@ -45,7 +44,7 @@ var getCA = func(i certificate.Issuer) (pem.RootCertificate, error) {
 // NewCertificateManager returns a new certificate manager with a MRC compat client.
 // TODO(4713): Remove and use NewCertificateManagerFromMRC
 func NewCertificateManager(ctx context.Context, kubeClient kubernetes.Interface, kubeConfig *rest.Config,
-	providerNamespace string, option Options, kubeController k8s.Controller, checkInterval time.Duration, trustDomain string) (*certificate.Manager, error) {
+	providerNamespace string, option Options, computeClient compute.Interface, checkInterval time.Duration, trustDomain string) (*certificate.Manager, error) {
 	if err := option.Validate(); err != nil {
 		return nil, err
 	}
@@ -54,7 +53,7 @@ func NewCertificateManager(ctx context.Context, kubeClient kubernetes.Interface,
 		MRCProviderGenerator: MRCProviderGenerator{
 			kubeClient:      kubeClient,
 			kubeConfig:      kubeConfig,
-			KeyBitSize:      utils.GetCertKeyBitSize(kubeController.GetMeshConfig()),
+			KeyBitSize:      utils.GetCertKeyBitSize(computeClient.GetMeshConfig()),
 			caExtractorFunc: getCA,
 		},
 		mrc: &v1alpha2.MeshRootCertificate{
@@ -107,27 +106,27 @@ func NewCertificateManager(ctx context.Context, kubeClient kubernetes.Interface,
 	return certificate.NewManager(
 		ctx,
 		mrcClient,
-		func() time.Duration { return utils.GetServiceCertValidityPeriod(kubeController.GetMeshConfig()) },
-		func() time.Duration { return utils.GetIngressGatewayCertValidityPeriod(kubeController.GetMeshConfig()) },
+		func() time.Duration { return utils.GetServiceCertValidityPeriod(computeClient.GetMeshConfig()) },
+		func() time.Duration { return utils.GetIngressGatewayCertValidityPeriod(computeClient.GetMeshConfig()) },
 		checkInterval,
 	)
 }
 
 // NewCertificateManagerFromMRC returns a new certificate manager.
 func NewCertificateManagerFromMRC(ctx context.Context, kubeClient kubernetes.Interface, kubeConfig *rest.Config,
-	providerNamespace string, option Options, kubeController k8s.Controller, ic *informers.InformerCollection, checkInterval time.Duration) (*certificate.Manager, error) {
+	providerNamespace string, option Options, computeClient compute.Interface, checkInterval time.Duration) (*certificate.Manager, error) {
 	if err := option.Validate(); err != nil {
 		return nil, err
 	}
 
 	mrcClient := &MRCComposer{
+		Interface: computeClient,
 		MRCProviderGenerator: MRCProviderGenerator{
 			kubeClient:      kubeClient,
 			kubeConfig:      kubeConfig,
-			KeyBitSize:      utils.GetCertKeyBitSize(kubeController.GetMeshConfig()),
+			KeyBitSize:      utils.GetCertKeyBitSize(computeClient.GetMeshConfig()),
 			caExtractorFunc: getCA,
 		},
-		informerCollection: ic,
 	}
 	// TODO(#4745): Remove after deprecating the osm.vault.token option.
 	if vaultOption, ok := option.(VaultOptions); ok {
@@ -137,8 +136,8 @@ func NewCertificateManagerFromMRC(ctx context.Context, kubeClient kubernetes.Int
 	return certificate.NewManager(
 		ctx,
 		mrcClient,
-		func() time.Duration { return utils.GetServiceCertValidityPeriod(kubeController.GetMeshConfig()) },
-		func() time.Duration { return utils.GetIngressGatewayCertValidityPeriod(kubeController.GetMeshConfig()) },
+		func() time.Duration { return utils.GetServiceCertValidityPeriod(computeClient.GetMeshConfig()) },
+		func() time.Duration { return utils.GetIngressGatewayCertValidityPeriod(computeClient.GetMeshConfig()) },
 		checkInterval,
 	)
 }
diff --git a/pkg/certificate/providers/mrc.go b/pkg/certificate/providers/mrc.go
index 0d7dc997..f1d41d83 100644
--- a/pkg/certificate/providers/mrc.go
+++ b/pkg/certificate/providers/mrc.go
@@ -7,43 +7,24 @@ import (
 
 	"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
 	"github.com/openservicemesh/osm/pkg/certificate"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
+	"github.com/openservicemesh/osm/pkg/compute"
 )
 
 // MRCComposer is a composer object that allows consumers
 // to observe MRCs (via List() and Watch()) as well as generate
 // `certificate.Provider`s from those MRCs
 type MRCComposer struct {
-	informerCollection *informers.InformerCollection
+	compute.Interface
 	MRCProviderGenerator
 }
 
-// List returns the MRCs stored in the informerCollection's store
-func (m *MRCComposer) List() ([]*v1alpha2.MeshRootCertificate, error) {
-	// informers return slice of pointers so we'll convert them to value types before returning
-	mrcPtrs := m.informerCollection.List(informers.InformerKeyMeshRootCertificate)
-	var mrcs []*v1alpha2.MeshRootCertificate
-	for _, mrcPtr := range mrcPtrs {
-		if mrcPtr == nil {
-			continue
-		}
-		mrc, ok := mrcPtr.(*v1alpha2.MeshRootCertificate)
-		if !ok {
-			continue
-		}
-		mrcs = append(mrcs, mrc)
-	}
-
-	return mrcs, nil
-}
-
 // Watch returns a channel that receives events whenever MRCs are added, updated, and deleted
 // from the informerCollection's MRC store. Channels returned from multiple invocations of
 // Watch() are unique and have no coordination with each other. Events are guaranteed
 // to be ordered for any particular resources, but NOT across different resources.
 func (m *MRCComposer) Watch(ctx context.Context) (<-chan certificate.MRCEvent, error) {
 	eventChan := make(chan certificate.MRCEvent)
-	m.informerCollection.AddEventHandler(informers.InformerKeyMeshRootCertificate, cache.ResourceEventHandlerFuncs{
+	m.AddMeshRootCertificateEventHandler(cache.ResourceEventHandlerFuncs{
 		AddFunc: func(obj interface{}) {
 			mrc := obj.(*v1alpha2.MeshRootCertificate)
 			log.Debug().Msgf("received MRC add event for MRC %s/%s", mrc.GetNamespace(), mrc.GetName())
diff --git a/pkg/certificate/providers/tresor/fake/fake.go b/pkg/certificate/providers/tresor/fake/fake.go
index 02a7ece9..1d5dd57c 100644
--- a/pkg/certificate/providers/tresor/fake/fake.go
+++ b/pkg/certificate/providers/tresor/fake/fake.go
@@ -117,7 +117,7 @@ func (c *fakeMRCClient) GetCertIssuerForMRC(mrc *v1alpha2.MeshRootCertificate) (
 }
 
 // List returns the single, pre-generated MRC. It is intended to implement the certificate.MRCClient interface.
-func (c *fakeMRCClient) List() ([]*v1alpha2.MeshRootCertificate, error) {
+func (c *fakeMRCClient) ListMeshRootCertificates() ([]*v1alpha2.MeshRootCertificate, error) {
 	// return single empty object in the list.
 	return []*v1alpha2.MeshRootCertificate{{Spec: v1alpha2.MeshRootCertificateSpec{TrustDomain: "fake.example.com"}}}, nil
 }
diff --git a/pkg/certificate/types.go b/pkg/certificate/types.go
index 50ce9ae8..0f21aaf7 100644
--- a/pkg/certificate/types.go
+++ b/pkg/certificate/types.go
@@ -127,6 +127,7 @@ type Manager struct {
 // MRCClient is an interface that can watch for changes to the MRC. It is typically backed by a k8s informer.
 type MRCClient interface {
 	UpdateMeshRootCertificate(mrc *v1alpha2.MeshRootCertificate) error
+	ListMeshRootCertificates() ([]*v1alpha2.MeshRootCertificate, error)
 	MRCEventBroker
 
 	// GetCertIssuerForMRC returns an Issuer based on the provided MRC.
diff --git a/pkg/compute/mock_compute_client_generated.go b/pkg/compute/mock_compute_client_generated.go
index 813edb18..56968d30 100644
--- a/pkg/compute/mock_compute_client_generated.go
+++ b/pkg/compute/mock_compute_client_generated.go
@@ -19,6 +19,7 @@ import (
 	v1alpha4 "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha4"
 	v1alpha20 "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
 	types "k8s.io/apimachinery/pkg/types"
+	cache "k8s.io/client-go/tools/cache"
 	v1alpha10 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
 )
 
@@ -45,6 +46,18 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
 	return m.recorder
 }
 
+// AddMeshRootCertificateEventHandler mocks base method.
+func (m *MockInterface) AddMeshRootCertificateEventHandler(arg0 cache.ResourceEventHandler) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "AddMeshRootCertificateEventHandler", arg0)
+}
+
+// AddMeshRootCertificateEventHandler indicates an expected call of AddMeshRootCertificateEventHandler.
+func (mr *MockInterfaceMockRecorder) AddMeshRootCertificateEventHandler(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMeshRootCertificateEventHandler", reflect.TypeOf((*MockInterface)(nil).AddMeshRootCertificateEventHandler), arg0)
+}
+
 // GetHTTPRouteGroup mocks base method.
 func (m *MockInterface) GetHTTPRouteGroup(arg0 string) *v1alpha4.HTTPRouteGroup {
 	m.ctrl.T.Helper()
diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go
index c58079b8..4e18a9cd 100644
--- a/pkg/k8s/client.go
+++ b/pkg/k8s/client.go
@@ -11,167 +11,40 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
 	mcs "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
-	mcsv1alpha1Client "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned"
 
 	configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
 	policyv1alpha1 "github.com/openservicemesh/osm/pkg/apis/policy/v1alpha1"
-	configv1alpha2Client "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
-	policyv1alpha1Client "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned"
 
 	"github.com/openservicemesh/osm/pkg/constants"
 	"github.com/openservicemesh/osm/pkg/errcode"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/models"
 )
 
 // NewClient returns a new kubernetes.Controller which means to provide access to locally-cached k8s resources
-func NewClient(osmNamespace, meshConfigName string, informerCollection *informers.InformerCollection, kubeClient kubernetes.Interface, policyClient policyv1alpha1Client.Interface, configClient configv1alpha2Client.Interface, mcsClient mcsv1alpha1Client.Interface, msgBroker *messaging.Broker, selectInformers ...informers.InformerKey) *Client {
+func NewClient(osmNamespace, meshConfigName string, broker *messaging.Broker, opts ...ClientOption) (*Client, error) {
 	// Initialize client object
 	c := &Client{
-		informers:      informerCollection,
-		msgBroker:      msgBroker,
-		policyClient:   policyClient,
-		configClient:   configClient,
-		mcsClient:      mcsClient,
-		kubeClient:     kubeClient,
+		informers:      map[informerKey]cache.SharedIndexInformer{},
+		msgBroker:      broker,
 		osmNamespace:   osmNamespace,
 		meshConfigName: meshConfigName,
 	}
-
-	// Initialize informers
-	informerInitHandlerMap := map[informers.InformerKey]func(){
-		informers.InformerKeyNamespace:              c.initNamespaceMonitor,
-		informers.InformerKeyService:                c.initServicesMonitor,
-		informers.InformerKeyServiceAccount:         c.initServiceAccountsMonitor,
-		informers.InformerKeyPod:                    c.initPodMonitor,
-		informers.InformerKeyEndpoint:               c.initEndpointMonitor,
-		informers.InformerKeyMeshConfig:             c.initMeshConfigMonitor,
-		informers.InformerKeyMeshRootCertificate:    c.initMRCMonitor,
-		informers.InformerKeyExtensionService:       c.initExtensionServiceMonitor,
-		informers.InformerKeyEgress:                 c.initEgressMonitor,
-		informers.InformerKeyIngressBackend:         c.initIngressBackendMonitor,
-		informers.InformerKeyRetry:                  c.initRetryMonitor,
-		informers.InformerKeyUpstreamTrafficSetting: c.initUpstreamTrafficSettingMonitor,
-		informers.InformerKeyTelemetry:              c.initTelemetryMonitor,
-		informers.InformerKeyTrafficSplit:           c.initTrafficSplitMonitor,
-		informers.InformerKeyHTTPRouteGroup:         c.initHTTPRouteGroupMonitor,
-		informers.InformerKeyTCPRoute:               c.initTCPRouteMonitor,
-		informers.InformerKeyTrafficTarget:          c.initTrafficTargetMonitor,
-		informers.InformerKeyServiceImport:          c.initServiceImportMonitor,
-		informers.InformerKeyServiceExport:          c.initServiceExportMonitor,
-	}
-
-	// If specific informers are not selected to be initialized, initialize all informers
-	if len(selectInformers) == 0 {
-		selectInformers = []informers.InformerKey{
-			informers.InformerKeyNamespace, informers.InformerKeyService, informers.InformerKeyServiceAccount, informers.InformerKeyPod, informers.InformerKeyEndpoint, informers.InformerKeyMeshConfig, informers.InformerKeyMeshRootCertificate, informers.InformerKeyExtensionService,
-			informers.InformerKeyEgress, informers.InformerKeyIngressBackend, informers.InformerKeyRetry, informers.InformerKeyUpstreamTrafficSetting, informers.InformerKeyTelemetry, informers.InformerKeyTrafficSplit, informers.InformerKeyHTTPRouteGroup, informers.InformerKeyTCPRoute,
-			informers.InformerKeyTrafficTarget, informers.InformerKeyServiceImport, informers.InformerKeyServiceExport}
-	}
-
-	for _, informer := range selectInformers {
-		informerInitHandlerMap[informer]()
+	// Execute all of the given options (e.g. set clients, set custom stores, etc.)
+	for _, opt := range opts {
+		if opt != nil {
+			opt(c)
+		}
 	}
 
-	return c
-}
-
-// Initializes Namespace monitoring
-func (c *Client) initNamespaceMonitor() {
-	// Add event handler to informer
-	c.informers.AddEventHandler(informers.InformerKeyNamespace, GetEventHandlerFuncs(nil, c.msgBroker))
-}
-
-func (c *Client) initMeshConfigMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyMeshConfig, GetEventHandlerFuncs(nil, c.msgBroker))
-	c.informers.AddEventHandler(informers.InformerKeyMeshConfig, c.metricsHandler())
-}
-
-func (c *Client) initMRCMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyMeshRootCertificate, GetEventHandlerFuncs(nil, c.msgBroker))
-}
-
-func (c *Client) initExtensionServiceMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyExtensionService, GetEventHandlerFuncs(nil, c.msgBroker))
-}
-
-func (c *Client) initEgressMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyEgress, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initIngressBackendMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyIngressBackend, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initRetryMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyRetry, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initUpstreamTrafficSettingMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyUpstreamTrafficSetting, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initTelemetryMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyTelemetry, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-// Function to filter K8s meta Objects by OSM's isMonitoredNamespace
-func (c *Client) shouldObserve(obj interface{}) bool {
-	object, ok := obj.(metav1.Object)
-	if !ok {
-		return false
+	if err := c.run(broker.Done()); err != nil {
+		log.Error().Err(err).Msg("Could not start informer collection")
+		return nil, err
 	}
-	return c.IsMonitoredNamespace(object.GetNamespace())
-}
-
-// Initializes Service monitoring
-func (c *Client) initServicesMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyService, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-// Initializes Service Account monitoring
-func (c *Client) initServiceAccountsMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyServiceAccount, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initPodMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyPod, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initEndpointMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyEndpoint, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initTrafficSplitMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyTrafficSplit, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
 
-func (c *Client) initHTTPRouteGroupMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyHTTPRouteGroup, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initTCPRouteMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyTCPRoute, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initTrafficTargetMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyTrafficTarget, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initServiceImportMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyServiceImport, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-func (c *Client) initServiceExportMonitor() {
-	c.informers.AddEventHandler(informers.InformerKeyServiceExport, GetEventHandlerFuncs(c.shouldObserve, c.msgBroker))
-}
-
-// IsMonitoredNamespace returns a boolean indicating if the namespace is among the list of monitored namespaces
-func (c *Client) IsMonitoredNamespace(namespace string) bool {
-	return c.informers.IsMonitoredNamespace(namespace)
+	return c, nil
 }
 
 func key(name, namespace string) string {
@@ -182,7 +55,7 @@ func key(name, namespace string) string {
 func (c *Client) ListNamespaces() ([]*corev1.Namespace, error) {
 	var namespaces []*corev1.Namespace
 
-	for _, ns := range c.informers.List(informers.InformerKeyNamespace) {
+	for _, ns := range c.list(informerKeyNamespace) {
 		namespace, ok := ns.(*corev1.Namespace)
 		if !ok {
 			log.Error().Err(errListingNamespaces).Msg("Failed to list monitored namespaces")
@@ -196,7 +69,7 @@ func (c *Client) ListNamespaces() ([]*corev1.Namespace, error) {
 // GetService retrieves the Kubernetes Services resource for the given MeshService
 func (c *Client) GetService(name, namespace string) *corev1.Service {
 	// client-go cache uses <namespace>/<name> as key
-	svcIf, exists, err := c.informers.GetByKey(informers.InformerKeyService, key(name, namespace))
+	svcIf, exists, err := c.getByKey(informerKeyService, key(name, namespace))
 	if exists && err == nil {
 		svc := svcIf.(*corev1.Service)
 		return svc
@@ -206,7 +79,7 @@ func (c *Client) GetService(name, namespace string) *corev1.Service {
 
 // GetSecret returns the secret for a given secret name and namespace
 func (c *Client) GetSecret(name, namespace string) *models.Secret {
-	secretIf, exists, err := c.informers.GetByKey(informers.InformerKeySecret, key(name, namespace))
+	secretIf, exists, err := c.getByKey(informerKeySecret, key(name, namespace))
 	if exists && err == nil {
 		corev1Secret, ok := secretIf.(*corev1.Secret)
 		if !ok {
@@ -225,7 +98,7 @@ func (c *Client) GetSecret(name, namespace string) *models.Secret {
 func (c *Client) ListSecrets() []*models.Secret {
 	var secrets []*models.Secret
 
-	for _, secretPtr := range c.informers.List(informers.InformerKeySecret) {
+	for _, secretPtr := range c.list(informerKeySecret) {
 		if secretPtr == nil {
 			continue
 		}
@@ -259,7 +132,7 @@ func (c *Client) UpdateSecret(ctx context.Context, secret *models.Secret) error
 func (c *Client) ListServices() []*corev1.Service {
 	var services []*corev1.Service
 
-	for _, serviceInterface := range c.informers.List(informers.InformerKeyService) {
+	for _, serviceInterface := range c.list(informerKeyService) {
 		svc := serviceInterface.(*corev1.Service)
 
 		if !c.IsMonitoredNamespace(svc.Namespace) {
@@ -274,7 +147,7 @@ func (c *Client) ListServices() []*corev1.Service {
 func (c *Client) ListServiceAccounts() []*corev1.ServiceAccount {
 	var serviceAccounts []*corev1.ServiceAccount
 
-	for _, serviceInterface := range c.informers.List(informers.InformerKeyServiceAccount) {
+	for _, serviceInterface := range c.list(informerKeyServiceAccount) {
 		sa := serviceInterface.(*corev1.ServiceAccount)
 
 		if !c.IsMonitoredNamespace(sa.Namespace) {
@@ -287,7 +160,7 @@ func (c *Client) ListServiceAccounts() []*corev1.ServiceAccount {
 
 // GetNamespace returns a Namespace resource if found, nil otherwise.
 func (c *Client) GetNamespace(ns string) *corev1.Namespace {
-	nsIf, exists, err := c.informers.GetByKey(informers.InformerKeyNamespace, ns)
+	nsIf, exists, err := c.getByKey(informerKeyNamespace, ns)
 	if exists && err == nil {
 		ns := nsIf.(*corev1.Namespace)
 		return ns
@@ -301,7 +174,7 @@ func (c *Client) GetNamespace(ns string) *corev1.Namespace {
 func (c *Client) ListPods() []*corev1.Pod {
 	var pods []*corev1.Pod
 
-	for _, podInterface := range c.informers.List(informers.InformerKeyPod) {
+	for _, podInterface := range c.list(informerKeyPod) {
 		pod := podInterface.(*corev1.Pod)
 		if !c.IsMonitoredNamespace(pod.Namespace) {
 			continue
@@ -314,7 +187,7 @@ func (c *Client) ListPods() []*corev1.Pod {
 // GetEndpoints returns the endpoint for a given service, otherwise returns nil if not found
 // or error if the API errored out.
 func (c *Client) GetEndpoints(name, namespace string) (*corev1.Endpoints, error) {
-	ep, exists, err := c.informers.GetByKey(informers.InformerKeyEndpoint, key(name, namespace))
+	ep, exists, err := c.getByKey(informerKeyEndpoints, key(name, namespace))
 	if err != nil {
 		return nil, err
 	}
@@ -342,7 +215,7 @@ func IsHeadlessService(svc corev1.Service) bool {
 // GetMeshConfig returns the current MeshConfig
 func (c *Client) GetMeshConfig() configv1alpha2.MeshConfig {
 	key := types.NamespacedName{Namespace: c.osmNamespace, Name: c.meshConfigName}.String()
-	item, _, err := c.informers.GetByKey(informers.InformerKeyMeshConfig, key)
+	item, _, err := c.getByKey(informerKeyMeshConfig, key)
 	if item != nil {
 		return *item.(*configv1alpha2.MeshConfig)
 	}
@@ -420,7 +293,7 @@ func (c *Client) GetOSMNamespace() string {
 func (c *Client) ListEgressPolicies() []*policyv1alpha1.Egress {
 	var policies []*policyv1alpha1.Egress
 
-	for _, egressIface := range c.informers.List(informers.InformerKeyEgress) {
+	for _, egressIface := range c.list(informerKeyEgress) {
 		egressPolicy := egressIface.(*policyv1alpha1.Egress)
 
 		if !c.IsMonitoredNamespace(egressPolicy.Namespace) {
@@ -436,7 +309,7 @@ func (c *Client) ListEgressPolicies() []*policyv1alpha1.Egress {
 func (c *Client) ListIngressBackendPolicies() []*policyv1alpha1.IngressBackend {
 	var backends []*policyv1alpha1.IngressBackend
 
-	for _, ingressBackendIface := range c.informers.List(informers.InformerKeyIngressBackend) {
+	for _, ingressBackendIface := range c.list(informerKeyIngressBackend) {
 		backend := ingressBackendIface.(*policyv1alpha1.IngressBackend)
 		if !c.IsMonitoredNamespace(backend.Namespace) {
 			continue
@@ -452,7 +325,7 @@ func (c *Client) ListIngressBackendPolicies() []*policyv1alpha1.IngressBackend {
 func (c *Client) ListRetryPolicies() []*policyv1alpha1.Retry {
 	var retries []*policyv1alpha1.Retry
 
-	for _, retryInterface := range c.informers.List(informers.InformerKeyRetry) {
+	for _, retryInterface := range c.list(informerKeyRetry) {
 		policy := retryInterface.(*policyv1alpha1.Retry)
 		if !c.IsMonitoredNamespace(policy.Namespace) {
 			continue
@@ -469,7 +342,7 @@ func (c *Client) ListUpstreamTrafficSettings() []*policyv1alpha1.UpstreamTraffic
 	var settings []*policyv1alpha1.UpstreamTrafficSetting
 
 	// Filter by MeshService
-	for _, resource := range c.informers.List(informers.InformerKeyUpstreamTrafficSetting) {
+	for _, resource := range c.list(informerKeyUpstreamTrafficSetting) {
 		setting := resource.(*policyv1alpha1.UpstreamTrafficSetting)
 
 		if !c.IsMonitoredNamespace(setting.Namespace) {
@@ -484,7 +357,7 @@ func (c *Client) ListUpstreamTrafficSettings() []*policyv1alpha1.UpstreamTraffic
 
 // GetUpstreamTrafficSetting returns the UpstreamTrafficSetting resources with namespaced name
 func (c *Client) GetUpstreamTrafficSetting(namespace *types.NamespacedName) *policyv1alpha1.UpstreamTrafficSetting {
-	resource, exists, err := c.informers.GetByKey(informers.InformerKeyUpstreamTrafficSetting, namespace.String())
+	resource, exists, err := c.getByKey(informerKeyUpstreamTrafficSetting, namespace.String())
 	if exists && err == nil {
 		return resource.(*policyv1alpha1.UpstreamTrafficSetting)
 	}
@@ -494,7 +367,7 @@ func (c *Client) GetUpstreamTrafficSetting(namespace *types.NamespacedName) *pol
 // GetMeshRootCertificate returns a MeshRootCertificate resource with namespaced name
 func (c *Client) GetMeshRootCertificate(mrcName string) *configv1alpha2.MeshRootCertificate {
 	key := types.NamespacedName{Namespace: c.osmNamespace, Name: mrcName}.String()
-	resource, exists, err := c.informers.GetByKey(informers.InformerKeyMeshRootCertificate, key)
+	resource, exists, err := c.getByKey(informerKeyMeshRootCertificate, key)
 	if exists && err == nil {
 		return resource.(*configv1alpha2.MeshRootCertificate)
 	}
@@ -505,7 +378,7 @@ func (c *Client) GetMeshRootCertificate(mrcName string) *configv1alpha2.MeshRoot
 func (c *Client) ListTrafficSplits() []*smiSplit.TrafficSplit {
 	var trafficSplits []*smiSplit.TrafficSplit
 
-	for _, splitIface := range c.informers.List(informers.InformerKeyTrafficSplit) {
+	for _, splitIface := range c.list(informerKeyTrafficSplit) {
 		trafficSplit := splitIface.(*smiSplit.TrafficSplit)
 
 		if !c.IsMonitoredNamespace(trafficSplit.Namespace) {
@@ -519,7 +392,7 @@ func (c *Client) ListTrafficSplits() []*smiSplit.TrafficSplit {
 // ListHTTPTrafficSpecs lists SMI HTTPRouteGroup resources
 func (c *Client) ListHTTPTrafficSpecs() []*smiSpecs.HTTPRouteGroup {
 	var httpTrafficSpec []*smiSpecs.HTTPRouteGroup
-	for _, specIface := range c.informers.List(informers.InformerKeyHTTPRouteGroup) {
+	for _, specIface := range c.list(informerKeyHTTPRouteGroup) {
 		routeGroup := specIface.(*smiSpecs.HTTPRouteGroup)
 
 		if !c.IsMonitoredNamespace(routeGroup.Namespace) {
@@ -533,7 +406,7 @@ func (c *Client) ListHTTPTrafficSpecs() []*smiSpecs.HTTPRouteGroup {
 // GetHTTPRouteGroup returns an SMI HTTPRouteGroup resource given its name of the form <namespace>/<name>
 func (c *Client) GetHTTPRouteGroup(namespacedName string) *smiSpecs.HTTPRouteGroup {
 	// client-go cache uses <namespace>/<name> as key
-	routeIf, exists, err := c.informers.GetByKey(informers.InformerKeyHTTPRouteGroup, namespacedName)
+	routeIf, exists, err := c.getByKey(informerKeyHTTPRouteGroup, namespacedName)
 	if exists && err == nil {
 		route := routeIf.(*smiSpecs.HTTPRouteGroup)
 		if !c.IsMonitoredNamespace(route.Namespace) {
@@ -557,7 +430,7 @@ func (c *Client) UpdateMeshRootCertificateStatus(obj *configv1alpha2.MeshRootCer
 // ListMeshRootCertificates returns the MRCs stored in the informerCollection's store
 func (c *Client) ListMeshRootCertificates() ([]*configv1alpha2.MeshRootCertificate, error) {
 	// informers return slice of generic, essentially untyped so we'll convert them to value types before returning
-	mrcPtrs := c.informers.List(informers.InformerKeyMeshRootCertificate)
+	mrcPtrs := c.list(informerKeyMeshRootCertificate)
 	var mrcs []*configv1alpha2.MeshRootCertificate
 	for _, mrcPtr := range mrcPtrs {
 		if mrcPtr == nil {
@@ -576,7 +449,7 @@ func (c *Client) ListMeshRootCertificates() ([]*configv1alpha2.MeshRootCertifica
 // ListTCPTrafficSpecs lists SMI TCPRoute resources
 func (c *Client) ListTCPTrafficSpecs() []*smiSpecs.TCPRoute {
 	var tcpRouteSpec []*smiSpecs.TCPRoute
-	for _, specIface := range c.informers.List(informers.InformerKeyTCPRoute) {
+	for _, specIface := range c.list(informerKeyTCPRoute) {
 		tcpRoute := specIface.(*smiSpecs.TCPRoute)
 
 		if !c.IsMonitoredNamespace(tcpRoute.Namespace) {
@@ -590,7 +463,7 @@ func (c *Client) ListTCPTrafficSpecs() []*smiSpecs.TCPRoute {
 // GetTCPRoute returns an SMI TCPRoute resource given its name of the form <namespace>/<name>
 func (c *Client) GetTCPRoute(namespacedName string) *smiSpecs.TCPRoute {
 	// client-go cache uses <namespace>/<name> as key
-	routeIf, exists, err := c.informers.GetByKey(informers.InformerKeyTCPRoute, namespacedName)
+	routeIf, exists, err := c.getByKey(informerKeyTCPRoute, namespacedName)
 	if exists && err == nil {
 		route := routeIf.(*smiSpecs.TCPRoute)
 		if !c.IsMonitoredNamespace(route.Namespace) {
@@ -606,7 +479,7 @@ func (c *Client) GetTCPRoute(namespacedName string) *smiSpecs.TCPRoute {
 func (c *Client) ListTrafficTargets() []*smiAccess.TrafficTarget {
 	var trafficTargets []*smiAccess.TrafficTarget
 
-	for _, targetIface := range c.informers.List(informers.InformerKeyTrafficTarget) {
+	for _, targetIface := range c.list(informerKeyTrafficTarget) {
 		trafficTarget := targetIface.(*smiAccess.TrafficTarget)
 
 		if !c.IsMonitoredNamespace(trafficTarget.Namespace) {
@@ -628,7 +501,7 @@ func (c *Client) GetTelemetryPolicy(proxy *models.Proxy) *policyv1alpha1.Telemet
 
 	var policy *policyv1alpha1.Telemetry
 
-	for _, resource := range c.informers.List(informers.InformerKeyTelemetry) {
+	for _, resource := range c.list(informerKeyTelemetry) {
 		t := resource.(*policyv1alpha1.Telemetry)
 
 		// If there is a global policy and a more specific policy hasn't been
@@ -670,7 +543,7 @@ func (c *Client) GetTelemetryPolicy(proxy *models.Proxy) *policyv1alpha1.Telemet
 func (c *Client) ListServiceImports() []*mcs.ServiceImport {
 	var serviceImports []*mcs.ServiceImport
 
-	for _, resource := range c.informers.List(informers.InformerKeyServiceImport) {
+	for _, resource := range c.list(informerKeyServiceImport) {
 		serviceImport := resource.(*mcs.ServiceImport)
 		if !c.IsMonitoredNamespace(serviceImport.Namespace) {
 			continue
@@ -685,7 +558,7 @@ func (c *Client) ListServiceImports() []*mcs.ServiceImport {
 func (c *Client) ListServiceExports() []*mcs.ServiceExport {
 	var serviceExports []*mcs.ServiceExport
 
-	for _, resource := range c.informers.List(informers.InformerKeyServiceImport) {
+	for _, resource := range c.list(informerKeyServiceExport) {
 		serviceExport := resource.(*mcs.ServiceExport)
 		if !c.IsMonitoredNamespace(serviceExport.Namespace) {
 			continue
@@ -695,3 +568,8 @@ func (c *Client) ListServiceExports() []*mcs.ServiceExport {
 
 	return serviceExports
 }
+
+// AddMeshRootCertificateEventHandler adds an event handler specific to mesh root certificiates.
+func (c *Client) AddMeshRootCertificateEventHandler(handler cache.ResourceEventHandler) {
+	c.informers[informerKeyMeshRootCertificate].AddEventHandler(handler)
+}
diff --git a/pkg/k8s/event_handlers.go b/pkg/k8s/event_handlers.go
index ca82fc6e..683478f2 100644
--- a/pkg/k8s/event_handlers.go
+++ b/pkg/k8s/event_handlers.go
@@ -3,83 +3,73 @@ package k8s
 import (
 	"reflect"
 
-	"github.com/rs/zerolog"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/cache"
 
 	configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
 	"github.com/openservicemesh/osm/pkg/k8s/events"
-	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/metricsstore"
 )
 
-// observeFilter returns true for YES observe and false for NO do not pay attention to this
-// This filter could be added optionally by anything using GetEventHandlerFuncs()
-type observeFilter func(obj interface{}) bool
+// Function to filter K8s meta Objects by OSM's isMonitoredNamespace
+func (c *Client) shouldObserve(obj interface{}) bool {
+	switch v := obj.(type) {
+	case *corev1.Namespace, *configv1alpha2.MeshConfig, *configv1alpha2.MeshRootCertificate, *configv1alpha2.ExtensionService:
+		return true
+	case metav1.Object:
+		return c.IsMonitoredNamespace(v.GetNamespace())
+	}
+	return false
+}
 
-// GetEventHandlerFuncs returns the ResourceEventHandlerFuncs object used to receive events when a k8s
+// defaultEventHandler returns the ResourceEventHandlerFuncs object used to receive events when a k8s
 // object is added/updated/deleted.
-func GetEventHandlerFuncs(shouldObserve observeFilter, msgBroker *messaging.Broker) cache.ResourceEventHandlerFuncs {
-	if shouldObserve == nil {
-		shouldObserve = func(obj interface{}) bool { return true }
-	}
+func (c *Client) defaultEventHandler() cache.ResourceEventHandlerFuncs {
 	return cache.ResourceEventHandlerFuncs{
 		AddFunc: func(obj interface{}) {
-			if !shouldObserve(obj) {
-				return
-			}
-			msg := events.PubSubMessage{
-				Kind:   events.GetKind(obj),
-				Type:   events.Added,
-				NewObj: obj,
-				OldObj: nil,
-			}
-			logResourceEvent(log, msg.Topic(), obj)
-			ns := getNamespace(obj)
-			metricsstore.DefaultMetricsStore.K8sAPIEventCounter.WithLabelValues(msg.Topic(), ns).Inc()
-			msgBroker.GetQueue().AddRateLimited(msg)
+			c.handleEvent(events.Added, nil, obj)
 		},
 
 		UpdateFunc: func(oldObj, newObj interface{}) {
-			if !shouldObserve(newObj) {
-				return
-			}
-			msg := events.PubSubMessage{
-				Kind:   events.GetKind(newObj),
-				Type:   events.Updated,
-				NewObj: newObj,
-				OldObj: oldObj,
-			}
-			logResourceEvent(log, msg.Topic(), newObj)
-			ns := getNamespace(newObj)
-			metricsstore.DefaultMetricsStore.K8sAPIEventCounter.WithLabelValues(msg.Topic(), ns).Inc()
-			msgBroker.GetQueue().AddRateLimited(msg)
+			c.handleEvent(events.Updated, oldObj, newObj)
 		},
 
 		DeleteFunc: func(obj interface{}) {
-			if !shouldObserve(obj) {
-				return
-			}
-			msg := events.PubSubMessage{
-				Kind:   events.GetKind(obj),
-				Type:   events.Deleted,
-				NewObj: nil,
-				OldObj: obj,
-			}
-			logResourceEvent(log, msg.Topic(), obj)
-			ns := getNamespace(obj)
-			metricsstore.DefaultMetricsStore.K8sAPIEventCounter.WithLabelValues(msg.Topic(), ns).Inc()
-			msgBroker.GetQueue().AddRateLimited(msg)
+			c.handleEvent(events.Deleted, obj, nil)
 		},
 	}
 }
 
+func (c *Client) handleEvent(event events.EventType, oldObj, newObj interface{}) {
+	obj := newObj
+	if event == events.Deleted {
+		obj = oldObj
+	}
+
+	if !c.shouldObserve(obj) {
+		return
+	}
+
+	msg := events.PubSubMessage{
+		Kind:   events.GetKind(obj),
+		Type:   event,
+		NewObj: newObj,
+		OldObj: oldObj,
+	}
+	logResourceEvent(msg.Topic(), obj)
+	ns := getNamespace(obj)
+	metricsstore.DefaultMetricsStore.K8sAPIEventCounter.WithLabelValues(msg.Topic(), ns).Inc()
+	c.msgBroker.GetQueue().AddRateLimited(msg)
+}
+
 func getNamespace(obj interface{}) string {
 	return reflect.ValueOf(obj).Elem().FieldByName("ObjectMeta").FieldByName("Namespace").String()
 }
 
-func logResourceEvent(parent zerolog.Logger, event string, obj interface{}) {
-	log := parent.With().Str("event", event).Logger()
+func logResourceEvent(event string, obj interface{}) {
+	log := log.With().Str("event", event).Logger()
 	o, err := meta.Accessor(obj)
 	if err != nil {
 		log.Error().Err(err).Msg("error parsing object, ignoring")
diff --git a/pkg/k8s/informers.go b/pkg/k8s/informers.go
new file mode 100644
index 00000000..9e67e849
--- /dev/null
+++ b/pkg/k8s/informers.go
@@ -0,0 +1,241 @@
+package k8s
+
+import (
+	"time"
+
+	"errors"
+
+	smiTrafficAccessClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned"
+	smiAccessInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/informers/externalversions"
+	smiTrafficSpecClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned"
+	smiTrafficSpecInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/informers/externalversions"
+	smiTrafficSplitClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned"
+	smiTrafficSplitInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/informers/externalversions"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
+	"k8s.io/client-go/informers"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
+	mcsClient "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned"
+	mcsInformers "sigs.k8s.io/mcs-api/pkg/client/informers/externalversions"
+
+	"github.com/openservicemesh/osm/pkg/constants"
+	configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
+	configInformers "github.com/openservicemesh/osm/pkg/gen/client/config/informers/externalversions"
+	policyClientset "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned"
+	policyInformers "github.com/openservicemesh/osm/pkg/gen/client/policy/informers/externalversions"
+)
+
+// informerKey stores the different Informers we keep for K8s resources
+type informerKey string
+
+const (
+	// informerKeyNamespace is the informerKey for a Namespace informer
+	informerKeyNamespace informerKey = "Namespace"
+	// informerKeyService is the informerKey for a Service informer
+	informerKeyService informerKey = "Service"
+	// informerKeyPod is the informerKey for a Pod informer
+	informerKeyPod informerKey = "Pod"
+	// informerKeyEndpoints is the informerKey for a Endpoints informer
+	informerKeyEndpoints informerKey = "Endpoints"
+	// informerKeyServiceAccount is the informerKey for a ServiceAccount informer
+	informerKeyServiceAccount informerKey = "ServiceAccount"
+	// informerKeySecret is the informerKey for a Secret informer
+	informerKeySecret informerKey = "Secret"
+
+	// informerKeyTrafficSplit is the informerKey for a TrafficSplit informer
+	informerKeyTrafficSplit informerKey = "TrafficSplit"
+	// informerKeyTrafficTarget is the informerKey for a TrafficTarget informer
+	informerKeyTrafficTarget informerKey = "TrafficTarget"
+	// informerKeyHTTPRouteGroup is the informerKey for a HTTPRouteGroup informer
+	informerKeyHTTPRouteGroup informerKey = "HTTPRouteGroup"
+	// informerKeyTCPRoute is the informerKey for a TCPRoute informer
+	informerKeyTCPRoute informerKey = "TCPRoute"
+
+	// informerKeyMeshConfig is the informerKey for a MeshConfig informer
+	informerKeyMeshConfig informerKey = "MeshConfig"
+	// informerKeyMeshRootCertificate is the informerKey for a MeshRootCertificate informer
+	informerKeyMeshRootCertificate informerKey = "MeshRootCertificate"
+
+	// informerKeyEgress is the informerKey for a Egress informer
+	informerKeyEgress informerKey = "Egress"
+	// informerKeyIngressBackend is the informerKey for a IngressBackend informer
+	informerKeyIngressBackend informerKey = "IngressBackend"
+	// informerKeyUpstreamTrafficSetting is the informerKey for a UpstreamTrafficSetting informer
+	informerKeyUpstreamTrafficSetting informerKey = "UpstreamTrafficSetting"
+	// informerKeyRetry is the informerKey for a Retry informer
+	informerKeyRetry informerKey = "Retry"
+	// informerKeyTelemetry lookup identifier
+	informerKeyTelemetry informerKey = "Telemetry"
+	// informerKeyExtensionService is the informerKey for an ExtensionService informer
+	informerKeyExtensionService informerKey = "ExtensionService"
+	// informerKeyServiceImport is the informerKey for a ServiceImport informer
+	informerKeyServiceImport informerKey = "ServiceImport"
+	// informerKeyServiceExport is the informerKey for a ServiceExport informer
+	informerKeyServiceExport informerKey = "ServiceExport"
+)
+
+const (
+	// DefaultKubeEventResyncInterval is the default resync interval for k8s events
+	// This is set to 0 because we do not need resyncs from k8s client, and have our
+	// own Ticker to turn on periodic resyncs.
+	DefaultKubeEventResyncInterval = 0 * time.Second
+)
+
+var (
+	errInitInformers = errors.New("informer not initialized")
+	errSyncingCaches = errors.New("failed initial cache sync for informers")
+)
+
+// ClientOption is a function that modifies an informer collection
+type ClientOption func(*Client)
+
+// WithKubeClient sets the kubeClient for the Client
+func WithKubeClient(kubeClient kubernetes.Interface, meshName string) ClientOption {
+	return func(c *Client) {
+		c.kubeClient = kubeClient
+		// initialize informers
+		monitorNamespaceLabel := map[string]string{constants.OSMKubeResourceMonitorAnnotation: meshName}
+
+		labelSelector := fields.SelectorFromSet(monitorNamespaceLabel).String()
+		option := informers.WithTweakListOptions(func(opt *metav1.ListOptions) {
+			opt.LabelSelector = labelSelector
+		})
+
+		monitorSecretLabel := map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue}
+		secretLabelSelector := fields.SelectorFromSet(monitorSecretLabel).String()
+		secretOption := informers.WithTweakListOptions(func(opt *metav1.ListOptions) {
+			opt.LabelSelector = secretLabelSelector
+		})
+
+		nsInformerFactory := informers.NewSharedInformerFactoryWithOptions(kubeClient, DefaultKubeEventResyncInterval, option)
+		informerFactory := informers.NewSharedInformerFactory(kubeClient, DefaultKubeEventResyncInterval)
+		secretInformerFactory := informers.NewSharedInformerFactoryWithOptions(kubeClient, DefaultKubeEventResyncInterval, secretOption)
+		v1api := informerFactory.Core().V1()
+		c.informers[informerKeyNamespace] = nsInformerFactory.Core().V1().Namespaces().Informer()
+		c.informers[informerKeyService] = v1api.Services().Informer()
+		c.informers[informerKeyServiceAccount] = v1api.ServiceAccounts().Informer()
+		c.informers[informerKeyPod] = v1api.Pods().Informer()
+		c.informers[informerKeyEndpoints] = v1api.Endpoints().Informer()
+		c.informers[informerKeySecret] = secretInformerFactory.Core().V1().Secrets().Informer()
+	}
+}
+
+// WithSMIClients sets the SMI clients for the Client
+func WithSMIClients(smiTrafficSplitClient smiTrafficSplitClient.Interface, smiTrafficSpecClient smiTrafficSpecClient.Interface, smiAccessClient smiTrafficAccessClient.Interface) ClientOption {
+	return func(c *Client) {
+		accessInformerFactory := smiAccessInformers.NewSharedInformerFactory(smiAccessClient, DefaultKubeEventResyncInterval)
+		splitInformerFactory := smiTrafficSplitInformers.NewSharedInformerFactory(smiTrafficSplitClient, DefaultKubeEventResyncInterval)
+		specInformerFactory := smiTrafficSpecInformers.NewSharedInformerFactory(smiTrafficSpecClient, DefaultKubeEventResyncInterval)
+
+		c.informers[informerKeyTCPRoute] = specInformerFactory.Specs().V1alpha4().TCPRoutes().Informer()
+		c.informers[informerKeyHTTPRouteGroup] = specInformerFactory.Specs().V1alpha4().HTTPRouteGroups().Informer()
+		c.informers[informerKeyTrafficTarget] = accessInformerFactory.Access().V1alpha3().TrafficTargets().Informer()
+		c.informers[informerKeyTrafficSplit] = splitInformerFactory.Split().V1alpha2().TrafficSplits().Informer()
+	}
+}
+
+// WithConfigClient sets the config client for the Client
+func WithConfigClient(configClient configClientset.Interface) ClientOption {
+	return func(c *Client) {
+		c.configClient = configClient
+
+		listOption := configInformers.WithTweakListOptions(func(opt *metav1.ListOptions) {
+			opt.FieldSelector = fields.OneTermEqualSelector(metav1.ObjectNameField, c.meshConfigName).String()
+		})
+		meshConfiginformerFactory := configInformers.NewSharedInformerFactoryWithOptions(configClient, DefaultKubeEventResyncInterval, configInformers.WithNamespace(c.osmNamespace), listOption)
+		mrcInformerFactory := configInformers.NewSharedInformerFactoryWithOptions(configClient, DefaultKubeEventResyncInterval, configInformers.WithNamespace(c.osmNamespace))
+		informerFactory := configInformers.NewSharedInformerFactory(configClient, DefaultKubeEventResyncInterval)
+
+		c.informers[informerKeyMeshConfig] = meshConfiginformerFactory.Config().V1alpha2().MeshConfigs().Informer()
+		c.informers[informerKeyMeshRootCertificate] = mrcInformerFactory.Config().V1alpha2().MeshRootCertificates().Informer()
+		c.informers[informerKeyExtensionService] = informerFactory.Config().V1alpha2().ExtensionServices().Informer()
+	}
+}
+
+// WithMCSClient sets the MCS clients for the Client
+func WithMCSClient(client mcsClient.Interface) ClientOption {
+	return func(c *Client) {
+		c.mcsClient = client
+		mcsInformerFactory := mcsInformers.NewSharedInformerFactory(client, DefaultKubeEventResyncInterval)
+
+		c.informers[informerKeyServiceImport] = mcsInformerFactory.Multicluster().V1alpha1().ServiceImports().Informer()
+		c.informers[informerKeyServiceExport] = mcsInformerFactory.Multicluster().V1alpha1().ServiceExports().Informer()
+	}
+}
+
+// WithPolicyClient sets the policy client for the Client
+func WithPolicyClient(policyClient policyClientset.Interface) ClientOption {
+	return func(c *Client) {
+		c.policyClient = policyClient
+
+		informerFactory := policyInformers.NewSharedInformerFactory(policyClient, DefaultKubeEventResyncInterval)
+
+		c.informers[informerKeyEgress] = informerFactory.Policy().V1alpha1().Egresses().Informer()
+		c.informers[informerKeyIngressBackend] = informerFactory.Policy().V1alpha1().IngressBackends().Informer()
+		c.informers[informerKeyUpstreamTrafficSetting] = informerFactory.Policy().V1alpha1().UpstreamTrafficSettings().Informer()
+		c.informers[informerKeyRetry] = informerFactory.Policy().V1alpha1().Retries().Informer()
+		c.informers[informerKeyTelemetry] = informerFactory.Policy().V1alpha1().Telemetries().Informer()
+	}
+}
+
+func (c *Client) run(stop <-chan struct{}) error {
+	log.Info().Msg("Client started")
+	var hasSynced []cache.InformerSynced
+	var names []string
+
+	if c.informers == nil {
+		return errInitInformers
+	}
+
+	handler := c.defaultEventHandler()
+
+	for name, informer := range c.informers {
+		if informer == nil {
+			continue
+		}
+
+		informer.AddEventHandler(handler)
+
+		go informer.Run(stop)
+		names = append(names, string(name))
+		log.Info().Msgf("Waiting for %s informer cache sync...", name)
+		hasSynced = append(hasSynced, informer.HasSynced)
+	}
+
+	if !cache.WaitForCacheSync(stop, hasSynced...) {
+		return errSyncingCaches
+	}
+
+	log.Info().Msgf("Caches for %v synced successfully", names)
+
+	return nil
+}
+
+// getByKey retrieves an item (based on the given index) from the store of the informer indexed by the given informerKey
+func (c *Client) getByKey(informerKey informerKey, objectKey string) (interface{}, bool, error) {
+	informer, ok := c.informers[informerKey]
+	if !ok {
+		// keithmattix: This is the silent failure option, but perhaps we want to return an error?
+		return nil, false, nil
+	}
+
+	return informer.GetStore().GetByKey(objectKey)
+}
+
+// list returns the contents of the store of the informer indexed by the given informerKey
+func (c *Client) list(informerKey informerKey) []interface{} {
+	informer, ok := c.informers[informerKey]
+	if !ok {
+		// keithmattix: This is the silent failure option, but perhaps we want to return an error?
+		return nil
+	}
+
+	return informer.GetStore().List()
+}
+
+// IsMonitoredNamespace returns a boolean indicating if the namespace is among the list of monitored namespaces
+func (c *Client) IsMonitoredNamespace(namespace string) bool {
+	_, exists, _ := c.informers[informerKeyNamespace].GetStore().GetByKey(namespace)
+	return exists
+}
diff --git a/pkg/k8s/informers/informers.go b/pkg/k8s/informers/informers.go
deleted file mode 100644
index 002d3ded..00000000
--- a/pkg/k8s/informers/informers.go
+++ /dev/null
@@ -1,245 +0,0 @@
-// Package informers centralize informers by creating a single object that
-// runs a set of informers, instead of creating different objects
-// that each manage their own informer collections.
-// A pointer to this object is then shared with all objects that need it.
-package informers
-
-import (
-	"errors"
-	"testing"
-
-	"github.com/rs/zerolog/log"
-	smiTrafficAccessClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned"
-	smiAccessInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/informers/externalversions"
-	smiTrafficSpecClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned"
-	smiTrafficSpecInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/informers/externalversions"
-	smiTrafficSplitClient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned"
-	smiTrafficSplitInformers "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/informers/externalversions"
-
-	mcsClient "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned"
-	mcsInformers "sigs.k8s.io/mcs-api/pkg/client/informers/externalversions"
-
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/fields"
-	"k8s.io/client-go/informers"
-	"k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/tools/cache"
-
-	"github.com/openservicemesh/osm/pkg/constants"
-	configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
-	configInformers "github.com/openservicemesh/osm/pkg/gen/client/config/informers/externalversions"
-	policyClientset "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned"
-	policyInformers "github.com/openservicemesh/osm/pkg/gen/client/policy/informers/externalversions"
-)
-
-// InformerCollectionOption is a function that modifies an informer collection
-type InformerCollectionOption func(*InformerCollection)
-
-// NewInformerCollection creates a new InformerCollection
-func NewInformerCollection(meshName string, stop <-chan struct{}, opts ...InformerCollectionOption) (*InformerCollection, error) {
-	ic := &InformerCollection{
-		meshName:  meshName,
-		informers: map[InformerKey]cache.SharedIndexInformer{},
-	}
-
-	// Execute all of the given options (e.g. set clients, set custom stores, etc.)
-	for _, opt := range opts {
-		if opt != nil {
-			opt(ic)
-		}
-	}
-
-	if err := ic.run(stop); err != nil {
-		log.Error().Err(err).Msg("Could not start informer collection")
-		return nil, err
-	}
-
-	return ic, nil
-}
-
-// WithKubeClient sets the kubeClient for the InformerCollection
-func WithKubeClient(kubeClient kubernetes.Interface) InformerCollectionOption {
-	return func(ic *InformerCollection) {
-		// initialize informers
-		monitorNamespaceLabel := map[string]string{constants.OSMKubeResourceMonitorAnnotation: ic.meshName}
-		monitorSecretLabel := map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue}
-
-		nsLabelSelector := fields.SelectorFromSet(monitorNamespaceLabel).String()
-		nsOption := informers.WithTweakListOptions(func(opt *metav1.ListOptions) {
-			opt.LabelSelector = nsLabelSelector
-		})
-
-		secretLabelSelector := fields.SelectorFromSet(monitorSecretLabel).String()
-		secretOption := informers.WithTweakListOptions(func(opt *metav1.ListOptions) {
-			opt.LabelSelector = secretLabelSelector
-		})
-
-		nsInformerFactory := informers.NewSharedInformerFactoryWithOptions(kubeClient, DefaultKubeEventResyncInterval, nsOption)
-		secretInformerFactory := informers.NewSharedInformerFactoryWithOptions(kubeClient, DefaultKubeEventResyncInterval, secretOption)
-		informerFactory := informers.NewSharedInformerFactory(kubeClient, DefaultKubeEventResyncInterval)
-		v1api := informerFactory.Core().V1()
-		ic.informers[InformerKeyNamespace] = nsInformerFactory.Core().V1().Namespaces().Informer()
-		ic.informers[InformerKeyService] = v1api.Services().Informer()
-		ic.informers[InformerKeyServiceAccount] = v1api.ServiceAccounts().Informer()
-		ic.informers[InformerKeyPod] = v1api.Pods().Informer()
-		ic.informers[InformerKeyEndpoint] = v1api.Endpoints().Informer()
-		ic.informers[InformerKeySecret] = secretInformerFactory.Core().V1().Secrets().Informer()
-	}
-}
-
-// WithSMIClients sets the SMI clients for the InformerCollection
-func WithSMIClients(smiTrafficSplitClient smiTrafficSplitClient.Interface, smiTrafficSpecClient smiTrafficSpecClient.Interface, smiAccessClient smiTrafficAccessClient.Interface) InformerCollectionOption {
-	return func(ic *InformerCollection) {
-		accessInformerFactory := smiAccessInformers.NewSharedInformerFactory(smiAccessClient, DefaultKubeEventResyncInterval)
-		splitInformerFactory := smiTrafficSplitInformers.NewSharedInformerFactory(smiTrafficSplitClient, DefaultKubeEventResyncInterval)
-		specInformerFactory := smiTrafficSpecInformers.NewSharedInformerFactory(smiTrafficSpecClient, DefaultKubeEventResyncInterval)
-
-		ic.informers[InformerKeyTCPRoute] = specInformerFactory.Specs().V1alpha4().TCPRoutes().Informer()
-		ic.informers[InformerKeyHTTPRouteGroup] = specInformerFactory.Specs().V1alpha4().HTTPRouteGroups().Informer()
-		ic.informers[InformerKeyTrafficTarget] = accessInformerFactory.Access().V1alpha3().TrafficTargets().Informer()
-		ic.informers[InformerKeyTrafficSplit] = splitInformerFactory.Split().V1alpha2().TrafficSplits().Informer()
-	}
-}
-
-// WithConfigClient sets the config client for the InformerCollection
-func WithConfigClient(configClient configClientset.Interface, meshConfigName, osmNamespace string) InformerCollectionOption {
-	return func(ic *InformerCollection) {
-		listOption := configInformers.WithTweakListOptions(func(opt *metav1.ListOptions) {
-			opt.FieldSelector = fields.OneTermEqualSelector(metav1.ObjectNameField, meshConfigName).String()
-		})
-		meshConfiginformerFactory := configInformers.NewSharedInformerFactoryWithOptions(configClient, DefaultKubeEventResyncInterval, configInformers.WithNamespace(osmNamespace), listOption)
-		mrcInformerFactory := configInformers.NewSharedInformerFactoryWithOptions(configClient, DefaultKubeEventResyncInterval, configInformers.WithNamespace(osmNamespace))
-		extensionSvcInformerFactory := configInformers.NewSharedInformerFactoryWithOptions(configClient, DefaultKubeEventResyncInterval)
-
-		ic.informers[InformerKeyMeshConfig] = meshConfiginformerFactory.Config().V1alpha2().MeshConfigs().Informer()
-		ic.informers[InformerKeyMeshRootCertificate] = mrcInformerFactory.Config().V1alpha2().MeshRootCertificates().Informer()
-		ic.informers[InformerKeyExtensionService] = extensionSvcInformerFactory.Config().V1alpha2().ExtensionServices().Informer()
-	}
-}
-
-// WithPolicyClient sets the policy client for the InformerCollection
-func WithPolicyClient(policyClient policyClientset.Interface) InformerCollectionOption {
-	return func(ic *InformerCollection) {
-		informerFactory := policyInformers.NewSharedInformerFactory(policyClient, DefaultKubeEventResyncInterval)
-
-		ic.informers[InformerKeyEgress] = informerFactory.Policy().V1alpha1().Egresses().Informer()
-		ic.informers[InformerKeyIngressBackend] = informerFactory.Policy().V1alpha1().IngressBackends().Informer()
-		ic.informers[InformerKeyUpstreamTrafficSetting] = informerFactory.Policy().V1alpha1().UpstreamTrafficSettings().Informer()
-		ic.informers[InformerKeyRetry] = informerFactory.Policy().V1alpha1().Retries().Informer()
-		ic.informers[InformerKeyTelemetry] = informerFactory.Policy().V1alpha1().Telemetries().Informer()
-	}
-}
-
-// WithMCSClient sets the MCS clients for the InformerCollection
-func WithMCSClient(client mcsClient.Interface) InformerCollectionOption {
-	return func(ic *InformerCollection) {
-		mcsInformerFactory := mcsInformers.NewSharedInformerFactory(client, DefaultKubeEventResyncInterval)
-
-		ic.informers[InformerKeyServiceImport] = mcsInformerFactory.Multicluster().V1alpha1().ServiceExports().Informer()
-		ic.informers[InformerKeyServiceExport] = mcsInformerFactory.Multicluster().V1alpha1().ServiceExports().Informer()
-	}
-}
-
-func (ic *InformerCollection) run(stop <-chan struct{}) error {
-	log.Info().Msg("InformerCollection started")
-	var hasSynced []cache.InformerSynced
-	var names []string
-
-	if ic.informers == nil {
-		return errInitInformers
-	}
-
-	for name, informer := range ic.informers {
-		if informer == nil {
-			continue
-		}
-
-		go informer.Run(stop)
-		names = append(names, string(name))
-		log.Info().Msgf("Waiting for %s informer cache sync...", name)
-		hasSynced = append(hasSynced, informer.HasSynced)
-	}
-
-	if !cache.WaitForCacheSync(stop, hasSynced...) {
-		return errSyncingCaches
-	}
-
-	log.Info().Msgf("Caches for %v synced successfully", names)
-
-	return nil
-}
-
-// Add is only exported for the sake of tests and requires a testing.T to ensure it's
-// never used in production. This functionality was added for the express purpose of testing
-// flexibility since alternatives can often lead to flaky tests and race conditions
-// between the time an object is added to a fake clientset and when that object
-// is actually added to the informer `cache.Store`
-func (ic *InformerCollection) Add(key InformerKey, obj interface{}, t *testing.T) error {
-	if t == nil {
-		return errors.New("this method should only be used in tests")
-	}
-
-	i, ok := ic.informers[key]
-	if !ok {
-		t.Errorf("tried to add to nil store with key %s", key)
-	}
-
-	return i.GetStore().Add(obj)
-}
-
-// Update is only exported for the sake of tests and requires a testing.T to ensure it's
-// never used in production. This functionality was added for the express purpose of testing
-// flexibility since the alternatives can often lead to flaky tests and race conditions
-// between the time an object is added to a fake clientset and when that object
-// is actually added to the informer `cache.Store`
-func (ic *InformerCollection) Update(key InformerKey, obj interface{}, t *testing.T) error {
-	if t == nil {
-		return errors.New("this method should only be used in tests")
-	}
-
-	i, ok := ic.informers[key]
-	if !ok {
-		t.Errorf("tried to update to nil store with key %s", key)
-	}
-
-	return i.GetStore().Update(obj)
-}
-
-// AddEventHandler adds an handler to the informer indexed by the given InformerKey
-func (ic *InformerCollection) AddEventHandler(informerKey InformerKey, handler cache.ResourceEventHandler) {
-	i, ok := ic.informers[informerKey]
-	if !ok {
-		log.Info().Msgf("attempted to add event handler for nil informer %s", informerKey)
-		return
-	}
-
-	i.AddEventHandler(handler)
-}
-
-// GetByKey retrieves an item (based on the given index) from the store of the informer indexed by the given InformerKey
-func (ic *InformerCollection) GetByKey(informerKey InformerKey, objectKey string) (interface{}, bool, error) {
-	informer, ok := ic.informers[informerKey]
-	if !ok {
-		// keithmattix: This is the silent failure option, but perhaps we want to return an error?
-		return nil, false, nil
-	}
-
-	return informer.GetStore().GetByKey(objectKey)
-}
-
-// List returns the contents of the store of the informer indexed by the given InformerKey
-func (ic *InformerCollection) List(informerKey InformerKey) []interface{} {
-	informer, ok := ic.informers[informerKey]
-	if !ok {
-		// keithmattix: This is the silent failure option, but perhaps we want to return an error?
-		return nil
-	}
-
-	return informer.GetStore().List()
-}
-
-// IsMonitoredNamespace returns a boolean indicating if the namespace is among the list of monitored namespaces
-func (ic InformerCollection) IsMonitoredNamespace(namespace string) bool {
-	_, exists, _ := ic.informers[InformerKeyNamespace].GetStore().GetByKey(namespace)
-	return exists
-}
diff --git a/pkg/k8s/informers/types.go b/pkg/k8s/informers/types.go
deleted file mode 100644
index d792e64c..00000000
--- a/pkg/k8s/informers/types.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package informers
-
-import (
-	"errors"
-	"time"
-
-	"k8s.io/client-go/tools/cache"
-)
-
-// InformerKey stores the different Informers we keep for K8s resources
-type InformerKey string
-
-const (
-	// InformerKeyNamespace is the InformerKey for a Namespace informer
-	InformerKeyNamespace InformerKey = "Namespace"
-	// InformerKeyService is the InformerKey for a Service informer
-	InformerKeyService InformerKey = "Service"
-	// InformerKeyPod is the InformerKey for a Pod informer
-	InformerKeyPod InformerKey = "Pod"
-	// InformerKeyEndpoint is the InformerKey for a Endpoint informer
-	InformerKeyEndpoint InformerKey = "Endpoint"
-	// InformerKeyServiceAccount is the InformerKey for a ServiceAccount informer
-	InformerKeyServiceAccount InformerKey = "ServiceAccount"
-	// InformerKeySecret is the InformerKey for a Secret informer
-	InformerKeySecret InformerKey = "Secret"
-
-	// InformerKeyTrafficSplit is the InformerKey for a TrafficSplit informer
-	InformerKeyTrafficSplit InformerKey = "TrafficSplit"
-	// InformerKeyTrafficTarget is the InformerKey for a TrafficTarget informer
-	InformerKeyTrafficTarget InformerKey = "TrafficTarget"
-	// InformerKeyHTTPRouteGroup is the InformerKey for a HTTPRouteGroup informer
-	InformerKeyHTTPRouteGroup InformerKey = "HTTPRouteGroup"
-	// InformerKeyTCPRoute is the InformerKey for a TCPRoute informer
-	InformerKeyTCPRoute InformerKey = "TCPRoute"
-
-	// InformerKeyMeshConfig is the InformerKey for a MeshConfig informer
-	InformerKeyMeshConfig InformerKey = "MeshConfig"
-	// InformerKeyMeshRootCertificate is the InformerKey for a MeshRootCertificate informer
-	InformerKeyMeshRootCertificate InformerKey = "MeshRootCertificate"
-	// InformerKeyExtensionService is the InformerKey for an ExtensionService informer
-	InformerKeyExtensionService InformerKey = "ExtensionService"
-
-	// InformerKeyEgress is the InformerKey for a Egress informer
-	InformerKeyEgress InformerKey = "Egress"
-	// InformerKeyIngressBackend is the InformerKey for a IngressBackend informer
-	InformerKeyIngressBackend InformerKey = "IngressBackend"
-	// InformerKeyUpstreamTrafficSetting is the InformerKey for a UpstreamTrafficSetting informer
-	InformerKeyUpstreamTrafficSetting InformerKey = "UpstreamTrafficSetting"
-	// InformerKeyRetry is the InformerKey for a Retry informer
-	InformerKeyRetry InformerKey = "Retry"
-	// InformerKeyTelemetry is the InformerKey for a Telemetry informer
-	InformerKeyTelemetry InformerKey = "Telemetry"
-
-	// InformerKeyServiceImport is the InformerKey for a ServiceImport informer
-	InformerKeyServiceImport InformerKey = "ServiceImport"
-	// InformerKeyServiceExport is the InformerKey for a ServiceExport informer
-	InformerKeyServiceExport InformerKey = "ServiceExport"
-)
-
-const (
-	// DefaultKubeEventResyncInterval is the default resync interval for k8s events
-	// This is set to 0 because we do not need resyncs from k8s client, and have our
-	// own Ticker to turn on periodic resyncs.
-	DefaultKubeEventResyncInterval = 0 * time.Second
-)
-
-var (
-	errInitInformers = errors.New("informer not initialized")
-	errSyncingCaches = errors.New("failed initial cache sync for informers")
-)
-
-// InformerCollection is an abstraction around a set of informers
-// initialized with the clients stored in its fields. This data
-// type should only be passed around as a pointer
-type InformerCollection struct {
-	informers map[InformerKey]cache.SharedIndexInformer
-	meshName  string
-}
diff --git a/pkg/k8s/mock_controller_generated.go b/pkg/k8s/mock_controller_generated.go
index 9f986982..63ea1017 100644
--- a/pkg/k8s/mock_controller_generated.go
+++ b/pkg/k8s/mock_controller_generated.go
@@ -17,6 +17,7 @@ import (
 	v1alpha20 "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
 	v1 "k8s.io/api/core/v1"
 	types "k8s.io/apimachinery/pkg/types"
+	cache "k8s.io/client-go/tools/cache"
 	v1alpha10 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
 )
 
@@ -43,6 +44,18 @@ func (m *MockController) EXPECT() *MockControllerMockRecorder {
 	return m.recorder
 }
 
+// AddMeshRootCertificateEventHandler mocks base method.
+func (m *MockController) AddMeshRootCertificateEventHandler(arg0 cache.ResourceEventHandler) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "AddMeshRootCertificateEventHandler", arg0)
+}
+
+// AddMeshRootCertificateEventHandler indicates an expected call of AddMeshRootCertificateEventHandler.
+func (mr *MockControllerMockRecorder) AddMeshRootCertificateEventHandler(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMeshRootCertificateEventHandler", reflect.TypeOf((*MockController)(nil).AddMeshRootCertificateEventHandler), arg0)
+}
+
 // GetEndpoints mocks base method.
 func (m *MockController) GetEndpoints(arg0, arg1 string) (*v1.Endpoints, error) {
 	m.ctrl.T.Helper()
diff --git a/pkg/k8s/types.go b/pkg/k8s/types.go
index a9d23a22..3bdce539 100644
--- a/pkg/k8s/types.go
+++ b/pkg/k8s/types.go
@@ -4,11 +4,11 @@ package k8s
 
 import (
 	"context"
-	"time"
 
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
 
 	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha3"
 	spec "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha4"
@@ -21,7 +21,6 @@ import (
 	configv1alpha2Client "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
 	policyv1alpha1Client "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned"
 
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/models"
@@ -49,20 +48,13 @@ const (
 	DeleteEvent EventType = "DELETE"
 )
 
-const (
-	// DefaultKubeEventResyncInterval is the default resync interval for k8s events
-	// This is set to 0 because we do not need resyncs from k8s client, and have our
-	// own Ticker to turn on periodic resyncs.
-	DefaultKubeEventResyncInterval = 0 * time.Second
-)
-
 // Client is the type used to represent the k8s client for the native k8s resources
 type Client struct {
 	policyClient   policyv1alpha1Client.Interface
 	configClient   configv1alpha2Client.Interface
 	mcsClient      mcsv1alpha1Client.Interface
 	kubeClient     kubernetes.Interface
-	informers      *informers.InformerCollection
+	informers      map[informerKey]cache.SharedIndexInformer
 	msgBroker      *messaging.Broker
 	osmNamespace   string
 	meshConfigName string
@@ -120,6 +112,8 @@ type PassthroughInterface interface {
 
 	GetMeshConfig() configv1alpha2.MeshConfig
 	GetMeshRootCertificate(mrcName string) *configv1alpha2.MeshRootCertificate
+	AddMeshRootCertificateEventHandler(handler cache.ResourceEventHandler)
+
 	ListMeshRootCertificates() ([]*configv1alpha2.MeshRootCertificate, error)
 	UpdateMeshRootCertificate(obj *configv1alpha2.MeshRootCertificate) (*configv1alpha2.MeshRootCertificate, error)
 	UpdateMeshRootCertificateStatus(obj *configv1alpha2.MeshRootCertificate) (*configv1alpha2.MeshRootCertificate, error)
diff --git a/pkg/messaging/broker.go b/pkg/messaging/broker.go
index 82e0ccb6..e905e19c 100644
--- a/pkg/messaging/broker.go
+++ b/pkg/messaging/broker.go
@@ -34,21 +34,27 @@ func NewBroker(stopCh <-chan struct{}) *Broker {
 		proxyUpdatePubSub: pubsub.New(0),
 		proxyUpdateCh:     make(chan string),
 		kubeEventPubSub:   pubsub.New(0),
+		stop:              stopCh,
 	}
 
-	go b.runWorkqueueProcessor(stopCh)
-	go b.runProxyUpdateDispatcher(stopCh)
-	go b.queueLenMetric(stopCh, 5*time.Second)
+	go b.runWorkqueueProcessor()
+	go b.runProxyUpdateDispatcher()
+	go b.queueLenMetric(5 * time.Second)
 
 	return b
 }
 
-func (b *Broker) queueLenMetric(stop <-chan struct{}, interval time.Duration) {
+// Done returns a channel that's closed when the broker is shutdown.
+func (b *Broker) Done() <-chan struct{} {
+	return b.stop
+}
+
+func (b *Broker) queueLenMetric(interval time.Duration) {
 	tick := time.NewTicker(interval)
 	defer tick.Stop()
 	for {
 		select {
-		case <-stop:
+		case <-b.stop:
 			return
 		case <-tick.C:
 			metricsstore.DefaultMetricsStore.EventsQueued.Set(float64(b.queue.Len()))
@@ -88,7 +94,7 @@ func (b *Broker) GetTotalDispatchedProxyEventCount() uint64 {
 
 // runWorkqueueProcessor starts a goroutine to process events from the workqueue until
 // signalled to stop on the given channel.
-func (b *Broker) runWorkqueueProcessor(stopCh <-chan struct{}) {
+func (b *Broker) runWorkqueueProcessor() {
 	// Start the goroutine workqueue to process kubernetes events
 	// The continuous processing of items in the workqueue will run
 	// until signalled to stop.
@@ -101,7 +107,7 @@ func (b *Broker) runWorkqueueProcessor(stopCh <-chan struct{}) {
 			}
 		},
 		time.Second,
-		stopCh,
+		b.stop,
 	)
 }
 
@@ -112,7 +118,7 @@ func (b *Broker) runWorkqueueProcessor(stopCh <-chan struct{}) {
 // 2. Max window timer that caps the max duration a sliding window can be reset to
 // When either of the above timers expire, the proxy update event is published
 // on the dedicated pub-sub instance.
-func (b *Broker) runProxyUpdateDispatcher(stopCh <-chan struct{}) {
+func (b *Broker) runProxyUpdateDispatcher() {
 	// batchTimer and maxTimer are updated by the dispatcher routine
 	// when events are processed and timeouts expire. They are initialized
 	// with a large timeout (a decade) so they don't time out till an event
@@ -201,7 +207,7 @@ func (b *Broker) runProxyUpdateDispatcher(stopCh <-chan struct{}) {
 			dispatchPending = false
 			batchCount = 0
 
-		case <-stopCh:
+		case <-b.stop:
 			log.Info().Msg("Proxy update dispatcher received stop signal, exiting")
 			return
 		}
diff --git a/pkg/messaging/types.go b/pkg/messaging/types.go
index 20b61e37..f8ccc490 100644
--- a/pkg/messaging/types.go
+++ b/pkg/messaging/types.go
@@ -24,6 +24,8 @@ type Broker struct {
 	totalQEventCount               uint64
 	totalQProxyEventCount          uint64
 	totalDispatchedProxyEventCount uint64
+
+	stop <-chan struct{}
 }
 
 const (
diff --git a/pkg/reconciler/client.go b/pkg/reconciler/client.go
index 024c90b9..94f766e2 100644
--- a/pkg/reconciler/client.go
+++ b/pkg/reconciler/client.go
@@ -15,11 +15,10 @@ import (
 	"github.com/openservicemesh/osm/pkg/constants"
 	"github.com/openservicemesh/osm/pkg/errcode"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	k8sinformers "github.com/openservicemesh/osm/pkg/k8s/informers"
 )
 
 // NewReconcilerClient implements a client to reconcile osm managed resources
-func NewReconcilerClient(kubeClient kubernetes.Interface, apiServerClient clientset.Interface, meshName, osmVersion string, stop chan struct{}, selectInformers ...k8sinformers.InformerKey) error {
+func NewReconcilerClient(kubeClient kubernetes.Interface, apiServerClient clientset.Interface, meshName, osmVersion string, stop chan struct{}, selectInformers ...InformerKey) error {
 	// Initialize client object
 	c := client{
 		kubeClient:      kubeClient,
@@ -30,22 +29,12 @@ func NewReconcilerClient(kubeClient kubernetes.Interface, apiServerClient client
 	}
 
 	// Initialize informers
-	informerInitHandlerMap := map[k8sinformers.InformerKey]func(){
+	informerInitHandlerMap := map[InformerKey]func(){
 		CrdInformerKey:               c.initCustomResourceDefinitionMonitor,
 		MutatingWebhookInformerKey:   c.initMutatingWebhookConfigurationMonitor,
 		ValidatingWebhookInformerKey: c.initValidatingWebhookConfigurationMonitor,
 	}
 
-	// If specific informers are not selected to be initialized, initialize all informers
-	if len(selectInformers) == 0 {
-		informers := []k8sinformers.InformerKey{MutatingWebhookInformerKey, ValidatingWebhookInformerKey}
-		// initialize informer for CRDs only if the apiServerClient is not nil
-		if apiServerClient != nil {
-			informers = append(informers, CrdInformerKey)
-		}
-		selectInformers = informers
-	}
-
 	for _, informer := range selectInformers {
 		informerInitHandlerMap[informer]()
 	}
diff --git a/pkg/reconciler/types.go b/pkg/reconciler/types.go
index 34a3819e..f9838e86 100644
--- a/pkg/reconciler/types.go
+++ b/pkg/reconciler/types.go
@@ -8,28 +8,30 @@ import (
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/cache"
 
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 )
 
 var log = logger.New("reconciler")
 
+// InformerKey is a key used to identify an informer for a specific K8s kind.
+type InformerKey string
+
 const (
 	// CrdInformerKey lookup identifier
-	CrdInformerKey informers.InformerKey = "CRDInformerKey"
+	CrdInformerKey InformerKey = "CRDInformerKey"
 
 	// MutatingWebhookInformerKey lookup identifier
-	MutatingWebhookInformerKey informers.InformerKey = "MutatingWebhookConfigInformerKey"
+	MutatingWebhookInformerKey InformerKey = "MutatingWebhookConfigInformerKey"
 
 	// ValidatingWebhookInformerKey lookup identifier
-	ValidatingWebhookInformerKey informers.InformerKey = "ValidatingWebhookConfigInformerKey"
+	ValidatingWebhookInformerKey InformerKey = "ValidatingWebhookConfigInformerKey"
 
 	// nameIndex is the lookup name for the most comment index function, which is to index by the name field
 	nameIndex string = "name"
 )
 
 // informerCollection is the type holding the collection of informers we keep
-type informerCollection map[informers.InformerKey]cache.SharedIndexInformer
+type informerCollection map[InformerKey]cache.SharedIndexInformer
 
 // client is a struct for all components necessary to connect to and maintain state of a Kubernetes cluster
 type client struct {


Test patch:
diff --git a/pkg/catalog/traffictarget_test.go b/pkg/catalog/traffictarget_test.go
index 695c0fd4..c9b21838 100644
--- a/pkg/catalog/traffictarget_test.go
+++ b/pkg/catalog/traffictarget_test.go
@@ -8,15 +8,10 @@ import (
 	smiAccess "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha3"
 	smiSpecs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha4"
 	smiSplit "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
-	smiAccessClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned/fake"
-	smiSpecClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned/fake"
-	smiSplitClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake"
 	"github.com/stretchr/testify/assert"
 	tassert "github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	fakePolicyClient "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/service"
 	"github.com/openservicemesh/osm/pkg/tests"
 
@@ -918,12 +913,6 @@ func TestListTrafficSplitsByOptions(t *testing.T) {
 	mockCompute.EXPECT().IsMonitoredNamespace(tests.BookbuyerService.Namespace).Return(true).AnyTimes()
 
 	testNamespaceName := "test"
-	fakeClient := fakePolicyClient.NewSimpleClientset()
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-	ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient), informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet))
-	a.Nil(err)
 	meshCatalog := MeshCatalog{
 		Interface: mockCompute,
 	}
@@ -947,8 +936,6 @@ func TestListTrafficSplitsByOptions(t *testing.T) {
 			},
 		},
 	}
-	err = ic.Add(informers.InformerKeyTrafficSplit, obj, t)
-	a.Nil(err)
 	mockCompute.EXPECT().ListTrafficSplits().Return([]*smiSplit.TrafficSplit{obj}).AnyTimes()
 
 	// Verify
@@ -981,12 +968,6 @@ func TestListTrafficTargetsByOptions(t *testing.T) {
 	mockCompute.EXPECT().IsMonitoredNamespace(tests.BookbuyerService.Namespace).Return(true).AnyTimes()
 
 	testNamespaceName := "test"
-	fakeClient := fakePolicyClient.NewSimpleClientset()
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-	ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient), informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet))
-	a.Nil(err)
 	meshCatalog := MeshCatalog{
 		Interface: mockCompute,
 	}
@@ -1018,8 +999,6 @@ func TestListTrafficTargetsByOptions(t *testing.T) {
 			}},
 		},
 	}
-	err = ic.Add(informers.InformerKeyTrafficTarget, obj, t)
-	a.Nil(err)
 	mockCompute.EXPECT().ListTrafficTargets().Return([]*smiAccess.TrafficTarget{obj}).AnyTimes()
 
 	// Verify
diff --git a/pkg/certificate/providers/config_test.go b/pkg/certificate/providers/config_test.go
index f89abb0e..67b79df2 100644
--- a/pkg/certificate/providers/config_test.go
+++ b/pkg/certificate/providers/config_test.go
@@ -16,20 +16,22 @@ import (
 	"k8s.io/client-go/rest"
 
 	"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
+	"github.com/openservicemesh/osm/pkg/compute"
+	"github.com/openservicemesh/osm/pkg/compute/kube"
 	"github.com/openservicemesh/osm/pkg/constants"
 	configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
 	fakeConfigClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
+	"github.com/openservicemesh/osm/pkg/messaging"
 
 	"github.com/openservicemesh/osm/pkg/certificate"
 	"github.com/openservicemesh/osm/pkg/certificate/pem"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 )
 
 func TestGetCertificateManager(t *testing.T) {
 	mockCtrl := gomock.NewController(t)
-	k8sMock := k8s.NewMockController(mockCtrl)
-	k8sMock.EXPECT().GetMeshConfig().AnyTimes()
+	computeMock := compute.NewMockInterface(mockCtrl)
+	computeMock.EXPECT().GetMeshConfig().AnyTimes()
 
 	type testCase struct {
 		name        string
@@ -132,7 +134,7 @@ func TestGetCertificateManager(t *testing.T) {
 				getCA = oldCA
 			}()
 
-			manager, err := NewCertificateManager(context.Background(), tc.kubeClient, tc.restConfig, tc.providerNamespace, tc.options, k8sMock, 1*time.Hour, "cluster.local")
+			manager, err := NewCertificateManager(context.Background(), tc.kubeClient, tc.restConfig, tc.providerNamespace, tc.options, computeMock, 1*time.Hour, "cluster.local")
 			if tc.expectError {
 				assert.Empty(manager)
 				assert.Error(err)
@@ -150,10 +152,6 @@ func TestGetCertificateManager(t *testing.T) {
 }
 
 func TestGetCertificateManagerFromMRC(t *testing.T) {
-	mockCtrl := gomock.NewController(t)
-	k8sMock := k8s.NewMockController(mockCtrl)
-	k8sMock.EXPECT().GetMeshConfig().AnyTimes()
-
 	type testCase struct {
 		name        string
 		expectError bool
@@ -639,11 +637,16 @@ func TestGetCertificateManagerFromMRC(t *testing.T) {
 				getCA = oldCA
 			}()
 
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithKubeClient(tc.kubeClient), informers.WithConfigClient(tc.configClient, "", "osm-system"))
-			assert.NoError(err)
-			assert.NotNil(ic)
+			stop := make(chan struct{})
+			client, err := k8s.NewClient(tc.providerNamespace, "osm-mesh-config", messaging.NewBroker(stop),
+				k8s.WithKubeClient(tc.kubeClient, "osm"),
+				k8s.WithConfigClient(tc.configClient),
+			)
+			assert.Nil(err)
+
+			computeClient := kube.NewClient(client)
 
-			manager, err := NewCertificateManagerFromMRC(context.Background(), tc.kubeClient, tc.restConfig, tc.providerNamespace, tc.options, k8sMock, ic, 1*time.Hour)
+			manager, err := NewCertificateManagerFromMRC(context.Background(), tc.kubeClient, tc.restConfig, tc.providerNamespace, tc.options, computeClient, 1*time.Hour)
 			if tc.expectError {
 				assert.Empty(manager)
 				assert.Error(err)
diff --git a/pkg/compute/kube/client_test.go b/pkg/compute/kube/client_test.go
index 72764823..4c09ccfe 100644
--- a/pkg/compute/kube/client_test.go
+++ b/pkg/compute/kube/client_test.go
@@ -25,21 +25,17 @@ import (
 	. "github.com/onsi/gomega"
 
 	policyv1alpha1 "github.com/openservicemesh/osm/pkg/apis/policy/v1alpha1"
-	fakePolicyClient "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/models"
 
 	"github.com/openservicemesh/osm/pkg/constants"
 	"github.com/openservicemesh/osm/pkg/endpoint"
 	"github.com/openservicemesh/osm/pkg/identity"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/service"
 	"github.com/openservicemesh/osm/pkg/tests"
 )
 
-var testMeshName = "mesh"
-
 var _ = Describe("Test Kube client Provider (w/o kubecontroller)", func() {
 	var (
 		mockCtrl           *gomock.Controller
@@ -486,11 +482,16 @@ func TestGetServicesForServiceIdentity(t *testing.T) {
 				})
 			}
 			testClient := testclient.NewSimpleClientset(objs...)
-			ic, err := informers.NewInformerCollection("test-mesh", stop, informers.WithKubeClient(testClient))
+
+			k8sClient, err := k8s.NewClient("osm-ns", tests.OsmMeshConfigName, messaging.NewBroker(stop),
+				k8s.WithKubeClient(testClient, "test-mesh"),
+			)
 			assert.NoError(err)
 			c := &client{
-				kubeController: k8s.NewClient("osm-ns", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, messaging.NewBroker(stop)),
+				kubeController: k8sClient,
 			}
+			assert.NoError(err)
+
 			actual := c.GetServicesForServiceIdentity(tc.svcIdentity)
 			assert.ElementsMatch(tc.expected, actual)
 		})
@@ -551,8 +552,7 @@ func TestGetHostnamesForServicePort(t *testing.T) {
 
 func TestIsMetricsEnabled(t *testing.T) {
 	testCases := []struct {
-		name        string
-		informerOpt informers.InformerCollectionOption
+		name string
 
 		pod           *corev1.Pod
 		expectEnabled bool
@@ -820,10 +820,12 @@ func TestListServicesForProxy(t *testing.T) {
 				})
 			}
 			testClient := testclient.NewSimpleClientset(objs...)
-			ic, err := informers.NewInformerCollection("test-mesh", stop, informers.WithKubeClient(testClient))
+			k8sClient, err := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, messaging.NewBroker(stop),
+				k8s.WithKubeClient(testClient, "test-mesh"),
+			)
 			assert.NoError(err)
 			c := &client{
-				kubeController: k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, messaging.NewBroker(stop)),
+				kubeController: k8sClient,
 			}
 			actual, err := c.ListServicesForProxy(tc.proxy)
 			assert.ElementsMatch(tc.expected, actual)
@@ -1140,18 +1142,7 @@ func TestListEgressPoliciesForSourceAccount(t *testing.T) {
 		t.Run(fmt.Sprintf("Running test case %d: %s", i, tc.name), func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient))
-			a.Nil(err)
-
 			c := NewClient(mockKubeController)
-			a.Nil(err)
-			a.NotNil(c)
-
-			// Create fake egress policies
-			for _, egressPolicy := range tc.allEgresses {
-				_ = ic.Add(informers.InformerKeyEgress, egressPolicy, t)
-			}
 
 			mockKubeController.EXPECT().ListEgressPolicies().Return(tc.allEgresses).AnyTimes()
 			actual := c.ListEgressPoliciesForServiceAccount(tc.source)
@@ -1338,19 +1329,7 @@ func TestGetIngressBackendPolicy(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := assert.New(t)
-
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient))
-			a.Nil(err)
-
 			c := NewClient(mockKubeController)
-			a.Nil(err)
-			a.NotNil(c)
-
-			// Create fake ingress backends
-			for _, ingressBackend := range tc.allResources {
-				_ = ic.Add(informers.InformerKeyIngressBackend, ingressBackend, t)
-			}
 
 			mockKubeController.EXPECT().ListIngressBackendPolicies().Return(tc.allResources).AnyTimes()
 
@@ -1489,20 +1468,7 @@ func TestListRetryPolicy(t *testing.T) {
 	for i, tc := range testCases {
 		t.Run(fmt.Sprintf("Running test case %d: %s", i, tc.name), func(t *testing.T) {
 			a := assert.New(t)
-
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient))
-			a.Nil(err)
-
 			c := NewClient(mockKubeController)
-			a.Nil(err)
-			a.NotNil(c)
-
-			// Create fake retry policies
-			for _, retryPolicy := range tc.allRetries {
-				err := ic.Add(informers.InformerKeyRetry, retryPolicy, t)
-				a.Nil(err)
-			}
 
 			mockKubeController.EXPECT().ListRetryPolicies().Return(tc.allRetries).AnyTimes()
 
@@ -1690,12 +1656,11 @@ func TestGetProxyStatsHeaders(t *testing.T) {
 			stop := make(chan struct{})
 			defer close(stop)
 
-			informer, err := informers.NewInformerCollection(tests.MeshName, stop,
-				informers.WithKubeClient(fakeClient),
+			k8sClient, err := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, messaging.NewBroker(stop),
+				k8s.WithKubeClient(fakeClient, tests.MeshName),
 			)
 			assert.NoError(err)
-			controller := k8s.NewClient("ns", "", informer, nil, nil, nil, nil, messaging.NewBroker(stop))
-			c := NewClient(controller)
+			c := NewClient(k8sClient)
 			actual, err := c.GetProxyStatsHeaders(test.proxy)
 			if test.expectErr {
 				assert.Error(err)
@@ -1775,19 +1740,7 @@ func TestGetUpstreamTrafficSettingByService(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient))
-			a.Nil(err)
-
 			c := NewClient(mockKubeController)
-			a.Nil(err)
-			a.NotNil(c)
-
-			// Create fake egress policies
-			for _, resource := range tc.allResources {
-				_ = ic.Add(informers.InformerKeyUpstreamTrafficSetting, resource, t)
-			}
-
 			mockKubeController.EXPECT().ListUpstreamTrafficSettings().Return(tc.allResources).AnyTimes()
 
 			actual := c.GetUpstreamTrafficSettingByService(tc.service)
@@ -1849,18 +1802,7 @@ func TestGetUpstreamTrafficSettingByNamespace(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection("osm", nil, informers.WithPolicyClient(fakeClient))
-			a.Nil(err)
-
 			c := NewClient(mockKubeController)
-			a.Nil(err)
-			a.NotNil(c)
-
-			// Create fake egress policies
-			for _, resource := range tc.allResources {
-				_ = ic.Add(informers.InformerKeyUpstreamTrafficSetting, resource, t)
-			}
 
 			mockKubeController.EXPECT().ListUpstreamTrafficSettings().Return(tc.allResources).AnyTimes()
 			mockKubeController.EXPECT().GetUpstreamTrafficSetting(name1).Return(resource1).AnyTimes()
@@ -2283,13 +2225,13 @@ func TestK8sServicesToMeshServices(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			assert := tassert.New(t)
 
+			stop := make(chan struct{})
 			fakeClient := testclient.NewSimpleClientset(tc.svcEndpoints...)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(fakeClient))
-			assert.Nil(err)
-
-			kubecontroller := k8s.NewClient("", "", ic, nil, nil, nil, nil, messaging.NewBroker(make(<-chan struct{})))
-
-			c := NewClient(kubecontroller)
+			k8sClient, err := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, messaging.NewBroker(stop),
+				k8s.WithKubeClient(fakeClient, "test-mesh"),
+			)
+			assert.NoError(err)
+			c := NewClient(k8sClient)
 
 			actual := c.serviceToMeshServices(tc.svc)
 			assert.ElementsMatch(tc.expected, actual)
@@ -2419,14 +2361,13 @@ func TestGetMeshService(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			_ = ic.Add(informers.InformerKeyService, tc.svc, t)
-			_ = ic.Add(informers.InformerKeyEndpoint, tc.endpoints, t)
-
-			controller := k8s.NewClient(osmNamespace, "", ic, nil, nil, nil, nil, messaging.NewBroker(make(chan struct{})))
 
-			c := NewClient(controller)
+			stop := make(chan struct{})
+			k8sClient, err := k8s.NewClient(osmNamespace, tests.OsmMeshConfigName, messaging.NewBroker(stop),
+				k8s.WithKubeClient(testclient.NewSimpleClientset(tc.svc, tc.endpoints), "test-mesh"),
+			)
+			a.NoError(err)
+			c := NewClient(k8sClient)
 
 			actual, err := c.GetMeshService(tc.namespacedSvc.Name, tc.namespacedSvc.Namespace, tc.port)
 			a.Equal(tc.expectedTargetPort, actual.TargetPort)
diff --git a/pkg/envoy/generator/generator_benchmark_test.go b/pkg/envoy/generator/generator_benchmark_test.go
index 473c10ab..365d6292 100644
--- a/pkg/envoy/generator/generator_benchmark_test.go
+++ b/pkg/envoy/generator/generator_benchmark_test.go
@@ -4,47 +4,44 @@ import (
 	"context"
 	"fmt"
 	"testing"
+	"time"
 
 	"github.com/google/uuid"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	k8sClientFake "k8s.io/client-go/kubernetes/fake"
-	mcsFake "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned/fake"
 
 	configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
 	"github.com/openservicemesh/osm/pkg/catalog"
+	tresorFake "github.com/openservicemesh/osm/pkg/certificate/providers/tresor/fake"
 	"github.com/openservicemesh/osm/pkg/compute/kube"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
-	"github.com/openservicemesh/osm/pkg/logger"
-	"github.com/openservicemesh/osm/pkg/messaging"
-	"github.com/openservicemesh/osm/pkg/models"
-	"github.com/openservicemesh/osm/pkg/signals"
-
-	"github.com/openservicemesh/osm/pkg/certificate"
-
 	"github.com/openservicemesh/osm/pkg/constants"
 	configFake "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	policyFake "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
+	"github.com/openservicemesh/osm/pkg/logger"
+	"github.com/openservicemesh/osm/pkg/messaging"
+	"github.com/openservicemesh/osm/pkg/models"
+	"github.com/openservicemesh/osm/pkg/signals"
 	"github.com/openservicemesh/osm/pkg/tests"
 )
 
 func setupTestGenerator(b *testing.B) (*models.Proxy, *EnvoyConfigGenerator) {
 	stop := signals.RegisterExitHandlers()
 	msgBroker := messaging.NewBroker(stop)
-	kubeClient := k8sClientFake.NewSimpleClientset()
-	configClient := configFake.NewSimpleClientset()
-	policyClient := policyFake.NewSimpleClientset()
-	mcsClient := mcsFake.NewSimpleClientset()
-	informerCollection, err := informers.NewInformerCollection(tests.MeshName, stop,
-		informers.WithKubeClient(kubeClient),
-		informers.WithConfigClient(configClient, tests.OsmMeshConfigName, tests.OsmNamespace),
-	)
-	if err != nil {
-		b.Fatalf("Failed to create informer collection: %s", err)
+
+	// monitor namespace
+	namespace := tests.Namespace
+	nsObj := &corev1.Namespace{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:   namespace,
+			Labels: map[string]string{constants.OSMKubeResourceMonitorAnnotation: tests.MeshName},
+		},
 	}
-	kubeController := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, informerCollection, kubeClient, policyClient, configClient, mcsClient, msgBroker)
-	kubeProvider := kube.NewClient(kubeController)
+	proxyUUID := uuid.New()
+	labels := map[string]string{constants.EnvoyUniqueIDLabelName: proxyUUID.String()}
+	pod := tests.NewPodFixture(namespace, fmt.Sprintf("pod-0-%s", proxyUUID), tests.BookstoreServiceAccountName, tests.PodLabels)
+	pod.Labels[constants.EnvoyUniqueIDLabelName] = proxyUUID.String()
 
 	meshConfig := configv1alpha2.MeshConfig{
 		TypeMeta: metav1.TypeMeta{
@@ -74,22 +71,27 @@ func setupTestGenerator(b *testing.B) (*models.Proxy, *EnvoyConfigGenerator) {
 			},
 		},
 	}
-	_, err = configClient.ConfigV1alpha2().MeshConfigs(tests.OsmNamespace).Create(context.Background(), &meshConfig, metav1.CreateOptions{})
+
+	svc := tests.NewServiceFixture(tests.BookstoreV1ServiceName, namespace, labels)
+
+	kubeClient := k8sClientFake.NewSimpleClientset(nsObj, pod, svc)
+	configClient := configFake.NewSimpleClientset(&meshConfig)
+	policyClient := policyFake.NewSimpleClientset()
+
+	kubeController, err := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, msgBroker,
+		k8s.WithKubeClient(kubeClient, tests.MeshName),
+		k8s.WithConfigClient(configClient),
+		k8s.WithPolicyClient(policyClient),
+	)
 	if err != nil {
-		b.Fatalf("Failed to create mesh config: %v", err)
+		b.Fatalf("Failed to create informer collection: %s", err)
 	}
+	kubeProvider := kube.NewClient(kubeController)
 
-	certManager, err := certificate.FakeCertManager()
+	certManager := tresorFake.NewFake(time.Minute)
 	if err != nil {
 		b.Fatalf("Failed to create fake cert manager: %v", err)
 	}
-
-	// --- setup
-	namespace := tests.Namespace
-	proxySvcAccount := tests.BookstoreServiceAccount
-
-	proxyUUID := uuid.New()
-	labels := map[string]string{constants.EnvoyUniqueIDLabelName: proxyUUID.String()}
 	mc := catalog.NewMeshCatalog(
 		kubeProvider,
 		certManager,
@@ -97,32 +99,7 @@ func setupTestGenerator(b *testing.B) (*models.Proxy, *EnvoyConfigGenerator) {
 		msgBroker,
 	)
 
-	pod := tests.NewPodFixture(namespace, fmt.Sprintf("pod-0-%s", proxyUUID), tests.BookstoreServiceAccountName, tests.PodLabels)
-	pod.Labels[constants.EnvoyUniqueIDLabelName] = proxyUUID.String()
-	_, err = kubeClient.CoreV1().Pods(namespace).Create(context.Background(), pod, metav1.CreateOptions{})
-	if err != nil {
-		b.Fatalf("Failed to create pod: %v", err)
-	}
-
-	// monitor namespace
-	nsObj := corev1.Namespace{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:   namespace,
-			Labels: map[string]string{constants.OSMKubeResourceMonitorAnnotation: tests.MeshName},
-		},
-	}
-	if err := informerCollection.Add(informers.InformerKeyNamespace, &nsObj, &testing.T{}); err != nil {
-		b.Fatalf("Failed to add namespace to informer collection: %s", err)
-	}
-
-	svc := tests.NewServiceFixture(tests.BookstoreV1ServiceName, namespace, labels)
-	_, err = kubeClient.CoreV1().Services(namespace).Create(context.Background(), svc, metav1.CreateOptions{})
-	if err != nil {
-		b.Fatalf("Failed to create service: %v", err)
-	}
-
-	proxy := models.NewProxy(models.KindSidecar, proxyUUID, proxySvcAccount.ToServiceIdentity(), nil, 1)
-
+	proxy := models.NewProxy(models.KindSidecar, proxyUUID, tests.BookstoreServiceIdentity, nil, 1)
 	return proxy, NewEnvoyConfigGenerator(mc, certManager)
 }
 
diff --git a/pkg/injector/bootstrap_test.go b/pkg/injector/bootstrap_test.go
index 5f887ca0..a29a8309 100644
--- a/pkg/injector/bootstrap_test.go
+++ b/pkg/injector/bootstrap_test.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
 	"github.com/openservicemesh/osm/pkg/certificate"
+	tresorFake "github.com/openservicemesh/osm/pkg/certificate/providers/tresor/fake"
 	"github.com/openservicemesh/osm/pkg/compute"
 	"github.com/openservicemesh/osm/pkg/constants"
 	"github.com/openservicemesh/osm/pkg/envoy/bootstrap"
@@ -378,9 +379,7 @@ func TestGetBootstrapSecrets(t *testing.T) {
 			mockInterface := compute.NewMockInterface(gomock.NewController(t))
 			mockInterface.EXPECT().ListSecrets().Return(tc.secrets)
 
-			certManager, err := certificate.FakeCertManager()
-			assert.Nil(err)
-
+			certManager := tresorFake.NewFake(time.Hour)
 			b := NewBootstrapSecretRotator(mockInterface, certManager, time.Duration(1))
 
 			actual := b.getBootstrapSecrets()
@@ -527,7 +526,7 @@ func TestRotateBootstrapSecrets(t *testing.T) {
 
 	for i, tc := range testCases {
 		t.Run(fmt.Sprintf("Running test case %d: %s", i, tc.name), func(t *testing.T) {
-			certManager, err := certificate.FakeCertManager()
+			certManager := tresorFake.NewFake(time.Hour)
 			assert.Nil(err)
 
 			objs := make([]runtime.Object, len(tc.secrets))
diff --git a/pkg/injector/webhook_benchmark_test.go b/pkg/injector/webhook_benchmark_test.go
index 9f3072f6..5d030d39 100644
--- a/pkg/injector/webhook_benchmark_test.go
+++ b/pkg/injector/webhook_benchmark_test.go
@@ -15,7 +15,6 @@ import (
 	configFake "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	policyFake "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/signals"
@@ -82,11 +81,12 @@ func BenchmarkPodCreationHandler(b *testing.B) {
 	mcsClient := mcsFake.NewSimpleClientset()
 	stop := signals.RegisterExitHandlers()
 	msgBroker := messaging.NewBroker(stop)
-	informerCollection, err := informers.NewInformerCollection(tests.MeshName, stop,
-		informers.WithKubeClient(kubeClient),
-		informers.WithConfigClient(configClient, tests.OsmMeshConfigName, tests.OsmNamespace),
+	kubeController, err := k8s.NewClient("osm", tests.OsmMeshConfigName, msgBroker,
+		k8s.WithConfigClient(configClient),
+		k8s.WithKubeClient(kubeClient, tests.MeshName),
+		k8s.WithPolicyClient(policyClient),
+		k8s.WithMCSClient(mcsClient),
 	)
-	kubeController := k8s.NewClient("osm-system", tests.OsmMeshConfigName, informerCollection, kubeClient, policyClient, configClient, mcsClient, msgBroker)
 	if err != nil {
 		b.Fatalf("Failed to create kubeController: %s", err.Error())
 	}
diff --git a/pkg/k8s/client_test.go b/pkg/k8s/client_test.go
index 719f725e..0a20ffae 100644
--- a/pkg/k8s/client_test.go
+++ b/pkg/k8s/client_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 	"time"
 
-	gomock "github.com/golang/mock/gomock"
 	"github.com/google/uuid"
 	smiSpecs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha4"
 	smiAccessClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned/fake"
@@ -22,7 +21,6 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/kubernetes/fake"
-	testclient "k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/tools/cache"
 
 	configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
@@ -32,7 +30,6 @@ import (
 
 	"github.com/openservicemesh/osm/pkg/constants"
 	"github.com/openservicemesh/osm/pkg/identity"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/metricsstore"
 	"github.com/openservicemesh/osm/pkg/models"
@@ -56,6 +53,9 @@ func TestIsMonitoredNamespace(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "foo",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
 			ns:       "foo",
@@ -77,10 +77,11 @@ func TestIsMonitoredNamespace(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
 
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyNamespace, tc.namespace, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.namespace), testMeshName))
+			a.NoError(err)
 
 			actual := c.IsMonitoredNamespace(tc.ns)
 			a.Equal(tc.expected, actual)
@@ -100,6 +101,9 @@ func TestGetNamespace(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "foo",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
 			ns:       "foo",
@@ -110,6 +114,9 @@ func TestGetNamespace(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "foo",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
 			ns:       "invalid",
@@ -120,10 +127,11 @@ func TestGetNamespace(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyNamespace, tc.namespace, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.namespace), testMeshName))
+			a.NoError(err)
 
 			actual := c.GetNamespace(tc.ns)
 			if tc.expected {
@@ -138,20 +146,26 @@ func TestGetNamespace(t *testing.T) {
 func TestListNamespaces(t *testing.T) {
 	testCases := []struct {
 		name       string
-		namespaces []*corev1.Namespace
+		namespaces []runtime.Object
 		expected   []string
 	}{
 		{
 			name: "gets the namespace from the cache given its key",
-			namespaces: []*corev1.Namespace{
-				{
+			namespaces: []runtime.Object{
+				&corev1.Namespace{
 					ObjectMeta: metav1.ObjectMeta{
 						Name: "ns1",
+						Labels: map[string]string{
+							constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+						},
 					},
 				},
-				{
+				&corev1.Namespace{
 					ObjectMeta: metav1.ObjectMeta{
 						Name: "ns2",
+						Labels: map[string]string{
+							constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+						},
 					},
 				},
 			},
@@ -167,12 +181,11 @@ func TestListNamespaces(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			for _, ns := range tc.namespaces {
-				_ = ic.Add(informers.InformerKeyNamespace, ns, t)
-			}
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.namespaces...), testMeshName))
+			a.NoError(err)
 
 			actual, err := c.ListNamespaces()
 			a.Nil(err)
@@ -234,10 +247,11 @@ func TestGetService(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyService, tc.service, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.service), testMeshName))
+			a.NoError(err)
 
 			actual := c.GetService(tc.svcName, tc.svcNamespace)
 			if tc.expected {
@@ -252,22 +266,24 @@ func TestGetService(t *testing.T) {
 func TestListSecrets(t *testing.T) {
 	testCases := []struct {
 		name     string
-		secrets  []*corev1.Secret
+		secrets  []runtime.Object
 		expected []*models.Secret
 	}{
 		{
 			name: "get multiple k8s secrets",
-			secrets: []*corev1.Secret{
-				{
+			secrets: []runtime.Object{
+				&corev1.Secret{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns1",
 						Name:      "s1",
+						Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
 					},
 				},
-				{
+				&corev1.Secret{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns2",
 						Name:      "s2",
+						Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
 					},
 				},
 			},
@@ -284,11 +300,12 @@ func TestListSecrets(t *testing.T) {
 		},
 		{
 			name: "get one k8s secret",
-			secrets: []*corev1.Secret{
-				{
+			secrets: []runtime.Object{
+				&corev1.Secret{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns1",
 						Name:      "s1",
+						Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
 					},
 				},
 			},
@@ -300,22 +317,18 @@ func TestListSecrets(t *testing.T) {
 			},
 		},
 		{
-			name:     "no k8s secret",
-			secrets:  []*corev1.Secret{},
-			expected: []*models.Secret{},
+			name: "no k8s secret",
 		},
 	}
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			for _, s := range tc.secrets {
-				_ = ic.Add(informers.InformerKeySecret, s, t)
-			}
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.secrets...), testMeshName))
+			a.Nil(err)
 
 			actual := c.ListSecrets()
 			a.ElementsMatch(tc.expected, actual)
@@ -337,6 +350,7 @@ func TestGetSecret(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "foo",
 					Namespace: "ns1",
+					Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
 				},
 			},
 			secretName: "foo",
@@ -352,6 +366,7 @@ func TestGetSecret(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "foo",
 					Namespace: "ns1",
+					Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
 				},
 			},
 			secretName: "doesntExist",
@@ -363,11 +378,12 @@ func TestGetSecret(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			err = ic.Add(informers.InformerKeySecret, tc.secret, t)
-			a.Nil(err)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker,
+				WithKubeClient(fake.NewSimpleClientset(tc.secret), testMeshName))
+			a.NoError(err)
 
 			actual := c.GetSecret(tc.secretName, tc.namespace)
 			a.Equal(tc.expSecret, actual)
@@ -387,7 +403,9 @@ func TestUpdateSecret(t *testing.T) {
 			corev1Secret: &corev1.Secret{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "s1",
-					Namespace: "ns1"},
+					Namespace: "ns1",
+					Labels:    map[string]string{constants.OSMAppNameLabelKey: constants.OSMAppNameLabelValue},
+				},
 				Data: map[string][]byte{},
 			},
 			secret: &models.Secret{
@@ -401,17 +419,12 @@ func TestUpdateSecret(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-
-			err = ic.Add(informers.InformerKeySecret, tc.corev1Secret, t)
-			a.Nil(err)
-
-			fakeK8sClient := fake.NewSimpleClientset()
-			c := NewClient(testNs, tests.OsmMeshConfigName, ic, fakeK8sClient, nil, nil, nil, nil)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			_, err = c.kubeClient.CoreV1().Secrets("ns1").Create(context.Background(), tc.corev1Secret, metav1.CreateOptions{})
-			a.Nil(err)
+			c, err := NewClient(testNs, tests.OsmMeshConfigName, broker,
+				WithKubeClient(fake.NewSimpleClientset(tc.corev1Secret), testMeshName))
+			a.NoError(err)
 
 			err = c.UpdateSecret(context.Background(), tc.secret)
 			a.Nil(err)
@@ -427,7 +440,7 @@ func TestListServices(t *testing.T) {
 	testCases := []struct {
 		name      string
 		namespace *corev1.Namespace
-		services  []*corev1.Service
+		services  []runtime.Object
 		expected  []*corev1.Service
 	}{
 		{
@@ -435,16 +448,19 @@ func TestListServices(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "ns1",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
-			services: []*corev1.Service{
-				{
+			services: []runtime.Object{
+				&corev1.Service{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns1",
 						Name:      "s1",
 					},
 				},
-				{
+				&corev1.Service{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns2",
 						Name:      "s2",
@@ -465,14 +481,11 @@ func TestListServices(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyNamespace, tc.namespace, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			for _, s := range tc.services {
-				_ = ic.Add(informers.InformerKeyService, s, t)
-			}
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(append([]runtime.Object{tc.namespace}, tc.services...)...), testMeshName))
+			a.NoError(err)
 
 			actual := c.ListServices()
 			a.ElementsMatch(tc.expected, actual)
@@ -484,7 +497,7 @@ func TestListServiceAccounts(t *testing.T) {
 	testCases := []struct {
 		name      string
 		namespace *corev1.Namespace
-		sa        []*corev1.ServiceAccount
+		sa        []runtime.Object
 		expected  []*corev1.ServiceAccount
 	}{
 		{
@@ -492,16 +505,19 @@ func TestListServiceAccounts(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "ns1",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
-			sa: []*corev1.ServiceAccount{
-				{
+			sa: []runtime.Object{
+				&corev1.ServiceAccount{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns1",
 						Name:      "s1",
 					},
 				},
-				{
+				&corev1.ServiceAccount{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns2",
 						Name:      "s2",
@@ -522,14 +538,11 @@ func TestListServiceAccounts(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyNamespace, tc.namespace, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			for _, s := range tc.sa {
-				_ = ic.Add(informers.InformerKeyServiceAccount, s, t)
-			}
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(append([]runtime.Object{tc.namespace}, tc.sa...)...), testMeshName))
+			a.NoError(err)
 
 			actual := c.ListServiceAccounts()
 			a.ElementsMatch(tc.expected, actual)
@@ -541,7 +554,7 @@ func TestListPods(t *testing.T) {
 	testCases := []struct {
 		name      string
 		namespace *corev1.Namespace
-		pods      []*corev1.Pod
+		pods      []runtime.Object
 		expected  []*corev1.Pod
 	}{
 		{
@@ -549,16 +562,19 @@ func TestListPods(t *testing.T) {
 			namespace: &corev1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "ns1",
+					Labels: map[string]string{
+						constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+					},
 				},
 			},
-			pods: []*corev1.Pod{
-				{
+			pods: []runtime.Object{
+				&corev1.Pod{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns1",
 						Name:      "s1",
 					},
 				},
-				{
+				&corev1.Pod{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "ns2",
 						Name:      "s2",
@@ -579,14 +595,11 @@ func TestListPods(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyNamespace, tc.namespace, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			for _, p := range tc.pods {
-				_ = ic.Add(informers.InformerKeyPod, p, t)
-			}
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(append([]runtime.Object{tc.namespace}, tc.pods...)...), testMeshName))
+			a.NoError(err)
 
 			actual := c.ListPods()
 			a.ElementsMatch(tc.expected, actual)
@@ -636,10 +649,11 @@ func TestGetEndpoints(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyEndpoint, tc.endpoints, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(fake.NewSimpleClientset(tc.endpoints), testMeshName))
+			a.NoError(err)
 
 			actual, err := c.GetEndpoints(tc.svcName, tc.svcNamespace)
 			a.Nil(err)
@@ -740,11 +754,14 @@ func TestPolicyUpdateStatus(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			kubeClient := testclient.NewSimpleClientset()
+			kubeClient := fake.NewSimpleClientset()
 			policyClient := fakePolicyClient.NewSimpleClientset(tc.existingResource.(runtime.Object))
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithKubeClient(kubeClient), informers.WithPolicyClient(policyClient))
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, ic, kubeClient, policyClient, nil, nil, nil)
+
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithKubeClient(kubeClient, testMeshName), WithPolicyClient(policyClient))
+			a.NoError(err)
 			switch v := tc.updatedResource.(type) {
 			case *policyv1alpha1.IngressBackend:
 				_, err = c.UpdateIngressBackendStatus(v)
@@ -810,11 +827,13 @@ func TestConfigUpdateStatus(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			kubeClient := testclient.NewSimpleClientset()
+			kubeClient := fake.NewSimpleClientset()
 			configClient := fakeConfigClient.NewSimpleClientset(tc.existingResource.(runtime.Object))
-			ic, err := informers.NewInformerCollection(tests.MeshName, nil, informers.WithKubeClient(kubeClient))
-			a.Nil(err)
-			c := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, ic, nil, nil, configClient, nil, nil)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithKubeClient(kubeClient, testMeshName), WithConfigClient(configClient))
+			a.NoError(err)
 			switch v := tc.updatedResource.(type) {
 			case *configv1alpha2.MeshRootCertificate:
 				_, err = c.UpdateMeshRootCertificateStatus(v)
@@ -850,10 +869,10 @@ func TestGetPodForProxy(t *testing.T) {
 		tests.NewPodFixture(namespace, "pod-2", tests.BookstoreServiceAccountName, someOthePodLabels),
 	)
 
-	ic, err := informers.NewInformerCollection(testMeshName, stop, informers.WithKubeClient(kubeClient))
-	assert.Nil(err)
+	broker := messaging.NewBroker(stop)
 
-	kubeController := NewClient("osm", tests.OsmMeshConfigName, ic, nil, nil, nil, nil, messaging.NewBroker(nil))
+	c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithKubeClient(kubeClient, testMeshName))
+	assert.NoError(err)
 
 	testCases := []struct {
 		name  string
@@ -891,7 +910,7 @@ func TestGetPodForProxy(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			assert := tassert.New(t)
-			pod, err := kubeController.GetPodForProxy(tc.proxy)
+			pod, err := c.GetPodForProxy(tc.proxy)
 
 			assert.Equal(tc.pod, pod)
 			assert.Equal(tc.err, err)
@@ -913,19 +932,9 @@ func monitoredNS(name string) *v1.Namespace {
 func TestGetMeshConfig(t *testing.T) {
 	a := assert.New(t)
 
-	meshConfigClient := fakeConfigClient.NewSimpleClientset()
-	stop := make(chan struct{})
 	osmNamespace := "osm"
 	osmMeshConfigName := "osm-mesh-config"
 
-	ic, err := informers.NewInformerCollection("osm", stop, informers.WithConfigClient(meshConfigClient, osmMeshConfigName, osmNamespace))
-	a.Nil(err)
-
-	c := NewClient(osmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-
-	// Returns empty MeshConfig if informer cache is empty
-	a.Equal(configv1alpha2.MeshConfig{}, c.GetMeshConfig())
-
 	newObj := &configv1alpha2.MeshConfig{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "config.openservicemesh.io",
@@ -936,7 +945,21 @@ func TestGetMeshConfig(t *testing.T) {
 			Name:      osmMeshConfigName,
 		},
 	}
-	err = c.informers.Add(informers.InformerKeyMeshConfig, newObj, t)
+
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
+
+	meshConfigClient := fakeConfigClient.NewSimpleClientset()
+	c, err := NewClient(osmNamespace, tests.OsmMeshConfigName, broker, WithConfigClient(meshConfigClient))
+	a.NoError(err)
+
+	// Returns empty MeshConfig if informer cache is empty
+	a.Equal(configv1alpha2.MeshConfig{}, c.GetMeshConfig())
+
+	meshConfigClient = fakeConfigClient.NewSimpleClientset(newObj)
+	c, err = NewClient(osmNamespace, tests.OsmMeshConfigName, broker, WithConfigClient(meshConfigClient))
+	a.NoError(err)
+
 	a.Nil(err)
 	a.Equal(*newObj, c.GetMeshConfig())
 }
@@ -945,9 +968,11 @@ func TestMetricsHandler(t *testing.T) {
 	a := assert.New(t)
 	osmMeshConfigName := "osm-mesh-config"
 
-	c := &Client{
-		informers: &informers.InformerCollection{},
-	}
+	meshConfigClient := fakeConfigClient.NewSimpleClientset()
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
+	c, err := NewClient(tests.OsmNamespace, osmMeshConfigName, broker, WithConfigClient(meshConfigClient))
+	a.NoError(err)
 	handlers := c.metricsHandler()
 	metricsstore.DefaultMetricsStore.Start(metricsstore.DefaultMetricsStore.FeatureFlagEnabled)
 
@@ -998,6 +1023,9 @@ func TestListEgressPolicies(t *testing.T) {
 	egressNsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
 
@@ -1058,12 +1086,12 @@ func TestListEgressPolicies(t *testing.T) {
 
 	testCases := []struct {
 		name             string
-		allEgresses      []*policyv1alpha1.Egress
+		allEgresses      []runtime.Object
 		expectedEgresses []*policyv1alpha1.Egress
 	}{
 		{
 			name:             "Only return egress resources for monitored namespaces",
-			allEgresses:      []*policyv1alpha1.Egress{inMeshResource, outMeshResource},
+			allEgresses:      []runtime.Object{inMeshResource, outMeshResource},
 			expectedEgresses: []*policyv1alpha1.Egress{inMeshResource},
 		},
 	}
@@ -1072,24 +1100,14 @@ func TestListEgressPolicies(t *testing.T) {
 		t.Run(fmt.Sprintf("Running test case %d: %s", i, tc.name), func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			informerCollection, err := informers.NewInformerCollection("osm", nil,
-				informers.WithPolicyClient(fakeClient),
-				informers.WithKubeClient(testclient.NewSimpleClientset()))
-			a.Nil(err)
+			fakeClient := fakePolicyClient.NewSimpleClientset(tc.allEgresses...)
 
-			c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, fakeClient, nil, nil, nil)
-			a.Nil(err)
-			a.NotNil(c)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
+			c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithPolicyClient(fakeClient), WithKubeClient(fake.NewSimpleClientset(egressNsObj), testMeshName))
+			a.NoError(err)
 			// monitor namespaces
-			err = c.informers.Add(informers.InformerKeyNamespace, egressNsObj, t)
-			a.Nil(err)
-
-			// Create fake egress policies
-			for _, egressPolicy := range tc.allEgresses {
-				_ = c.informers.Add(informers.InformerKeyEgress, egressPolicy, t)
-			}
 
 			policies := c.ListEgressPolicies()
 			a.ElementsMatch(tc.expectedEgresses, policies)
@@ -1101,6 +1119,9 @@ func TestListRetryPolicy(t *testing.T) {
 	policyNsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
 
@@ -1108,12 +1129,6 @@ func TestListRetryPolicy(t *testing.T) {
 	thresholdTimeoutDuration := metav1.Duration{Duration: time.Duration(5 * time.Second)}
 	thresholdBackoffDuration := metav1.Duration{Duration: time.Duration(1 * time.Second)}
 
-	mockCtrl := gomock.NewController(t)
-	defer mockCtrl.Finish()
-
-	mockKubeController := NewMockController(mockCtrl)
-	mockKubeController.EXPECT().IsMonitoredNamespace(testNs).Return(true).AnyTimes()
-
 	outMeshResource := &policyv1alpha1.Retry{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "retry-1",
@@ -1179,12 +1194,12 @@ func TestListRetryPolicy(t *testing.T) {
 
 	testCases := []struct {
 		name            string
-		allRetries      []*policyv1alpha1.Retry
+		allRetries      []runtime.Object
 		expectedRetries []*policyv1alpha1.Retry
 	}{
 		{
 			name:            "Only return retry resources for monitored namespaces",
-			allRetries:      []*policyv1alpha1.Retry{inMeshResource, outMeshResource},
+			allRetries:      []runtime.Object{inMeshResource, outMeshResource},
 			expectedRetries: []*policyv1alpha1.Retry{inMeshResource},
 		},
 	}
@@ -1193,25 +1208,13 @@ func TestListRetryPolicy(t *testing.T) {
 		t.Run(fmt.Sprintf("Running test case %d: %s", i, tc.name), func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			informerCollection, err := informers.NewInformerCollection("osm", nil,
-				informers.WithPolicyClient(fakeClient),
-				informers.WithKubeClient(testclient.NewSimpleClientset()),
-			)
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, fakeClient, nil, nil, nil)
-			a.Nil(err)
-			a.NotNil(c)
+			fakeClient := fakePolicyClient.NewSimpleClientset(tc.allRetries...)
 
-			// monitor namespaces
-			err = c.informers.Add(informers.InformerKeyNamespace, policyNsObj, t)
-			a.Nil(err)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			// Create fake retry policies
-			for _, retryPolicy := range tc.allRetries {
-				err := c.informers.Add(informers.InformerKeyRetry, retryPolicy, t)
-				a.Nil(err)
-			}
+			c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithPolicyClient(fakeClient), WithKubeClient(fake.NewSimpleClientset(policyNsObj), testMeshName))
+			a.NoError(err)
 
 			policies := c.ListRetryPolicies()
 			a.ElementsMatch(tc.expectedRetries, policies)
@@ -1223,6 +1226,9 @@ func TestListUpstreamTrafficSetting(t *testing.T) {
 	settingNsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
 
@@ -1246,12 +1252,12 @@ func TestListUpstreamTrafficSetting(t *testing.T) {
 	}
 	testCases := []struct {
 		name         string
-		allResources []*policyv1alpha1.UpstreamTrafficSetting
+		allResources []runtime.Object
 		expected     []*policyv1alpha1.UpstreamTrafficSetting
 	}{
 		{
 			name:         "Only return upstream traffic settings for monitored namespaces",
-			allResources: []*policyv1alpha1.UpstreamTrafficSetting{inMeshResource, outMeshResource},
+			allResources: []runtime.Object{inMeshResource, outMeshResource},
 			expected:     []*policyv1alpha1.UpstreamTrafficSetting{inMeshResource},
 		},
 	}
@@ -1260,24 +1266,12 @@ func TestListUpstreamTrafficSetting(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fakePolicyClient.NewSimpleClientset()
-			informerCollection, err := informers.NewInformerCollection("osm", nil,
-				informers.WithPolicyClient(fakeClient),
-				informers.WithKubeClient(testclient.NewSimpleClientset()),
-			)
-			a.Nil(err)
-			c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, fakeClient, nil, nil, nil)
-			a.Nil(err)
-			a.NotNil(c)
+			fakeClient := fakePolicyClient.NewSimpleClientset(tc.allResources...)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			// monitor namespaces
-			err = c.informers.Add(informers.InformerKeyNamespace, settingNsObj, t)
-			a.Nil(err)
-
-			// Create fake upstream traffic settings
-			for _, resource := range tc.allResources {
-				_ = c.informers.Add(informers.InformerKeyUpstreamTrafficSetting, resource, t)
-			}
+			c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithPolicyClient(fakeClient), WithKubeClient(fake.NewSimpleClientset(settingNsObj), testMeshName))
+			a.NoError(err)
 
 			actual := c.ListUpstreamTrafficSettings()
 			a.Equal(tc.expected, actual)
@@ -1319,10 +1313,11 @@ func TestGetMeshRootCertificate(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
-			ic, err := informers.NewInformerCollection(testMeshName, nil, informers.WithConfigClient(fakeConfigClient.NewSimpleClientset(), tests.OsmMeshConfigName, tests.OsmNamespace))
-			a.Nil(err)
-			c := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			_ = ic.Add(informers.InformerKeyMeshRootCertificate, tc.meshRootCertificate, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
+
+			c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithConfigClient(fakeConfigClient.NewSimpleClientset(tc.meshRootCertificate)))
+			a.NoError(err)
 
 			actual := c.GetMeshRootCertificate(tc.mrcName)
 			if tc.expected {
@@ -1337,70 +1332,50 @@ func TestGetMeshRootCertificate(t *testing.T) {
 func TestListMeshRootCertificates(t *testing.T) {
 	a := assert.New(t)
 
-	mrcClient := fakeConfigClient.NewSimpleClientset()
-	stop := make(chan struct{})
-
-	ic, err := informers.NewInformerCollection(tests.MeshName, stop, informers.WithConfigClient(mrcClient, tests.OsmMeshConfigName, tests.OsmNamespace))
-	a.Nil(err)
-
-	c := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-
-	mrcList, err := c.ListMeshRootCertificates()
-	a.NoError(err)
-	a.Empty(mrcList)
-
-	newList := []*configv1alpha2.MeshRootCertificate{
-		{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "osm-mesh-root-certificate",
-				Namespace: "osm-system",
-			},
-			Spec: configv1alpha2.MeshRootCertificateSpec{
-				Provider: configv1alpha2.ProviderSpec{
-					Tresor: &configv1alpha2.TresorProviderSpec{
-						CA: configv1alpha2.TresorCASpec{
-							SecretRef: v1.SecretReference{
-								Name:      "osm-ca-bundle",
-								Namespace: "osm-system",
-							},
+	mrc := &configv1alpha2.MeshRootCertificate{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "osm-mesh-root-certificate",
+			Namespace: "osm-system",
+		},
+		Spec: configv1alpha2.MeshRootCertificateSpec{
+			Provider: configv1alpha2.ProviderSpec{
+				Tresor: &configv1alpha2.TresorProviderSpec{
+					CA: configv1alpha2.TresorCASpec{
+						SecretRef: v1.SecretReference{
+							Name:      "osm-ca-bundle",
+							Namespace: "osm-system",
 						},
 					},
 				},
 			},
-			Status: configv1alpha2.MeshRootCertificateStatus{
-				State: constants.MRCStateActive,
-			},
+		},
+		Status: configv1alpha2.MeshRootCertificateStatus{
+			State: constants.MRCStateActive,
 		},
 	}
-	err = c.informers.Add(informers.InformerKeyMeshRootCertificate, newList[0], t)
-	a.Nil(err)
+	mrcClient := fakeConfigClient.NewSimpleClientset(mrc)
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
 
-	mrcList, err = c.ListMeshRootCertificates()
+	c, err := NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker, WithConfigClient(mrcClient))
 	a.NoError(err)
-	a.ElementsMatch(newList, mrcList)
+
+	mrcList, err := c.ListMeshRootCertificates()
+	a.NoError(err)
+	a.Contains(mrcList, mrc)
+	a.Len(mrcList, 1)
 }
 
 func TestListHTTPTrafficSpecs(t *testing.T) {
 	nsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
 
-	a := assert.New(t)
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-	)
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
-
 	obj := &smiSpecs.HTTPRouteGroup{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "specs.smi-spec.io/v1alpha4",
@@ -1434,11 +1409,18 @@ func TestListHTTPTrafficSpecs(t *testing.T) {
 			},
 		},
 	}
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyHTTPRouteGroup, obj, t)
-	a.Nil(err)
+	a := assert.New(t)
+	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
+	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset(obj)
+	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
 
+	c, err := NewClient("osm", tests.OsmMeshConfigName, broker,
+		WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		WithKubeClient(fake.NewSimpleClientset(nsObj), testMeshName),
+	)
+	a.NoError(err)
 	// Verify
 	actual := c.ListHTTPTrafficSpecs()
 	a.Len(actual, 1)
@@ -1449,22 +1431,11 @@ func TestGetHTTPRouteGroup(t *testing.T) {
 	nsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
-
-	a := assert.New(t)
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-	)
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
-
 	obj := &smiSpecs.HTTPRouteGroup{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "specs.smi-spec.io/v1alpha4",
@@ -1498,11 +1469,18 @@ func TestGetHTTPRouteGroup(t *testing.T) {
 			},
 		},
 	}
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyHTTPRouteGroup, obj, t)
-	a.Nil(err)
+	a := assert.New(t)
+	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
+	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset(obj)
+	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
 
+	c, err := NewClient("osm", tests.OsmMeshConfigName, broker,
+		WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		WithKubeClient(fake.NewSimpleClientset(nsObj), testMeshName),
+	)
+	a.NoError(err)
 	// Verify
 	key, _ := cache.MetaNamespaceKeyFunc(obj)
 	actual := c.GetHTTPRouteGroup(key)
@@ -1516,23 +1494,12 @@ func TestListTCPTrafficSpecs(t *testing.T) {
 	nsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
 
-	a := assert.New(t)
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-	)
-
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
-
 	obj := &smiSpecs.TCPRoute{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "specs.smi-spec.io/v1alpha4",
@@ -1544,11 +1511,18 @@ func TestListTCPTrafficSpecs(t *testing.T) {
 		},
 		Spec: smiSpecs.TCPRouteSpec{},
 	}
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyTCPRoute, obj, t)
-	a.Nil(err)
+	a := assert.New(t)
+	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
+	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset(obj)
+	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
 
+	c, err := NewClient("osm", tests.OsmMeshConfigName, broker,
+		WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		WithKubeClient(fake.NewSimpleClientset(nsObj), testMeshName),
+	)
+	a.NoError(err)
 	// Verify
 	actual := c.ListTCPTrafficSpecs()
 	a.Len(actual, 1)
@@ -1559,20 +1533,11 @@ func TestGetTCPRoute(t *testing.T) {
 	nsObj := &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: testNs,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: testMeshName,
+			},
 		},
 	}
-	a := assert.New(t)
-	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
-	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
-	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-	)
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
 
 	obj := &smiSpecs.TCPRoute{
 		TypeMeta: metav1.TypeMeta{
@@ -1585,10 +1550,17 @@ func TestGetTCPRoute(t *testing.T) {
 		},
 		Spec: smiSpecs.TCPRouteSpec{},
 	}
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyTCPRoute, obj, t)
-	a.Nil(err)
+	a := assert.New(t)
+	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
+	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset(obj)
+	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
+
+	c, err := NewClient("osm", tests.OsmMeshConfigName, broker, WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		WithKubeClient(fake.NewSimpleClientset(nsObj), testMeshName),
+	)
+	a.NoError(err)
 
 	// Verify
 	key, _ := cache.MetaNamespaceKeyFunc(obj)
@@ -1621,7 +1593,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 	selectorPolicy := &policyv1alpha1.Telemetry{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: appNamespace,
-			Name:      "t2",
+			Name:      "t3",
 		},
 		Spec: policyv1alpha1.TelemetrySpec{
 			Selector: map[string]string{"app": "foo"},
@@ -1632,7 +1604,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 		name              string
 		proxy             *models.Proxy
 		pod               *corev1.Pod
-		telemetryPolicies []*policyv1alpha1.Telemetry
+		telemetryPolicies []runtime.Object
 		expected          *policyv1alpha1.Telemetry
 	}{
 		{
@@ -1643,7 +1615,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 					constants.EnvoyUniqueIDLabelName: proxyUUID.String(),
 					"app":                            "foo",
 				}),
-			telemetryPolicies: []*policyv1alpha1.Telemetry{
+			telemetryPolicies: []runtime.Object{
 				globalPolicy,
 			},
 			expected: globalPolicy,
@@ -1656,7 +1628,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 					constants.EnvoyUniqueIDLabelName: proxyUUID.String(),
 					"app":                            "foo",
 				}),
-			telemetryPolicies: []*policyv1alpha1.Telemetry{
+			telemetryPolicies: []runtime.Object{
 				globalPolicy,
 				namespacePolicy,
 			},
@@ -1670,7 +1642,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 					constants.EnvoyUniqueIDLabelName: proxyUUID.String(),
 					"app":                            "foo",
 				}),
-			telemetryPolicies: []*policyv1alpha1.Telemetry{
+			telemetryPolicies: []runtime.Object{
 				globalPolicy,
 				namespacePolicy,
 				selectorPolicy,
@@ -1685,7 +1657,7 @@ func TestGetTelemetryPolicy(t *testing.T) {
 					constants.EnvoyUniqueIDLabelName: proxyUUID.String(),
 					"app":                            "foo",
 				}),
-			telemetryPolicies: []*policyv1alpha1.Telemetry{
+			telemetryPolicies: []runtime.Object{
 				globalPolicy,
 				namespacePolicy,
 				selectorPolicy,
@@ -1698,21 +1670,14 @@ func TestGetTelemetryPolicy(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := assert.New(t)
 
-			fakeClient := fake.NewSimpleClientset()
-			fakePolicyClient := fakePolicyClient.NewSimpleClientset()
-			ic, err := informers.NewInformerCollection(testMeshName, nil,
-				informers.WithKubeClient(fakeClient), informers.WithPolicyClient(fakePolicyClient))
-			a.Nil(err)
-
-			c := NewClient(osmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, nil)
-			a.NotNil(c)
-
-			_ = ic.Add(informers.InformerKeyNamespace, monitoredNS(appNamespace), t)
-			_ = ic.Add(informers.InformerKeyPod, tc.pod, t)
+			stop := make(chan struct{})
+			broker := messaging.NewBroker(stop)
 
-			for _, policy := range tc.telemetryPolicies {
-				_ = ic.Add(informers.InformerKeyTelemetry, policy, t)
-			}
+			c, err := NewClient(osmNamespace, testMeshName, broker,
+				WithKubeClient(fake.NewSimpleClientset(monitoredNS(appNamespace), tc.pod), testMeshName),
+				WithPolicyClient(fakePolicyClient.NewSimpleClientset(tc.telemetryPolicies...)),
+			)
+			a.NoError(err)
 
 			actual := c.GetTelemetryPolicy(tc.proxy)
 			a.Equal(tc.expected, actual)
@@ -1721,41 +1686,24 @@ func TestGetTelemetryPolicy(t *testing.T) {
 }
 
 func TestListServiceImports(t *testing.T) {
-	nsObj := &corev1.Namespace{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: testNs,
-		},
-	}
-
 	a := assert.New(t)
-	mcsClientSet := mcsClientFake.NewSimpleClientset()
-
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithMCSClient(mcsClientSet),
-	)
-
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
 
 	obj := &mcs.ServiceImport{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: testNs,
 			Name:      "test-service-import",
 		},
-		TypeMeta: metav1.TypeMeta{
-			APIVersion: "multicluster.x-k8s.io/v1alpha1",
-			Kind:       "ServiceImport",
-		},
-		Spec: mcs.ServiceImportSpec{},
 	}
 
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyServiceImport, obj, t)
-	a.Nil(err)
+	mcsClientSet := mcsClientFake.NewSimpleClientset(obj)
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
+
+	c, err := NewClient("osm-system", "osm-mesh-config", broker,
+		WithKubeClient(fake.NewSimpleClientset(monitoredNS(testNs)), testMeshName),
+		WithMCSClient(mcsClientSet),
+	)
+	a.NoError(err)
 
 	// Verify
 	actual := c.ListServiceImports()
@@ -1764,41 +1712,23 @@ func TestListServiceImports(t *testing.T) {
 }
 
 func TestListServiceExports(t *testing.T) {
-	nsObj := &corev1.Namespace{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: testNs,
-		},
-	}
-
 	a := assert.New(t)
-	mcsClientSet := mcsClientFake.NewSimpleClientset()
-
-	informerCollection, err := informers.NewInformerCollection("osm", nil,
-		informers.WithKubeClient(testclient.NewSimpleClientset()),
-		informers.WithMCSClient(mcsClientSet),
-	)
-
-	a.Nil(err)
-	c := NewClient("osm", tests.OsmMeshConfigName, informerCollection, nil, nil, nil, nil, nil)
-	a.Nil(err)
-	a.NotNil(c)
-
 	obj := &mcs.ServiceExport{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: testNs,
 			Name:      "test-service-export",
 		},
-		TypeMeta: metav1.TypeMeta{
-			APIVersion: "multicluster.x-k8s.io/v1alpha1",
-			Kind:       "ServiceExport",
-		},
-		Status: mcs.ServiceExportStatus{},
 	}
+	mcsClientSet := mcsClientFake.NewSimpleClientset(obj)
 
-	err = c.informers.Add(informers.InformerKeyNamespace, nsObj, t)
-	a.Nil(err)
-	err = c.informers.Add(informers.InformerKeyServiceExport, obj, t)
-	a.Nil(err)
+	stop := make(chan struct{})
+	broker := messaging.NewBroker(stop)
+
+	c, err := NewClient("osm-system", "osm-mesh-config", broker,
+		WithKubeClient(fake.NewSimpleClientset(monitoredNS(testNs)), testMeshName),
+		WithMCSClient(mcsClientSet),
+	)
+	a.NoError(err)
 
 	// Verify
 	actual := c.ListServiceExports()
diff --git a/pkg/k8s/event_handlers_test.go b/pkg/k8s/event_handlers_test.go
index 411afa69..c89ec6e7 100644
--- a/pkg/k8s/event_handlers_test.go
+++ b/pkg/k8s/event_handlers_test.go
@@ -7,6 +7,7 @@ import (
 	"github.com/stretchr/testify/assert"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/kubernetes/fake"
 
 	"github.com/openservicemesh/osm/pkg/messaging"
 )
@@ -14,19 +15,38 @@ import (
 func TestGetEventHandlers(t *testing.T) {
 	testCases := []struct {
 		name               string
-		filter             observeFilter
+		obj                interface{}
 		expectedEventCount uint64
 	}{
 		{
-			name:               "add/update/delete events when the events are observed",
-			filter:             func(_ interface{}) bool { return true },
+			name: "add/update/delete events when the events are observed",
+			obj: &corev1.Pod{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "ns1",
+					Name:      "p1",
+				},
+			},
 			expectedEventCount: 3,
 		},
 		{
-			name:               "add/update/delete events when the events are not observed",
-			filter:             func(_ interface{}) bool { return false },
+			name: "add/update/delete events when the events are not observed",
+			obj: &corev1.Pod{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "ns2",
+					Name:      "p2",
+				},
+			},
 			expectedEventCount: 0,
 		},
+		{
+			name: "add/update/delete events for a namespace are always observed",
+			obj: &corev1.Namespace{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "ns2",
+				},
+			},
+			expectedEventCount: 3,
+		},
 	}
 
 	for _, tc := range testCases {
@@ -36,21 +56,20 @@ func TestGetEventHandlers(t *testing.T) {
 			stop := make(chan struct{})
 			msgBroker := messaging.NewBroker(stop)
 
-			eventFuncs := GetEventHandlerFuncs(tc.filter, msgBroker)
-			obj := &corev1.Pod{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "ns1",
-					Name:      "p1",
-				},
-			}
-			eventFuncs.OnAdd(obj)
-			eventFuncs.OnUpdate(obj, obj)
-			eventFuncs.OnDelete(obj)
+			c, err := NewClient("", "", msgBroker, WithKubeClient(fake.NewSimpleClientset(monitoredNS("ns1")), testMeshName))
+			a.NoError(err)
+
+			eventFuncs := c.defaultEventHandler()
+
+			eventFuncs.OnAdd(tc.obj)
+			eventFuncs.OnUpdate(tc.obj, tc.obj)
+			eventFuncs.OnDelete(tc.obj)
 
 			// Verify that if the filter observes the event, 3 events are queued
 			// Events are rate limited, wait for 1s
 			a.Eventually(func() bool {
-				return msgBroker.GetTotalQEventCount() == tc.expectedEventCount
+				// Add 1 since the initial namespace will always trigger an OnAdd call.
+				return msgBroker.GetTotalQEventCount() == tc.expectedEventCount+1
 			}, 1*time.Second, 10*time.Millisecond)
 		})
 	}
diff --git a/pkg/messaging/broker_test.go b/pkg/messaging/broker_test.go
index e327b473..7f0fa389 100644
--- a/pkg/messaging/broker_test.go
+++ b/pkg/messaging/broker_test.go
@@ -475,8 +475,9 @@ func TestQueueLenMetric(t *testing.T) {
 
 	b := &Broker{
 		queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
+		stop:  stop,
 	}
-	go b.queueLenMetric(stop, 10*time.Millisecond)
+	go b.queueLenMetric(10 * time.Millisecond)
 	metricsstore.DefaultMetricsStore.Start(metricsstore.DefaultMetricsStore.EventsQueued)
 
 	numEvents := 10
diff --git a/pkg/validator/server_benchmark_test.go b/pkg/validator/server_benchmark_test.go
index bb9a1279..4b452dac 100644
--- a/pkg/validator/server_benchmark_test.go
+++ b/pkg/validator/server_benchmark_test.go
@@ -14,14 +14,12 @@ import (
 	smiAccessClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned/fake"
 	smiSpecClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned/fake"
 	smiSplitClientFake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake"
-	mcsFake "sigs.k8s.io/mcs-api/pkg/client/clientset/versioned/fake"
 
 	policyv1alpha1 "github.com/openservicemesh/osm/pkg/apis/policy/v1alpha1"
 	"github.com/openservicemesh/osm/pkg/compute/kube"
 	configFake "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	policyFake "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/logger"
 	"github.com/openservicemesh/osm/pkg/messaging"
 	"github.com/openservicemesh/osm/pkg/signals"
@@ -37,23 +35,22 @@ func BenchmarkDoValidation(b *testing.B) {
 	kubeClient := k8sClientFake.NewSimpleClientset()
 	_, cancel := context.WithCancel(context.Background())
 	stop := signals.RegisterExitHandlers(cancel)
-	msgBroker := messaging.NewBroker(stop)
 	smiTrafficSplitClientSet := smiSplitClientFake.NewSimpleClientset()
 	smiTrafficSpecClientSet := smiSpecClientFake.NewSimpleClientset()
 	smiTrafficTargetClientSet := smiAccessClientFake.NewSimpleClientset()
 	policyClient := policyFake.NewSimpleClientset()
 	configClient := configFake.NewSimpleClientset()
-	mcsClient := mcsFake.NewSimpleClientset()
-	informerCollection, err := informers.NewInformerCollection(tests.MeshName, stop,
-		informers.WithKubeClient(kubeClient),
-		informers.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
-		informers.WithConfigClient(configClient, tests.OsmMeshConfigName, tests.OsmNamespace),
-		informers.WithPolicyClient(policyClient),
+
+	broker := messaging.NewBroker(stop)
+	k8sClient, err := k8s.NewClient("osm-ns", tests.OsmMeshConfigName, broker,
+		k8s.WithKubeClient(kubeClient, "osm"),
+		k8s.WithSMIClients(smiTrafficSplitClientSet, smiTrafficSpecClientSet, smiTrafficTargetClientSet),
+		k8s.WithConfigClient(configClient),
+		k8s.WithPolicyClient(policyClient),
 	)
 	if err != nil {
 		b.Fatalf("Failed to create informer collection: %s", err)
 	}
-	k8sClient := k8s.NewClient("osm-ns", tests.OsmMeshConfigName, informerCollection, kubeClient, policyClient, configClient, mcsClient, msgBroker)
 	compute := kube.NewClient(k8sClient)
 	kv := &validator{
 		computeClient: compute,
diff --git a/pkg/validator/server_test.go b/pkg/validator/server_test.go
index b01016c0..85d0eedb 100644
--- a/pkg/validator/server_test.go
+++ b/pkg/validator/server_test.go
@@ -24,7 +24,6 @@ import (
 	configFake "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	policyFake "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/messaging"
 
 	"github.com/openservicemesh/osm/pkg/webhook"
@@ -162,13 +161,16 @@ func TestNewValidatingWebhook(t *testing.T) {
 		}
 
 		kube := fake.NewSimpleClientset(webhook)
-		informerCollection, err := informers.NewInformerCollection("osm", stop, informers.WithKubeClient(kube))
-		tassert.NoError(t, err)
 		policyClient := policyFake.NewSimpleClientset()
 		configClient := configFake.NewSimpleClientset()
 		mcsClient := mcsFake.NewSimpleClientset()
-
-		k8sClient := k8s.NewClient(testNamespace, testMeshConfigName, informerCollection, kube, policyClient, configClient, mcsClient, broker)
+		k8sClient, err := k8s.NewClient(testNamespace, testMeshConfigName, broker,
+			k8s.WithKubeClient(kube, "osm"),
+			k8s.WithPolicyClient(policyClient),
+			k8s.WithConfigClient(configClient),
+			k8s.WithMCSClient(mcsClient),
+		)
+		tassert.NoError(t, err)
 		compute := computekube.NewClient(k8sClient)
 		ctx, cancel := context.WithCancel(context.Background())
 		err = NewValidatingWebhook(ctx, webhook.Name, testNamespace, testVersion, testMeshName, enableReconciler, validateTrafficTarget, certManager, kube, compute)
@@ -184,12 +186,16 @@ func TestNewValidatingWebhook(t *testing.T) {
 		defer close(stop)
 		broker := messaging.NewBroker(stop)
 		kube := fake.NewSimpleClientset()
-		informerCollection, err := informers.NewInformerCollection("osm", stop, informers.WithKubeClient(kube))
-		tassert.NoError(t, err)
 		policyClient := policyFake.NewSimpleClientset()
 		configClient := configFake.NewSimpleClientset()
 		mcsClient := mcsFake.NewSimpleClientset()
-		k8sClient := k8s.NewClient(testNamespace, testMeshConfigName, informerCollection, kube, policyClient, configClient, mcsClient, broker)
+		k8sClient, err := k8s.NewClient(testNamespace, testMeshConfigName, broker,
+			k8s.WithKubeClient(kube, "osm"),
+			k8s.WithPolicyClient(policyClient),
+			k8s.WithConfigClient(configClient),
+			k8s.WithMCSClient(mcsClient),
+		)
+		tassert.NoError(t, err)
 
 		compute := computekube.NewClient(k8sClient)
 		err = NewValidatingWebhook(context.Background(), "my-webhook", testNamespace, testVersion, testMeshName, enableReconciler, validateTrafficTarget, certManager, kube, compute)
@@ -206,12 +212,16 @@ func TestNewValidatingWebhook(t *testing.T) {
 		broker := messaging.NewBroker(stop)
 
 		kube := fake.NewSimpleClientset()
-		informerCollection, err := informers.NewInformerCollection("osm", stop, informers.WithKubeClient(kube))
-		tassert.NoError(t, err)
 		policyClient := policyFake.NewSimpleClientset()
 		configClient := configFake.NewSimpleClientset()
 		mcsClient := mcsFake.NewSimpleClientset()
-		k8sClient := k8s.NewClient(testNamespace, testMeshConfigName, informerCollection, kube, policyClient, configClient, mcsClient, broker)
+		k8sClient, err := k8s.NewClient(testNamespace, testMeshConfigName, broker,
+			k8s.WithKubeClient(kube, "osm"),
+			k8s.WithPolicyClient(policyClient),
+			k8s.WithConfigClient(configClient),
+			k8s.WithMCSClient(mcsClient),
+		)
+		tassert.NoError(t, err)
 		compute := computekube.NewClient(k8sClient)
 
 		err = NewValidatingWebhook(context.Background(), "my-webhook", testNamespace, testVersion, testMeshName, enableReconciler, validateTrafficTarget, certManager, kube, compute)
diff --git a/pkg/validator/validators_test.go b/pkg/validator/validators_test.go
index 10a5259e..98f795dd 100644
--- a/pkg/validator/validators_test.go
+++ b/pkg/validator/validators_test.go
@@ -20,7 +20,6 @@ import (
 	fakeConfigClient "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake"
 	fakePolicyClientset "github.com/openservicemesh/osm/pkg/gen/client/policy/clientset/versioned/fake"
 	"github.com/openservicemesh/osm/pkg/k8s"
-	"github.com/openservicemesh/osm/pkg/k8s/informers"
 	"github.com/openservicemesh/osm/pkg/tests"
 
 	"github.com/openservicemesh/osm/pkg/messaging"
@@ -30,6 +29,9 @@ func newNsK8sObj(ns string) *corev1.Namespace {
 	return &corev1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: ns,
+			Labels: map[string]string{
+				constants.OSMKubeResourceMonitorAnnotation: "osm",
+			},
 		},
 	}
 }
@@ -779,13 +781,13 @@ func TestIngressBackendValidator(t *testing.T) {
 			}
 
 			fakeClient := fakePolicyClientset.NewSimpleClientset(objects...)
-			informerCollection, err := informers.NewInformerCollection("osm", stop,
-				informers.WithPolicyClient(fakeClient),
-				informers.WithKubeClient(testclient.NewSimpleClientset()),
+
+			k8sClient, err := k8s.NewClient("osm-namespace", "osm-mesh-config", broker,
+				k8s.WithPolicyClient(fakeClient),
+				k8s.WithKubeClient(testclient.NewSimpleClientset(), "osm"),
 			)
 			assert.NoError(err)
 
-			k8sClient := k8s.NewClient("osm-namespace", "osm-mesh-config", informerCollection, nil, fakeClient, nil, nil, broker)
 			computeClient := kube.NewClient(k8sClient)
 			pv := &validator{
 				computeClient: computeClient,
@@ -1304,25 +1306,19 @@ func TestUpstreamTrafficSettingValidator(t *testing.T) {
 			}
 
 			fakeClient := fakePolicyClientset.NewSimpleClientset(objects...)
-			informerCollection, err := informers.NewInformerCollection("osm", stop,
-				informers.WithPolicyClient(fakeClient),
-				informers.WithKubeClient(testclient.NewSimpleClientset()),
+			k8sClient, err := k8s.NewClient("test-namespace", "test-mesh-config", broker,
+				k8s.WithPolicyClient(fakeClient),
+				k8s.WithKubeClient(testclient.NewSimpleClientset(newNsK8sObj(testNs)), "osm"),
 			)
 			assert.NoError(err)
 
-			k8sClient := k8s.NewClient("test-namespace", "test-mesh-config", informerCollection, nil, fakeClient, nil, nil, broker)
 			computeClient := kube.NewClient(k8sClient)
 
 			pv := &validator{
 				computeClient: computeClient,
 			}
 
-			if len(objects) > 0 {
-				// monitor namespaces
-				err := informerCollection.Add(informers.InformerKeyNamespace, newNsK8sObj(testNs), t)
-				assert.Nil(err)
-				assert.True(k8sClient.IsMonitoredNamespace(testNs))
-			}
+			assert.True(k8sClient.IsMonitoredNamespace(testNs))
 
 			// Block until we start getting upstreamtrafficsetting updates
 			// We only do this because the informerCollection doesn't have the
@@ -1816,7 +1812,7 @@ func TestCheckForExistingActiveMRC(t *testing.T) {
 	testCases := []struct {
 		name      string
 		mrc       *configv1alpha2.MeshRootCertificate
-		mrcList   []*configv1alpha2.MeshRootCertificate
+		mrcList   []runtime.Object
 		expReturn bool
 	}{
 		{
@@ -1841,8 +1837,8 @@ func TestCheckForExistingActiveMRC(t *testing.T) {
 					},
 				},
 			},
-			mrcList: []*configv1alpha2.MeshRootCertificate{
-				{
+			mrcList: []runtime.Object{
+				&configv1alpha2.MeshRootCertificate{
 					ObjectMeta: metav1.ObjectMeta{
 						Name:      "osm-mesh-root-certificate-2",
 						Namespace: "osm-system",
@@ -1887,8 +1883,8 @@ func TestCheckForExistingActiveMRC(t *testing.T) {
 					},
 				},
 			},
-			mrcList: []*configv1alpha2.MeshRootCertificate{
-				{
+			mrcList: []runtime.Object{
+				&configv1alpha2.MeshRootCertificate{
 					ObjectMeta: metav1.ObjectMeta{
 						Name:      "osm-mesh-root-certificate-2",
 						Namespace: "osm-system",
@@ -1936,8 +1932,8 @@ func TestCheckForExistingActiveMRC(t *testing.T) {
 					State: constants.MRCStateActive,
 				},
 			},
-			mrcList: []*configv1alpha2.MeshRootCertificate{
-				{
+			mrcList: []runtime.Object{
+				&configv1alpha2.MeshRootCertificate{
 					ObjectMeta: metav1.ObjectMeta{
 						Name:      "osm-mesh-root-certificate",
 						Namespace: "osm-system",
@@ -1966,18 +1962,14 @@ func TestCheckForExistingActiveMRC(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			a := tassert.New(t)
 
-			mrcClient := fakeConfigClient.NewSimpleClientset()
+			mrcClient := fakeConfigClient.NewSimpleClientset(tc.mrcList...)
 			stop := make(chan struct{})
-
-			ic, err := informers.NewInformerCollection(tests.MeshName, stop, informers.WithConfigClient(mrcClient, tests.OsmMeshConfigName, tests.OsmNamespace))
-			a.Nil(err)
-			for _, mrc := range tc.mrcList {
-				err = ic.Add(informers.InformerKeyMeshRootCertificate, mrc, t)
-				a.NoError(err)
-			}
-
 			broker := messaging.NewBroker(stop)
-			k8sClient := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, ic, nil, nil, nil, nil, broker)
+			k8sClient, err := k8s.NewClient(tests.OsmNamespace, tests.OsmMeshConfigName, broker,
+				k8s.WithConfigClient(mrcClient),
+				k8s.WithKubeClient(testclient.NewSimpleClientset(), "osm"),
+			)
+			a.NoError(err)
 			computeClient := kube.NewClient(k8sClient)
 
 			v := validator{computeClient: computeClient}