From ca7d2e783fb0926a5b17d42ff84d121574ed1812 Mon Sep 17 00:00:00 2001
From: Jakob Schrettenbrunner <jakob.schrettenbrunner@telekom.de>
Date: Thu, 25 Nov 2021 17:08:34 +0100
Subject: [PATCH] Use k8s.io/cli-runtime for kubernetes flags

Signed-off-by: Jakob Schrettenbrunner <jakob.schrettenbrunner@telekom.de>
---
 cmd/flux/bootstrap_bitbucket_server.go    | 12 +++---
 cmd/flux/bootstrap_git.go                 | 12 +++---
 cmd/flux/bootstrap_github.go              | 12 +++---
 cmd/flux/bootstrap_gitlab.go              | 12 +++---
 cmd/flux/check.go                         |  8 ++--
 cmd/flux/check_test.go                    |  2 +-
 cmd/flux/completion.go                    | 12 ++----
 cmd/flux/create.go                        |  2 +-
 cmd/flux/create_alert.go                  |  4 +-
 cmd/flux/create_alertprovider.go          |  4 +-
 cmd/flux/create_helmrelease.go            |  4 +-
 cmd/flux/create_image_policy.go           |  2 +-
 cmd/flux/create_image_repository.go       |  2 +-
 cmd/flux/create_image_update.go           |  2 +-
 cmd/flux/create_kustomization.go          |  4 +-
 cmd/flux/create_receiver.go               |  4 +-
 cmd/flux/create_secret_git.go             |  6 +--
 cmd/flux/create_secret_helm.go            |  6 +--
 cmd/flux/create_secret_tls.go             |  6 +--
 cmd/flux/create_source_bucket.go          |  6 +--
 cmd/flux/create_source_git.go             |  6 +--
 cmd/flux/create_source_helm.go            |  6 +--
 cmd/flux/create_tenant.go                 |  2 +-
 cmd/flux/delete.go                        |  6 +--
 cmd/flux/export.go                        |  9 +++--
 cmd/flux/export_secret.go                 |  9 +++--
 cmd/flux/get.go                           |  6 +--
 cmd/flux/install.go                       | 12 +++---
 cmd/flux/logs.go                          |  4 +-
 cmd/flux/main.go                          | 45 +++++++++--------------
 cmd/flux/main_e2e_test.go                 |  8 ++--
 cmd/flux/main_unit_test.go                |  3 +-
 cmd/flux/reconcile.go                     |  6 +--
 cmd/flux/reconcile_alertprovider.go       |  6 +--
 cmd/flux/reconcile_receiver.go            |  6 +--
 cmd/flux/reconcile_with_source.go         | 12 +++---
 cmd/flux/resume.go                        | 10 ++---
 cmd/flux/status.go                        |  2 +-
 cmd/flux/suspend.go                       |  8 ++--
 cmd/flux/trace.go                         |  4 +-
 cmd/flux/tree_kustomization.go            |  4 +-
 cmd/flux/uninstall.go                     |  8 ++--
 cmd/flux/version.go                       |  6 +--
 go.mod                                    |  1 +
 internal/bootstrap/bootstrap_plain_git.go | 12 +++---
 internal/bootstrap/options.go             | 12 +++---
 internal/utils/apply.go                   |  8 ++--
 internal/utils/utils.go                   | 26 +++----------
 48 files changed, 172 insertions(+), 197 deletions(-)

diff --git a/cmd/flux/bootstrap_bitbucket_server.go b/cmd/flux/bootstrap_bitbucket_server.go
index 07fb04c7..56e1a906 100644
--- a/cmd/flux/bootstrap_bitbucket_server.go
+++ b/cmd/flux/bootstrap_bitbucket_server.go
@@ -121,7 +121,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -179,7 +179,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
 	installOptions := install.Options{
 		BaseURL:                rootArgs.defaults.BaseURL,
 		Version:                bootstrapArgs.version,
-		Namespace:              rootArgs.namespace,
+		Namespace:              *kubeconfigArgs.Namespace,
 		Components:             bootstrapComponents(),
 		Registry:               bootstrapArgs.registry,
 		ImagePullSecret:        bootstrapArgs.imagePullSecret,
@@ -200,7 +200,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
 	// Source generation and secret config
 	secretOpts := sourcesecret.Options{
 		Name:         bootstrapArgs.secretName,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		TargetPath:   bServerArgs.path.String(),
 		ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 	}
@@ -232,8 +232,8 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
 	// Sync manifest config
 	syncOpts := sync.Options{
 		Interval:          bServerArgs.interval,
-		Name:              rootArgs.namespace,
-		Namespace:         rootArgs.namespace,
+		Name:              *kubeconfigArgs.Namespace,
+		Namespace:         *kubeconfigArgs.Namespace,
 		Branch:            bootstrapArgs.branch,
 		Secret:            bootstrapArgs.secretName,
 		TargetPath:        bServerArgs.path.ToSlash(),
@@ -251,7 +251,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
 		bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
 		bootstrap.WithProviderTeamPermissions(mapTeamSlice(bServerArgs.teams, bServerDefaultPermission)),
 		bootstrap.WithReadWriteKeyPermissions(bServerArgs.readWriteKey),
-		bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext),
+		bootstrap.WithKubeconfig(kubeconfigArgs),
 		bootstrap.WithLogger(logger),
 		bootstrap.WithCABundle(caBundle),
 	}
diff --git a/cmd/flux/bootstrap_git.go b/cmd/flux/bootstrap_git.go
index 786a2692..4a754764 100644
--- a/cmd/flux/bootstrap_git.go
+++ b/cmd/flux/bootstrap_git.go
@@ -101,7 +101,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -128,7 +128,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
 	installOptions := install.Options{
 		BaseURL:                rootArgs.defaults.BaseURL,
 		Version:                bootstrapArgs.version,
-		Namespace:              rootArgs.namespace,
+		Namespace:              *kubeconfigArgs.Namespace,
 		Components:             bootstrapComponents(),
 		Registry:               bootstrapArgs.registry,
 		ImagePullSecret:        bootstrapArgs.imagePullSecret,
@@ -149,7 +149,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
 	// Source generation and secret config
 	secretOpts := sourcesecret.Options{
 		Name:         bootstrapArgs.secretName,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		TargetPath:   gitArgs.path.String(),
 		ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 	}
@@ -194,8 +194,8 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
 	// Sync manifest config
 	syncOpts := sync.Options{
 		Interval:          gitArgs.interval,
-		Name:              rootArgs.namespace,
-		Namespace:         rootArgs.namespace,
+		Name:              *kubeconfigArgs.Namespace,
+		Namespace:         *kubeconfigArgs.Namespace,
 		URL:               repositoryURL.String(),
 		Branch:            bootstrapArgs.branch,
 		Secret:            bootstrapArgs.secretName,
@@ -220,7 +220,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
 		bootstrap.WithBranch(bootstrapArgs.branch),
 		bootstrap.WithAuthor(bootstrapArgs.authorName, bootstrapArgs.authorEmail),
 		bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
-		bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext),
+		bootstrap.WithKubeconfig(kubeconfigArgs),
 		bootstrap.WithPostGenerateSecretFunc(promptPublicKey),
 		bootstrap.WithLogger(logger),
 		bootstrap.WithCABundle(caBundle),
diff --git a/cmd/flux/bootstrap_github.go b/cmd/flux/bootstrap_github.go
index f2775da9..fd04ac6f 100644
--- a/cmd/flux/bootstrap_github.go
+++ b/cmd/flux/bootstrap_github.go
@@ -125,7 +125,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -175,7 +175,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 	installOptions := install.Options{
 		BaseURL:                rootArgs.defaults.BaseURL,
 		Version:                bootstrapArgs.version,
-		Namespace:              rootArgs.namespace,
+		Namespace:              *kubeconfigArgs.Namespace,
 		Components:             bootstrapComponents(),
 		Registry:               bootstrapArgs.registry,
 		ImagePullSecret:        bootstrapArgs.imagePullSecret,
@@ -196,7 +196,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 	// Source generation and secret config
 	secretOpts := sourcesecret.Options{
 		Name:         bootstrapArgs.secretName,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		TargetPath:   githubArgs.path.ToSlash(),
 		ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 	}
@@ -221,8 +221,8 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 	// Sync manifest config
 	syncOpts := sync.Options{
 		Interval:          githubArgs.interval,
-		Name:              rootArgs.namespace,
-		Namespace:         rootArgs.namespace,
+		Name:              *kubeconfigArgs.Namespace,
+		Namespace:         *kubeconfigArgs.Namespace,
 		Branch:            bootstrapArgs.branch,
 		Secret:            bootstrapArgs.secretName,
 		TargetPath:        githubArgs.path.ToSlash(),
@@ -240,7 +240,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 		bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
 		bootstrap.WithProviderTeamPermissions(mapTeamSlice(githubArgs.teams, ghDefaultPermission)),
 		bootstrap.WithReadWriteKeyPermissions(githubArgs.readWriteKey),
-		bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext),
+		bootstrap.WithKubeconfig(kubeconfigArgs),
 		bootstrap.WithLogger(logger),
 		bootstrap.WithCABundle(caBundle),
 	}
diff --git a/cmd/flux/bootstrap_gitlab.go b/cmd/flux/bootstrap_gitlab.go
index 88b85aeb..6906a2a7 100644
--- a/cmd/flux/bootstrap_gitlab.go
+++ b/cmd/flux/bootstrap_gitlab.go
@@ -129,7 +129,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -186,7 +186,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 	installOptions := install.Options{
 		BaseURL:                rootArgs.defaults.BaseURL,
 		Version:                bootstrapArgs.version,
-		Namespace:              rootArgs.namespace,
+		Namespace:              *kubeconfigArgs.Namespace,
 		Components:             bootstrapComponents(),
 		Registry:               bootstrapArgs.registry,
 		ImagePullSecret:        bootstrapArgs.imagePullSecret,
@@ -207,7 +207,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 	// Source generation and secret config
 	secretOpts := sourcesecret.Options{
 		Name:         bootstrapArgs.secretName,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		TargetPath:   gitlabArgs.path.String(),
 		ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 	}
@@ -235,8 +235,8 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 	// Sync manifest config
 	syncOpts := sync.Options{
 		Interval:          gitlabArgs.interval,
-		Name:              rootArgs.namespace,
-		Namespace:         rootArgs.namespace,
+		Name:              *kubeconfigArgs.Namespace,
+		Namespace:         *kubeconfigArgs.Namespace,
 		Branch:            bootstrapArgs.branch,
 		Secret:            bootstrapArgs.secretName,
 		TargetPath:        gitlabArgs.path.ToSlash(),
@@ -254,7 +254,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 		bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
 		bootstrap.WithProviderTeamPermissions(mapTeamSlice(gitlabArgs.teams, glDefaultPermission)),
 		bootstrap.WithReadWriteKeyPermissions(gitlabArgs.readWriteKey),
-		bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext),
+		bootstrap.WithKubeconfig(kubeconfigArgs),
 		bootstrap.WithLogger(logger),
 		bootstrap.WithCABundle(caBundle),
 	}
diff --git a/cmd/flux/check.go b/cmd/flux/check.go
index 42c6891e..a36159d0 100644
--- a/cmd/flux/check.go
+++ b/cmd/flux/check.go
@@ -128,7 +128,7 @@ func fluxCheck() {
 }
 
 func kubernetesCheck(constraints []string) bool {
-	cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
+	cfg, err := utils.KubeConfig(kubeconfigArgs)
 	if err != nil {
 		logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
 		return false
@@ -176,7 +176,7 @@ func componentsCheck() bool {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
 	if err != nil {
 		return false
 	}
@@ -186,7 +186,7 @@ func componentsCheck() bool {
 		return false
 	}
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return false
 	}
@@ -194,7 +194,7 @@ func componentsCheck() bool {
 	ok := true
 	selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
 	var list v1.DeploymentList
-	if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace), selector); err == nil {
+	if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err == nil {
 		for _, d := range list.Items {
 			if ref, err := buildComponentObjectRefs(d.Name); err == nil {
 				if err := statusChecker.Assess(ref...); err != nil {
diff --git a/cmd/flux/check_test.go b/cmd/flux/check_test.go
index c70d6b09..8ae39b1b 100644
--- a/cmd/flux/check_test.go
+++ b/cmd/flux/check_test.go
@@ -29,7 +29,7 @@ import (
 )
 
 func TestCheckPre(t *testing.T) {
-	jsonOutput, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, "version", "--output", "json")
+	jsonOutput, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, "version", "--output", "json")
 	if err != nil {
 		t.Fatalf("Error running utils.ExecKubectlCommand: %v", err.Error())
 	}
diff --git a/cmd/flux/completion.go b/cmd/flux/completion.go
index 077d768e..06beac2a 100644
--- a/cmd/flux/completion.go
+++ b/cmd/flux/completion.go
@@ -25,10 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/client-go/discovery"
-	memory "k8s.io/client-go/discovery/cached"
 	"k8s.io/client-go/dynamic"
-	"k8s.io/client-go/restmapper"
 )
 
 var completionCmd = &cobra.Command{
@@ -42,7 +39,7 @@ func init() {
 }
 
 func contextsCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
-	rawConfig, err := utils.ClientConfig(rootArgs.kubeconfig, rootArgs.kubecontext).RawConfig()
+	rawConfig, err := kubeconfigArgs.ToRawKubeConfigLoader().RawConfig()
 	if err != nil {
 		return completionError(err)
 	}
@@ -63,16 +60,15 @@ func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Co
 		ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 		defer cancel()
 
-		cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
+		cfg, err := utils.KubeConfig(kubeconfigArgs)
 		if err != nil {
 			return completionError(err)
 		}
 
-		dc, err := discovery.NewDiscoveryClientForConfig(cfg)
+		mapper, err := kubeconfigArgs.ToRESTMapper()
 		if err != nil {
 			return completionError(err)
 		}
-		mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc))
 
 		mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
 		if err != nil {
@@ -86,7 +82,7 @@ func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Co
 
 		var dr dynamic.ResourceInterface
 		if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
-			dr = client.Resource(mapping.Resource).Namespace(rootArgs.namespace)
+			dr = client.Resource(mapping.Resource).Namespace(*kubeconfigArgs.Namespace)
 		} else {
 			dr = client.Resource(mapping.Resource)
 		}
diff --git a/cmd/flux/create.go b/cmd/flux/create.go
index 3010c99c..758a2f54 100644
--- a/cmd/flux/create.go
+++ b/cmd/flux/create.go
@@ -104,7 +104,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) // NB globals
+	kubeClient, err := utils.KubeClient(kubeconfigArgs) // NB globals
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_alert.go b/cmd/flux/create_alert.go
index e260ae64..0a5ea93a 100644
--- a/cmd/flux/create_alert.go
+++ b/cmd/flux/create_alert.go
@@ -102,7 +102,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
 	alert := notificationv1.Alert{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: notificationv1.AlertSpec{
@@ -122,7 +122,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_alertprovider.go b/cmd/flux/create_alertprovider.go
index 93ac7e89..7d5bf640 100644
--- a/cmd/flux/create_alertprovider.go
+++ b/cmd/flux/create_alertprovider.go
@@ -94,7 +94,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	provider := notificationv1.Provider{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: notificationv1.ProviderSpec{
@@ -118,7 +118,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_helmrelease.go b/cmd/flux/create_helmrelease.go
index 6a035858..2072c720 100644
--- a/cmd/flux/create_helmrelease.go
+++ b/cmd/flux/create_helmrelease.go
@@ -160,7 +160,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	helmRelease := helmv2.HelmRelease{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: helmv2.HelmReleaseSpec{
@@ -250,7 +250,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_image_policy.go b/cmd/flux/create_image_policy.go
index 0cebd321..05cb5c14 100644
--- a/cmd/flux/create_image_policy.go
+++ b/cmd/flux/create_image_policy.go
@@ -101,7 +101,7 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
 	var policy = imagev1.ImagePolicy{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      objectName,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    labels,
 		},
 		Spec: imagev1.ImagePolicySpec{
diff --git a/cmd/flux/create_image_repository.go b/cmd/flux/create_image_repository.go
index 7619c8a6..b5ffdcb8 100644
--- a/cmd/flux/create_image_repository.go
+++ b/cmd/flux/create_image_repository.go
@@ -104,7 +104,7 @@ func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
 	var repo = imagev1.ImageRepository{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      objectName,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    labels,
 		},
 		Spec: imagev1.ImageRepositorySpec{
diff --git a/cmd/flux/create_image_update.go b/cmd/flux/create_image_update.go
index 6ef81a28..2adb562c 100644
--- a/cmd/flux/create_image_update.go
+++ b/cmd/flux/create_image_update.go
@@ -108,7 +108,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
 	var update = autov1.ImageUpdateAutomation{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      objectName,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    labels,
 		},
 		Spec: autov1.ImageUpdateAutomationSpec{
diff --git a/cmd/flux/create_kustomization.go b/cmd/flux/create_kustomization.go
index eb898e7b..d523374d 100644
--- a/cmd/flux/create_kustomization.go
+++ b/cmd/flux/create_kustomization.go
@@ -143,7 +143,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 	kustomization := kustomizev1.Kustomization{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    kslabels,
 		},
 		Spec: kustomizev1.KustomizationSpec{
@@ -232,7 +232,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_receiver.go b/cmd/flux/create_receiver.go
index c2d33a15..d6004dc1 100644
--- a/cmd/flux/create_receiver.go
+++ b/cmd/flux/create_receiver.go
@@ -109,7 +109,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	receiver := notificationv1.Receiver{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: notificationv1.ReceiverSpec{
@@ -130,7 +130,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/create_secret_git.go b/cmd/flux/create_secret_git.go
index 0e6d7106..769c2526 100644
--- a/cmd/flux/create_secret_git.go
+++ b/cmd/flux/create_secret_git.go
@@ -132,7 +132,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
 
 	opts := sourcesecret.Options{
 		Name:         name,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		Labels:       labels,
 		ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 	}
@@ -176,14 +176,14 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
 
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 	if err := upsertSecret(ctx, kubeClient, s); err != nil {
 		return err
 	}
-	logger.Actionf("git secret '%s' created in '%s' namespace", name, rootArgs.namespace)
+	logger.Actionf("git secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
 
 	return nil
 }
diff --git a/cmd/flux/create_secret_helm.go b/cmd/flux/create_secret_helm.go
index 0fe8df8b..8f9df1b5 100644
--- a/cmd/flux/create_secret_helm.go
+++ b/cmd/flux/create_secret_helm.go
@@ -80,7 +80,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
 
 	opts := sourcesecret.Options{
 		Name:         name,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		Labels:       labels,
 		Username:     secretHelmArgs.username,
 		Password:     secretHelmArgs.password,
@@ -100,7 +100,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
 
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -112,6 +112,6 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	logger.Actionf("helm secret '%s' created in '%s' namespace", name, rootArgs.namespace)
+	logger.Actionf("helm secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
 	return nil
 }
diff --git a/cmd/flux/create_secret_tls.go b/cmd/flux/create_secret_tls.go
index 2b8c40d9..a308066e 100644
--- a/cmd/flux/create_secret_tls.go
+++ b/cmd/flux/create_secret_tls.go
@@ -79,7 +79,7 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
 
 	opts := sourcesecret.Options{
 		Name:         name,
-		Namespace:    rootArgs.namespace,
+		Namespace:    *kubeconfigArgs.Namespace,
 		Labels:       labels,
 		CAFilePath:   secretTLSArgs.caFile,
 		CertFilePath: secretTLSArgs.certFile,
@@ -97,7 +97,7 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
 
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -109,6 +109,6 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	logger.Actionf("tls secret '%s' created in '%s' namespace", name, rootArgs.namespace)
+	logger.Actionf("tls secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
 	return nil
 }
diff --git a/cmd/flux/create_source_bucket.go b/cmd/flux/create_source_bucket.go
index 4ec6aaea..50858c5b 100644
--- a/cmd/flux/create_source_bucket.go
+++ b/cmd/flux/create_source_bucket.go
@@ -120,7 +120,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	bucket := &sourcev1.Bucket{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: sourcev1.BucketSpec{
@@ -152,7 +152,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -165,7 +165,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 		secret := corev1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      secretName,
-				Namespace: rootArgs.namespace,
+				Namespace: *kubeconfigArgs.Namespace,
 				Labels:    sourceLabels,
 			},
 			StringData: map[string]string{},
diff --git a/cmd/flux/create_source_git.go b/cmd/flux/create_source_git.go
index f2c6b918..17a928b6 100644
--- a/cmd/flux/create_source_git.go
+++ b/cmd/flux/create_source_git.go
@@ -193,7 +193,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	gitRepository := sourcev1.GitRepository{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: sourcev1.GitRepositorySpec{
@@ -235,7 +235,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -244,7 +244,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	if sourceGitArgs.secretRef == "" {
 		secretOpts := sourcesecret.Options{
 			Name:         name,
-			Namespace:    rootArgs.namespace,
+			Namespace:    *kubeconfigArgs.Namespace,
 			ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
 		}
 		switch u.Scheme {
diff --git a/cmd/flux/create_source_helm.go b/cmd/flux/create_source_helm.go
index a1edd409..81b5a05f 100644
--- a/cmd/flux/create_source_helm.go
+++ b/cmd/flux/create_source_helm.go
@@ -118,7 +118,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	helmRepository := &sourcev1.HelmRepository{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Labels:    sourceLabels,
 		},
 		Spec: sourcev1.HelmRepositorySpec{
@@ -147,7 +147,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -157,7 +157,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 		secretName := fmt.Sprintf("helm-%s", name)
 		secretOpts := sourcesecret.Options{
 			Name:         secretName,
-			Namespace:    rootArgs.namespace,
+			Namespace:    *kubeconfigArgs.Namespace,
 			Username:     sourceHelmArgs.username,
 			Password:     sourceHelmArgs.password,
 			CertFilePath: sourceHelmArgs.certFile,
diff --git a/cmd/flux/create_tenant.go b/cmd/flux/create_tenant.go
index 22bb978f..88b8eda6 100644
--- a/cmd/flux/create_tenant.go
+++ b/cmd/flux/create_tenant.go
@@ -159,7 +159,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/flux/delete.go b/cmd/flux/delete.go
index 966f8800..7facf933 100644
--- a/cmd/flux/delete.go
+++ b/cmd/flux/delete.go
@@ -60,13 +60,13 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	namespacedName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
@@ -85,7 +85,7 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, rootArgs.namespace)
+	logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, *kubeconfigArgs.Namespace)
 	err = kubeClient.Delete(ctx, del.object.asClientObject())
 	if err != nil {
 		return err
diff --git a/cmd/flux/export.go b/cmd/flux/export.go
index 173bb763..e9b3be11 100644
--- a/cmd/flux/export.go
+++ b/cmd/flux/export.go
@@ -20,6 +20,7 @@ import (
 	"bytes"
 	"context"
 	"fmt"
+
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -73,19 +74,19 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	if exportArgs.all {
-		err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace))
+		err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(*kubeconfigArgs.Namespace))
 		if err != nil {
 			return err
 		}
 
 		if export.list.len() == 0 {
-			return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace)
+			return fmt.Errorf("no objects found in %s namespace", *kubeconfigArgs.Namespace)
 		}
 
 		for i := 0; i < export.list.len(); i++ {
@@ -96,7 +97,7 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
 	} else {
 		name := args[0]
 		namespacedName := types.NamespacedName{
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Name:      name,
 		}
 		err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())
diff --git a/cmd/flux/export_secret.go b/cmd/flux/export_secret.go
index 74d018b2..eb7dfb05 100644
--- a/cmd/flux/export_secret.go
+++ b/cmd/flux/export_secret.go
@@ -19,6 +19,7 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -58,19 +59,19 @@ func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) err
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	if exportArgs.all {
-		err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace))
+		err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(*kubeconfigArgs.Namespace))
 		if err != nil {
 			return err
 		}
 
 		if export.list.len() == 0 {
-			return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace)
+			return fmt.Errorf("no objects found in %s namespace", *kubeconfigArgs.Namespace)
 		}
 
 		for i := 0; i < export.list.len(); i++ {
@@ -88,7 +89,7 @@ func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) err
 	} else {
 		name := args[0]
 		namespacedName := types.NamespacedName{
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 			Name:      name,
 		}
 		err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())
diff --git a/cmd/flux/get.go b/cmd/flux/get.go
index db3d34dd..f52fd496 100644
--- a/cmd/flux/get.go
+++ b/cmd/flux/get.go
@@ -135,14 +135,14 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	var listOpts []client.ListOption
 	if !getArgs.allNamespaces {
-		listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
+		listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
 	}
 
 	if len(args) > 0 {
@@ -162,7 +162,7 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
 
 	if get.list.len() == 0 {
 		if !getAll {
-			logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace)
+			logger.Failuref("no %s objects found in %s namespace", get.kind, *kubeconfigArgs.Namespace)
 		}
 		return nil
 	}
diff --git a/cmd/flux/install.go b/cmd/flux/install.go
index 36937b16..9032929b 100644
--- a/cmd/flux/install.go
+++ b/cmd/flux/install.go
@@ -131,7 +131,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 		logger.Generatef("generating manifests")
 	}
 
-	tmpDir, err := os.MkdirTemp("", rootArgs.namespace)
+	tmpDir, err := os.MkdirTemp("", *kubeconfigArgs.Namespace)
 	if err != nil {
 		return err
 	}
@@ -148,7 +148,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 	opts := install.Options{
 		BaseURL:                installArgs.manifestsPath,
 		Version:                installArgs.version,
-		Namespace:              rootArgs.namespace,
+		Namespace:              *kubeconfigArgs.Namespace,
 		Components:             components,
 		Registry:               installArgs.registry,
 		ImagePullSecret:        installArgs.imagePullSecret,
@@ -156,7 +156,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 		NetworkPolicy:          installArgs.networkPolicy,
 		LogLevel:               installArgs.logLevel.String(),
 		NotificationController: rootArgs.defaults.NotificationController,
-		ManifestFile:           fmt.Sprintf("%s.yaml", rootArgs.namespace),
+		ManifestFile:           fmt.Sprintf("%s.yaml", *kubeconfigArgs.Namespace),
 		Timeout:                rootArgs.timeout,
 		ClusterDomain:          installArgs.clusterDomain,
 		TolerationKeys:         installArgs.tolerationKeys,
@@ -183,21 +183,21 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 	}
 
 	logger.Successf("manifests build completed")
-	logger.Actionf("installing components in %s namespace", rootArgs.namespace)
+	logger.Actionf("installing components in %s namespace", *kubeconfigArgs.Namespace)
 
 	if installArgs.dryRun {
 		logger.Successf("install dry-run finished")
 		return nil
 	}
 
-	applyOutput, err := utils.Apply(ctx, rootArgs.kubeconfig, rootArgs.kubecontext, filepath.Join(tmpDir, manifest.Path))
+	applyOutput, err := utils.Apply(ctx, kubeconfigArgs, filepath.Join(tmpDir, manifest.Path))
 	if err != nil {
 		return fmt.Errorf("install failed: %w", err)
 	}
 
 	fmt.Fprintln(os.Stderr, applyOutput)
 
-	kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
 	if err != nil {
 		return fmt.Errorf("install failed: %w", err)
 	}
diff --git a/cmd/flux/logs.go b/cmd/flux/logs.go
index 23197363..3dc0f903 100644
--- a/cmd/flux/logs.go
+++ b/cmd/flux/logs.go
@@ -99,7 +99,7 @@ func logsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
+	cfg, err := utils.KubeConfig(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -278,7 +278,7 @@ func filterPrintLog(t *template.Template, l *ControllerLogEntry) {
 	if logsArgs.logLevel != "" && logsArgs.logLevel != l.Level ||
 		logsArgs.kind != "" && strings.ToLower(logsArgs.kind) != strings.ToLower(l.Kind) ||
 		logsArgs.name != "" && strings.ToLower(logsArgs.name) != strings.ToLower(l.Name) ||
-		!logsArgs.allNamespaces && strings.ToLower(rootArgs.namespace) != strings.ToLower(l.Namespace) {
+		!logsArgs.allNamespaces && strings.ToLower(*kubeconfigArgs.Namespace) != strings.ToLower(l.Namespace) {
 		return
 	}
 
diff --git a/cmd/flux/main.go b/cmd/flux/main.go
index 6b00e4b0..d61bcda9 100644
--- a/cmd/flux/main.go
+++ b/cmd/flux/main.go
@@ -21,13 +21,13 @@ import (
 	"fmt"
 	"log"
 	"os"
-	"path/filepath"
 	"strings"
 	"time"
 
 	"github.com/spf13/cobra"
 	"golang.org/x/term"
 	corev1 "k8s.io/api/core/v1"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 
 	"github.com/fluxcd/flux2/pkg/manifestgen/install"
@@ -99,9 +99,6 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.`,
 var logger = stderrLogger{stderr: os.Stderr}
 
 type rootFlags struct {
-	kubeconfig   string
-	kubecontext  string
-	namespace    string
 	timeout      time.Duration
 	verbose      bool
 	pollInterval time.Duration
@@ -109,19 +106,26 @@ type rootFlags struct {
 }
 
 var rootArgs = NewRootFlags()
+var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
 
 func init() {
-	rootCmd.PersistentFlags().StringVarP(&rootArgs.namespace, "namespace", "n", rootArgs.defaults.Namespace,
-		"the namespace scope for this operation, can be set with FLUX_SYSTEM_NAMESPACE env var")
-	rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace")))
-
 	rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation")
 	rootCmd.PersistentFlags().BoolVar(&rootArgs.verbose, "verbose", false, "print generated objects")
-	rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "",
-		"absolute path to the kubeconfig file")
 
-	rootCmd.PersistentFlags().StringVarP(&rootArgs.kubecontext, "context", "", "", "kubernetes context to use")
+	configureDefaultNamespace()
+	kubeconfigArgs.APIServer = nil // prevent AddFlags from configuring --server flag
+	kubeconfigArgs.Timeout = nil   // prevent AddFlags from configuring --request-timeout flag, we have --timeout instead
+	kubeconfigArgs.AddFlags(rootCmd.PersistentFlags())
+
+	// Since some subcommands use the `-s` flag as a short version for `--silent`, we manually configure the server flag
+	// without the `-s` short version. While we're no longer on par with kubectl's flags, we maintain backwards compatibility
+	// on the CLI interface.
+	apiServer := ""
+	kubeconfigArgs.APIServer = &apiServer
+	rootCmd.PersistentFlags().StringVar(kubeconfigArgs.APIServer, "server", *kubeconfigArgs.APIServer, "The address and port of the Kubernetes API server")
+
 	rootCmd.RegisterFlagCompletionFunc("context", contextsCompletionFunc)
+	rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace")))
 
 	rootCmd.DisableAutoGenTag = true
 	rootCmd.SetOut(os.Stdout)
@@ -138,30 +142,17 @@ func NewRootFlags() rootFlags {
 
 func main() {
 	log.SetFlags(0)
-	configureKubeconfig()
-	configureDefaultNamespace()
 	if err := rootCmd.Execute(); err != nil {
 		logger.Failuref("%v", err)
 		os.Exit(1)
 	}
 }
 
-func configureKubeconfig() {
-	switch {
-	case len(rootArgs.kubeconfig) > 0:
-	case len(os.Getenv("KUBECONFIG")) > 0:
-		rootArgs.kubeconfig = os.Getenv("KUBECONFIG")
-	default:
-		if home := homeDir(); len(home) > 0 {
-			rootArgs.kubeconfig = filepath.Join(home, ".kube", "config")
-		}
-	}
-}
-
 func configureDefaultNamespace() {
+	*kubeconfigArgs.Namespace = rootArgs.defaults.Namespace
 	fromEnv := os.Getenv("FLUX_SYSTEM_NAMESPACE")
-	if fromEnv != "" && rootArgs.namespace == rootArgs.defaults.Namespace {
-		rootArgs.namespace = fromEnv
+	if fromEnv != "" {
+		kubeconfigArgs.Namespace = &fromEnv
 	}
 }
 
diff --git a/cmd/flux/main_e2e_test.go b/cmd/flux/main_e2e_test.go
index 1e2c775e..7cd6bfa2 100644
--- a/cmd/flux/main_e2e_test.go
+++ b/cmd/flux/main_e2e_test.go
@@ -35,7 +35,7 @@ func TestMain(m *testing.M) {
 	if err != nil {
 		panic(fmt.Errorf("error creating kube manager: '%w'", err))
 	}
-	rootArgs.kubeconfig = testEnv.kubeConfigPath
+	kubeconfigArgs.KubeConfig = &testEnv.kubeConfigPath
 
 	// Install Flux.
 	output, err := executeCommand("install --components-extra=image-reflector-controller,image-automation-controller")
@@ -54,7 +54,7 @@ func TestMain(m *testing.M) {
 
 	// Delete namespace and wait for finalisation
 	kubectlArgs := []string{"delete", "namespace", "flux-system"}
-	_, err = utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
+	_, err = utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
 	if err != nil {
 		panic(fmt.Errorf("delete namespace error:'%w'", err))
 	}
@@ -66,13 +66,13 @@ func TestMain(m *testing.M) {
 
 func setupTestNamespace(namespace string) (func(), error) {
 	kubectlArgs := []string{"create", "namespace", namespace}
-	_, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
+	_, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
 	if err != nil {
 		return nil, err
 	}
 
 	return func() {
 		kubectlArgs := []string{"delete", "namespace", namespace}
-		utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
+		utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
 	}, nil
 }
diff --git a/cmd/flux/main_unit_test.go b/cmd/flux/main_unit_test.go
index 2b992cce..605b204c 100644
--- a/cmd/flux/main_unit_test.go
+++ b/cmd/flux/main_unit_test.go
@@ -42,7 +42,8 @@ func TestMain(m *testing.M) {
 		panic(fmt.Errorf("error creating kube manager: '%w'", err))
 	}
 	testEnv = km
-	rootArgs.kubeconfig = testEnv.kubeConfigPath
+	// rootArgs.kubeconfig = testEnv.kubeConfigPath
+	kubeconfigArgs.KubeConfig = &testEnv.kubeConfigPath
 
 	// Run tests
 	code := m.Run()
diff --git a/cmd/flux/reconcile.go b/cmd/flux/reconcile.go
index c0c609d8..c3e53a73 100644
--- a/cmd/flux/reconcile.go
+++ b/cmd/flux/reconcile.go
@@ -75,13 +75,13 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	namespacedName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
@@ -94,7 +94,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("resource is suspended")
 	}
 
-	logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.namespace)
+	logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
 	if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
 		return err
 	}
diff --git a/cmd/flux/reconcile_alertprovider.go b/cmd/flux/reconcile_alertprovider.go
index 092e8ac9..df24a68e 100644
--- a/cmd/flux/reconcile_alertprovider.go
+++ b/cmd/flux/reconcile_alertprovider.go
@@ -54,17 +54,17 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	namespacedName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
-	logger.Actionf("annotating Provider %s in %s namespace", name, rootArgs.namespace)
+	logger.Actionf("annotating Provider %s in %s namespace", name, *kubeconfigArgs.Namespace)
 	var alertProvider notificationv1.Provider
 	err = kubeClient.Get(ctx, namespacedName, &alertProvider)
 	if err != nil {
diff --git a/cmd/flux/reconcile_receiver.go b/cmd/flux/reconcile_receiver.go
index 9b7e7fd0..676aa30a 100644
--- a/cmd/flux/reconcile_receiver.go
+++ b/cmd/flux/reconcile_receiver.go
@@ -54,13 +54,13 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	namespacedName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
@@ -74,7 +74,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("resource is suspended")
 	}
 
-	logger.Actionf("annotating Receiver %s in %s namespace", name, rootArgs.namespace)
+	logger.Actionf("annotating Receiver %s in %s namespace", name, *kubeconfigArgs.Namespace)
 	if receiver.Annotations == nil {
 		receiver.Annotations = map[string]string{
 			meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
diff --git a/cmd/flux/reconcile_with_source.go b/cmd/flux/reconcile_with_source.go
index 7052b879..4eff1ee8 100644
--- a/cmd/flux/reconcile_with_source.go
+++ b/cmd/flux/reconcile_with_source.go
@@ -36,13 +36,13 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	namespacedName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
@@ -57,20 +57,20 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
 
 	if reconcile.object.reconcileSource() {
 		reconcileCmd, nsName := reconcile.object.getSource()
-		nsCopy := rootArgs.namespace
+		nsCopy := *kubeconfigArgs.Namespace
 		if nsName.Namespace != "" {
-			rootArgs.namespace = nsName.Namespace
+			*kubeconfigArgs.Namespace = nsName.Namespace
 		}
 
 		err := reconcileCmd.run(nil, []string{nsName.Name})
 		if err != nil {
 			return err
 		}
-		rootArgs.namespace = nsCopy
+		*kubeconfigArgs.Namespace = nsCopy
 	}
 
 	lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
-	logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.namespace)
+	logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
 	if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
 		return err
 	}
diff --git a/cmd/flux/resume.go b/cmd/flux/resume.go
index 004bcfb6..163fbb90 100644
--- a/cmd/flux/resume.go
+++ b/cmd/flux/resume.go
@@ -72,13 +72,13 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	var listOpts []client.ListOption
-	listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
+	listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
 	if len(args) > 0 {
 		listOpts = append(listOpts, client.MatchingFields{
 			"metadata.name": args[0],
@@ -91,12 +91,12 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
 	}
 
 	if resume.list.len() == 0 {
-		logger.Failuref("no %s objects found in %s namespace", resume.kind, rootArgs.namespace)
+		logger.Failuref("no %s objects found in %s namespace", resume.kind, *kubeconfigArgs.Namespace)
 		return nil
 	}
 
 	for i := 0; i < resume.list.len(); i++ {
-		logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), rootArgs.namespace)
+		logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
 		resume.list.resumeItem(i).setUnsuspended()
 		if err := kubeClient.Update(ctx, resume.list.resumeItem(i).asClientObject()); err != nil {
 			return err
@@ -105,7 +105,7 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
 
 		namespacedName := types.NamespacedName{
 			Name:      resume.list.resumeItem(i).asClientObject().GetName(),
-			Namespace: rootArgs.namespace,
+			Namespace: *kubeconfigArgs.Namespace,
 		}
 
 		logger.Waitingf("waiting for %s reconciliation", resume.kind)
diff --git a/cmd/flux/status.go b/cmd/flux/status.go
index 631a3e2f..d39071e2 100644
--- a/cmd/flux/status.go
+++ b/cmd/flux/status.go
@@ -69,7 +69,7 @@ func isReady(ctx context.Context, kubeClient client.Client,
 func buildComponentObjectRefs(components ...string) ([]object.ObjMetadata, error) {
 	var objRefs []object.ObjMetadata
 	for _, deployment := range components {
-		objMeta, err := object.CreateObjMetadata(rootArgs.namespace, deployment, schema.GroupKind{Group: "apps", Kind: "Deployment"})
+		objMeta, err := object.CreateObjMetadata(*kubeconfigArgs.Namespace, deployment, schema.GroupKind{Group: "apps", Kind: "Deployment"})
 		if err != nil {
 			return nil, err
 		}
diff --git a/cmd/flux/suspend.go b/cmd/flux/suspend.go
index 101f29bb..02a44bd1 100644
--- a/cmd/flux/suspend.go
+++ b/cmd/flux/suspend.go
@@ -69,13 +69,13 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	var listOpts []client.ListOption
-	listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
+	listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
 	if len(args) > 0 {
 		listOpts = append(listOpts, client.MatchingFields{
 			"metadata.name": args[0],
@@ -88,12 +88,12 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
 	}
 
 	if suspend.list.len() == 0 {
-		logger.Failuref("no %s objects found in %s namespace", suspend.kind, rootArgs.namespace)
+		logger.Failuref("no %s objects found in %s namespace", suspend.kind, *kubeconfigArgs.Namespace)
 		return nil
 	}
 
 	for i := 0; i < suspend.list.len(); i++ {
-		logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), rootArgs.namespace)
+		logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
 		suspend.list.item(i).setSuspended()
 		if err := kubeClient.Update(ctx, suspend.list.item(i).asClientObject()); err != nil {
 			return err
diff --git a/cmd/flux/trace.go b/cmd/flux/trace.go
index a5af188e..910c9d43 100644
--- a/cmd/flux/trace.go
+++ b/cmd/flux/trace.go
@@ -89,7 +89,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
@@ -107,7 +107,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
 	})
 
 	objName := types.NamespacedName{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}
 
diff --git a/cmd/flux/tree_kustomization.go b/cmd/flux/tree_kustomization.go
index 25d4142d..ed19f685 100644
--- a/cmd/flux/tree_kustomization.go
+++ b/cmd/flux/tree_kustomization.go
@@ -77,14 +77,14 @@ func treeKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
 	k := &kustomizev1.Kustomization{}
 	err = kubeClient.Get(ctx, client.ObjectKey{
-		Namespace: rootArgs.namespace,
+		Namespace: *kubeconfigArgs.Namespace,
 		Name:      name,
 	}, k)
 	if err != nil {
diff --git a/cmd/flux/uninstall.go b/cmd/flux/uninstall.go
index 448137a1..15d271b8 100644
--- a/cmd/flux/uninstall.go
+++ b/cmd/flux/uninstall.go
@@ -82,13 +82,13 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
 	defer cancel()
 
-	kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+	kubeClient, err := utils.KubeClient(kubeconfigArgs)
 	if err != nil {
 		return err
 	}
 
-	logger.Actionf("deleting components in %s namespace", rootArgs.namespace)
-	uninstallComponents(ctx, kubeClient, rootArgs.namespace, uninstallArgs.dryRun)
+	logger.Actionf("deleting components in %s namespace", *kubeconfigArgs.Namespace)
+	uninstallComponents(ctx, kubeClient, *kubeconfigArgs.Namespace, uninstallArgs.dryRun)
 
 	logger.Actionf("deleting toolkit.fluxcd.io finalizers in all namespaces")
 	uninstallFinalizers(ctx, kubeClient, uninstallArgs.dryRun)
@@ -97,7 +97,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 	uninstallCustomResourceDefinitions(ctx, kubeClient, uninstallArgs.dryRun)
 
 	if !uninstallArgs.keepNamespace {
-		uninstallNamespace(ctx, kubeClient, rootArgs.namespace, uninstallArgs.dryRun)
+		uninstallNamespace(ctx, kubeClient, *kubeconfigArgs.Namespace, uninstallArgs.dryRun)
 	}
 
 	logger.Successf("uninstall finished")
diff --git a/cmd/flux/version.go b/cmd/flux/version.go
index 93ee3f90..f5da9e29 100644
--- a/cmd/flux/version.go
+++ b/cmd/flux/version.go
@@ -74,19 +74,19 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
 	info["flux"] = rootArgs.defaults.Version
 
 	if !versionArgs.client {
-		kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
+		kubeClient, err := utils.KubeClient(kubeconfigArgs)
 		if err != nil {
 			return err
 		}
 
 		selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
 		var list v1.DeploymentList
-		if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace), selector); err != nil {
+		if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err != nil {
 			return err
 		}
 
 		if len(list.Items) == 0 {
-			return fmt.Errorf("no deployments found in %s namespace", rootArgs.namespace)
+			return fmt.Errorf("no deployments found in %s namespace", *kubeconfigArgs.Namespace)
 		}
 
 		for _, d := range list.Items {
diff --git a/go.mod b/go.mod
index 1cdfd738..a48b2954 100644
--- a/go.mod
+++ b/go.mod
@@ -33,6 +33,7 @@ require (
 	k8s.io/api v0.22.2
 	k8s.io/apiextensions-apiserver v0.22.2
 	k8s.io/apimachinery v0.22.2
+	k8s.io/cli-runtime v0.21.1
 	k8s.io/client-go v0.22.2
 	k8s.io/kubectl v0.21.1
 	sigs.k8s.io/cli-utils v0.26.0
diff --git a/internal/bootstrap/bootstrap_plain_git.go b/internal/bootstrap/bootstrap_plain_git.go
index 16d66ed7..f661e936 100644
--- a/internal/bootstrap/bootstrap_plain_git.go
+++ b/internal/bootstrap/bootstrap_plain_git.go
@@ -27,6 +27,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"sigs.k8s.io/cli-utils/pkg/object"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/kustomize/api/filesys"
@@ -57,8 +58,7 @@ type PlainGitBootstrapper struct {
 	gpgPassphrase  string
 	gpgKeyID       string
 
-	kubeconfig  string
-	kubecontext string
+	restClientGetter genericclioptions.RESTClientGetter
 
 	postGenerateSecret []PostGenerateSecretFunc
 
@@ -167,12 +167,12 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest
 		if _, err := os.Stat(kfile); err == nil {
 			// Apply the components and their patches
 			b.logger.Actionf("installing components in %q namespace", options.Namespace)
-			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, kfile); err != nil {
+			if _, err := utils.Apply(ctx, b.restClientGetter, kfile); err != nil {
 				return err
 			}
 		} else {
 			// Apply the CRDs and controllers
-			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, componentsYAML); err != nil {
+			if _, err := utils.Apply(ctx, b.restClientGetter, componentsYAML); err != nil {
 				return err
 			}
 		}
@@ -299,7 +299,7 @@ func (b *PlainGitBootstrapper) ReconcileSyncConfig(ctx context.Context, options
 
 	// Apply to cluster
 	b.logger.Actionf("applying sync manifests")
-	if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, filepath.Join(b.git.Path(), kusManifests.Path)); err != nil {
+	if _, err := utils.Apply(ctx, b.restClientGetter, filepath.Join(b.git.Path(), kusManifests.Path)); err != nil {
 		return err
 	}
 
@@ -332,7 +332,7 @@ func (b *PlainGitBootstrapper) ReportKustomizationHealth(ctx context.Context, op
 }
 
 func (b *PlainGitBootstrapper) ReportComponentsHealth(ctx context.Context, install install.Options, timeout time.Duration) error {
-	cfg, err := utils.KubeConfig(b.kubeconfig, b.kubecontext)
+	cfg, err := utils.KubeConfig(b.restClientGetter)
 	if err != nil {
 		return err
 	}
diff --git a/internal/bootstrap/options.go b/internal/bootstrap/options.go
index 2deb67db..6d79055c 100644
--- a/internal/bootstrap/options.go
+++ b/internal/bootstrap/options.go
@@ -19,6 +19,7 @@ package bootstrap
 import (
 	"github.com/fluxcd/flux2/internal/bootstrap/git"
 	"github.com/fluxcd/flux2/pkg/log"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 )
 
 type Option interface {
@@ -90,21 +91,18 @@ func (o commitMessageAppendixOption) applyGitProvider(b *GitProviderBootstrapper
 	o.applyGit(b.PlainGitBootstrapper)
 }
 
-func WithKubeconfig(kubeconfig, kubecontext string) Option {
+func WithKubeconfig(rcg genericclioptions.RESTClientGetter) Option {
 	return kubeconfigOption{
-		kubeconfig:  kubeconfig,
-		kubecontext: kubecontext,
+		rcg: rcg,
 	}
 }
 
 type kubeconfigOption struct {
-	kubeconfig  string
-	kubecontext string
+	rcg genericclioptions.RESTClientGetter
 }
 
 func (o kubeconfigOption) applyGit(b *PlainGitBootstrapper) {
-	b.kubeconfig = o.kubeconfig
-	b.kubecontext = o.kubecontext
+	b.restClientGetter = o.rcg
 }
 
 func (o kubeconfigOption) applyGitProvider(b *GitProviderBootstrapper) {
diff --git a/internal/utils/apply.go b/internal/utils/apply.go
index cf87123d..7865d0f2 100644
--- a/internal/utils/apply.go
+++ b/internal/utils/apply.go
@@ -26,9 +26,9 @@ import (
 
 	"github.com/fluxcd/pkg/ssa"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
 	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
 	"sigs.k8s.io/kustomize/api/konfig"
 
 	"github.com/fluxcd/flux2/pkg/manifestgen/kustomization"
@@ -36,12 +36,12 @@ import (
 
 // Apply is the equivalent of 'kubectl apply --server-side -f'.
 // If the given manifest is a kustomization.yaml, then apply performs the equivalent of 'kubectl apply --server-side -k'.
-func Apply(ctx context.Context, kubeConfigPath string, kubeContext string, manifestPath string) (string, error) {
-	cfg, err := KubeConfig(kubeConfigPath, kubeContext)
+func Apply(ctx context.Context, rcg genericclioptions.RESTClientGetter, manifestPath string) (string, error) {
+	cfg, err := KubeConfig(rcg)
 	if err != nil {
 		return "", err
 	}
-	restMapper, err := apiutil.NewDynamicRESTMapper(cfg)
+	restMapper, err := rcg.ToRESTMapper()
 	if err != nil {
 		return "", err
 	}
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index 963b88e2..361b9448 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -37,8 +37,8 @@ import (
 	apiruntime "k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	sigyaml "k8s.io/apimachinery/pkg/util/yaml"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"k8s.io/client-go/rest"
-	"k8s.io/client-go/tools/clientcmd"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/yaml"
 
@@ -107,22 +107,8 @@ func ExecKubectlCommand(ctx context.Context, mode ExecMode, kubeConfigPath strin
 	return "", nil
 }
 
-func ClientConfig(kubeConfigPath string, kubeContext string) clientcmd.ClientConfig {
-	configFiles := SplitKubeConfigPath(kubeConfigPath)
-	configOverrides := clientcmd.ConfigOverrides{}
-
-	if len(kubeContext) > 0 {
-		configOverrides.CurrentContext = kubeContext
-	}
-
-	return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
-		&clientcmd.ClientConfigLoadingRules{Precedence: configFiles},
-		&configOverrides,
-	)
-}
-
-func KubeConfig(kubeConfigPath string, kubeContext string) (*rest.Config, error) {
-	cfg, err := ClientConfig(kubeConfigPath, kubeContext).ClientConfig()
+func KubeConfig(rcg genericclioptions.RESTClientGetter) (*rest.Config, error) {
+	cfg, err := rcg.ToRESTConfig()
 	if err != nil {
 		return nil, fmt.Errorf("kubernetes configuration load failed: %w", err)
 	}
@@ -152,10 +138,10 @@ func NewScheme() *apiruntime.Scheme {
 	return scheme
 }
 
-func KubeClient(kubeConfigPath string, kubeContext string) (client.WithWatch, error) {
-	cfg, err := KubeConfig(kubeConfigPath, kubeContext)
+func KubeClient(rcg genericclioptions.RESTClientGetter) (client.WithWatch, error) {
+	cfg, err := rcg.ToRESTConfig()
 	if err != nil {
-		return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
+		return nil, err
 	}
 
 	scheme := NewScheme()
-- 
GitLab