diff --git a/.github/aur/flux-bin/.SRCINFO.template b/.github/aur/flux-bin/.SRCINFO.template
index 7f20ef923b5074ad7d88cea72f0dbad0a2b38107..5a4e706e2bfb9ea3eb495910c3fb9839e1a65372 100644
--- a/.github/aur/flux-bin/.SRCINFO.template
+++ b/.github/aur/flux-bin/.SRCINFO.template
@@ -8,7 +8,6 @@ pkgbase = flux-bin
 	arch = armv7h
 	arch = aarch64
 	license = APACHE
-	optdepends = kubectl
 	source_x86_64 = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_amd64.tar.gz
 	source_armv6h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
 	source_armv7h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
diff --git a/.github/aur/flux-bin/PKGBUILD.template b/.github/aur/flux-bin/PKGBUILD.template
index aa4b33db8f48dc612aef8c090c6a97bd464eb428..f3106d1ce574cb68c04a71dec7bfab026d2a2077 100644
--- a/.github/aur/flux-bin/PKGBUILD.template
+++ b/.github/aur/flux-bin/PKGBUILD.template
@@ -8,8 +8,7 @@ pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
 url="https://fluxcd.io/"
 arch=("x86_64" "armv6h" "armv7h" "aarch64")
 license=("APACHE")
-optdepends=('kubectl: for apply actions on the Kubernetes cluster',
-'bash-completion: auto-completion for flux in Bash',
+optdepends=('bash-completion: auto-completion for flux in Bash',
 'zsh-completions: auto-completion for flux in ZSH')
 source_x86_64=(
   "${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_amd64.tar.gz"
diff --git a/.github/aur/flux-go/.SRCINFO.template b/.github/aur/flux-go/.SRCINFO.template
index ba0cfd7785993205e4095fee2fc47f2e202d60f1..9f7aaf8bc3c116faba79e5dc5c569316e2f255e8 100644
--- a/.github/aur/flux-go/.SRCINFO.template
+++ b/.github/aur/flux-go/.SRCINFO.template
@@ -10,7 +10,6 @@ pkgbase = flux-go
 	license = APACHE
 	makedepends = go
 	depends = glibc
-	optdepends = kubectl
 	provides = flux-bin
 	conflicts = flux-bin
   replaces = flux-cli
diff --git a/.github/aur/flux-go/PKGBUILD.template b/.github/aur/flux-go/PKGBUILD.template
index e71d83229d75a04c40aee63e82d1b77eb99fd5f2..f9082627898f19d82c4d450f28294e25270d1623 100644
--- a/.github/aur/flux-go/PKGBUILD.template
+++ b/.github/aur/flux-go/PKGBUILD.template
@@ -13,8 +13,7 @@ conflicts=("flux-bin")
 replaces=("flux-cli")
 depends=("glibc")
 makedepends=('go>=1.16', 'kustomize>=3.0')
-optdepends=('kubectl: for apply actions on the Kubernetes cluster',
-'bash-completion: auto-completion for flux in Bash',
+optdepends=('bash-completion: auto-completion for flux in Bash',
 'zsh-completions: auto-completion for flux in ZSH')
 source=(
   "${pkgname}-${pkgver}.tar.gz::https://github.com/fluxcd/flux2/archive/v${pkgver}.tar.gz"
diff --git a/.github/aur/flux-scm/.SRCINFO.template b/.github/aur/flux-scm/.SRCINFO.template
index e7f3288a7cc965bca411e7be992a2c21313836e6..343c7ce2150c8e38d2204efde397356895434d63 100644
--- a/.github/aur/flux-scm/.SRCINFO.template
+++ b/.github/aur/flux-scm/.SRCINFO.template
@@ -10,7 +10,6 @@ pkgbase = flux-scm
 	license = APACHE
 	makedepends = go
 	depends = glibc
-	optdepends = kubectl
 	provides = flux-bin
 	conflicts = flux-bin
 	source = git+https://github.com/fluxcd/flux2.git
diff --git a/.github/aur/flux-scm/PKGBUILD.template b/.github/aur/flux-scm/PKGBUILD.template
index 16cdf969fa86699f14f1e144fffece5405706ca5..c22a5c6e72cbf05d7d6f8bb5ee88ee6d7bbc4655 100644
--- a/.github/aur/flux-scm/PKGBUILD.template
+++ b/.github/aur/flux-scm/PKGBUILD.template
@@ -12,8 +12,7 @@ provides=("flux-bin")
 conflicts=("flux-bin")
 depends=("glibc")
 makedepends=('go>=1.16', 'kustomize>=3.0')
-optdepends=('kubectl: for apply actions on the Kubernetes cluster',
-'bash-completion: auto-completion for flux in Bash',
+optdepends=('bash-completion: auto-completion for flux in Bash',
 'zsh-completions: auto-completion for flux in ZSH')
 source=(
   "git+https://github.com/fluxcd/flux2.git"
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index 16fc6a567643ccf5f07100f58070b758ec7aa30b..482747542c680f0e2ebf7406cd7d6710b8254279 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -93,7 +93,6 @@ jobs:
             --path="./deploy/overlays/dev" \
             --prune=true \
             --interval=5m \
-            --validation=client \
             --health-check="Deployment/frontend.dev" \
             --health-check="Deployment/backend.dev" \
             --health-check-timeout=3m
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 6fbf555096e3c3f88b6dd2f6329c24bfcb6f062d..b57017b19de61d2cb162bd4d4c6098112af6d249 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -49,9 +49,6 @@ brews:
     folder: Formula
     homepage: "https://fluxcd.io/"
     description: "Flux CLI"
-    dependencies:
-      - name: kubectl
-        type: optional
     install: |
       bin.install "flux"
 
diff --git a/Dockerfile b/Dockerfile
index 4145caa384686b2c5d55f3a5a2d451986fcd6ce2..61f4a28b2d358892d2c03df6c961d6cadd52173a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,7 +3,7 @@ FROM alpine:3.13 as builder
 RUN apk add --no-cache ca-certificates curl
 
 ARG ARCH=linux/amd64
-ARG KUBECTL_VER=1.20.4
+ARG KUBECTL_VER=1.22.2
 
 RUN curl -sL https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/${ARCH}/kubectl \
     -o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl && \
diff --git a/cmd/flux/check.go b/cmd/flux/check.go
index 82af8b885d01289a867b8458ab0f9462acdd7c8a..d613312fc2663a4fb659eda64503f449f30b7ade 100644
--- a/cmd/flux/check.go
+++ b/cmd/flux/check.go
@@ -18,15 +18,12 @@ package main
 
 import (
 	"context"
-	"encoding/json"
 	"os"
-	"os/exec"
 	"time"
 
 	"github.com/Masterminds/semver/v3"
 	"github.com/spf13/cobra"
 	v1 "k8s.io/api/apps/v1"
-	apimachineryversion "k8s.io/apimachinery/pkg/version"
 	"k8s.io/client-go/kubernetes"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -56,8 +53,11 @@ type checkFlags struct {
 	extraComponents []string
 }
 
-type kubectlVersion struct {
-	ClientVersion *apimachineryversion.Info `json:"clientVersion"`
+var kubernetesConstraints = []string{
+	">=1.19.0-0",
+	">=1.16.11-0 <=1.16.15-0",
+	">=1.17.7-0 <=1.17.17-0",
+	">=1.18.4-0 <=1.18.20-0",
 }
 
 var checkArgs checkFlags
@@ -73,19 +73,12 @@ func init() {
 }
 
 func runCheckCmd(cmd *cobra.Command, args []string) error {
-	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
-	defer cancel()
-
 	logger.Actionf("checking prerequisites")
 	checkFailed := false
 
 	fluxCheck()
 
-	if !kubectlCheck(ctx, ">=1.18.0-0") {
-		checkFailed = true
-	}
-
-	if !kubernetesCheck(">=1.16.0-0") {
+	if !kubernetesCheck(kubernetesConstraints) {
 		checkFailed = true
 	}
 
@@ -130,43 +123,7 @@ func fluxCheck() {
 	}
 }
 
-func kubectlCheck(ctx context.Context, constraint string) bool {
-	_, err := exec.LookPath("kubectl")
-	if err != nil {
-		logger.Failuref("kubectl not found")
-		return false
-	}
-
-	kubectlArgs := []string{"version", "--client", "--output", "json"}
-	output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
-	if err != nil {
-		logger.Failuref("kubectl version can't be determined")
-		return false
-	}
-
-	kv := &kubectlVersion{}
-	if err = json.Unmarshal([]byte(output), kv); err != nil {
-		logger.Failuref("kubectl version output can't be unmarshalled")
-		return false
-	}
-
-	v, err := version.ParseVersion(kv.ClientVersion.GitVersion)
-	if err != nil {
-		logger.Failuref("kubectl version can't be parsed")
-		return false
-	}
-
-	c, _ := semver.NewConstraint(constraint)
-	if !c.Check(v) {
-		logger.Failuref("kubectl version %s < %s", v.Original(), constraint)
-		return false
-	}
-
-	logger.Successf("kubectl %s %s", v.String(), constraint)
-	return true
-}
-
-func kubernetesCheck(constraint string) bool {
+func kubernetesCheck(constraints []string) bool {
 	cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
 	if err != nil {
 		logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
@@ -191,13 +148,23 @@ func kubernetesCheck(constraint string) bool {
 		return false
 	}
 
-	c, _ := semver.NewConstraint(constraint)
-	if !c.Check(v) {
-		logger.Failuref("Kubernetes version %s < %s", v.Original(), constraint)
+	var valid bool
+	var vrange string
+	for _, constraint := range constraints {
+		c, _ := semver.NewConstraint(constraint)
+		if c.Check(v) {
+			valid = true
+			vrange = constraint
+			break
+		}
+	}
+
+	if !valid {
+		logger.Failuref("Kubernetes version %s does not match %s", v.Original(), constraints[0])
 		return false
 	}
 
-	logger.Successf("Kubernetes %s %s", v.String(), constraint)
+	logger.Successf("Kubernetes %s %s", v.String(), vrange)
 	return true
 }
 
diff --git a/cmd/flux/check_test.go b/cmd/flux/check_test.go
index 542e6ababf29142ac8f81e604e843703072ab912..464200a60bae2192264984f92f4cca11f3aa1cf0 100644
--- a/cmd/flux/check_test.go
+++ b/cmd/flux/check_test.go
@@ -23,13 +23,11 @@ func TestCheckPre(t *testing.T) {
 		t.Fatalf("Error unmarshalling: %v", err.Error())
 	}
 
-	clientVersion := strings.TrimPrefix(versions["clientVersion"].GitVersion, "v")
 	serverVersion := strings.TrimPrefix(versions["serverVersion"].GitVersion, "v")
 
 	cmd := cmdTestCase{
 		args: "check --pre",
 		assert: assertGoldenTemplateFile("testdata/check/check_pre.golden", map[string]string{
-			"clientVersion": clientVersion,
 			"serverVersion": serverVersion,
 		}),
 	}
diff --git a/cmd/flux/create_kustomization.go b/cmd/flux/create_kustomization.go
index 2609585ffd2949a5b8f00cc02af8b10148537ad7..fbcfce2388faa07f0fbb41ddfe681b8d3050bee9 100644
--- a/cmd/flux/create_kustomization.go
+++ b/cmd/flux/create_kustomization.go
@@ -31,7 +31,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	"github.com/fluxcd/pkg/apis/meta"
 
 	"github.com/fluxcd/flux2/internal/flags"
@@ -49,7 +49,6 @@ var createKsCmd = &cobra.Command{
     --path="./examples/contour/" \
     --prune=true \
     --interval=10m \
-    --validation=client \
     --health-check="Deployment/contour.projectcontour" \
     --health-check="DaemonSet/envoy.projectcontour" \
     --health-check-timeout=3m
@@ -60,8 +59,7 @@ var createKsCmd = &cobra.Command{
     --source=GitRepository/webapp \
     --path="./deploy/overlays/dev" \
     --prune=true \
-    --interval=5m \
-    --validation=client
+    --interval=5m
 
   # Create a Kustomization using a source from a different namespace
   flux create kustomization podinfo \
@@ -69,8 +67,7 @@ var createKsCmd = &cobra.Command{
     --source=GitRepository/podinfo.flux-system \
     --path="./deploy/overlays/dev" \
     --prune=true \
-    --interval=5m \
-    --validation=client
+    --interval=5m
 
   # Create a Kustomization resource that references a Bucket
   flux create kustomization secrets \
@@ -108,6 +105,8 @@ func init() {
 	createKsCmd.Flags().Var(&kustomizationArgs.decryptionProvider, "decryption-provider", kustomizationArgs.decryptionProvider.Description())
 	createKsCmd.Flags().StringVar(&kustomizationArgs.decryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
 	createKsCmd.Flags().StringVar(&kustomizationArgs.targetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
+	createKsCmd.Flags().MarkDeprecated("validation", "this arg is no longer used, all resources are validated using server-side apply dry-run")
+
 	createCmd.AddCommand(createKsCmd)
 }
 
@@ -158,7 +157,6 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 				Namespace: kustomizationArgs.source.Namespace,
 			},
 			Suspend:         false,
-			Validation:      kustomizationArgs.validation,
 			TargetNamespace: kustomizationArgs.targetNamespace,
 		},
 	}
diff --git a/cmd/flux/delete_kustomization.go b/cmd/flux/delete_kustomization.go
index 142eed262572295e84fc516bd3b0858edd551f79..e3366f2f8f8a181abc5faecae666fdd5bdcb5fbb 100644
--- a/cmd/flux/delete_kustomization.go
+++ b/cmd/flux/delete_kustomization.go
@@ -19,7 +19,7 @@ package main
 import (
 	"github.com/spf13/cobra"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 var deleteKsCmd = &cobra.Command{
diff --git a/cmd/flux/export_kustomization.go b/cmd/flux/export_kustomization.go
index fcf488194cdc63d760e30cdb030459b1ccfeca4e..ed613dcc6baa95b3351a35b747b8efdac9a36e2e 100644
--- a/cmd/flux/export_kustomization.go
+++ b/cmd/flux/export_kustomization.go
@@ -20,7 +20,7 @@ import (
 	"github.com/spf13/cobra"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 var exportKsCmd = &cobra.Command{
diff --git a/cmd/flux/get_all.go b/cmd/flux/get_all.go
index 75d2216a075f8fd8ac20956a230b323c91adb242..5d4d03f23ec3515969fd2bb0e0ef7166f9881f7a 100644
--- a/cmd/flux/get_all.go
+++ b/cmd/flux/get_all.go
@@ -22,7 +22,7 @@ import (
 	"github.com/spf13/cobra"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 )
 
diff --git a/cmd/flux/get_kustomization.go b/cmd/flux/get_kustomization.go
index 3e749b2d691ac2d251eef3aa5f8fac2c4e1739d1..a6f1eb6a150852f869e119a8a0efd91e2ee46d7c 100644
--- a/cmd/flux/get_kustomization.go
+++ b/cmd/flux/get_kustomization.go
@@ -24,7 +24,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/runtime"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 var getKsCmd = &cobra.Command{
diff --git a/cmd/flux/install.go b/cmd/flux/install.go
index 436189b87310deccb5d500c64c80840917c0a930..cd6c8ccb751a8f332af38b51132dc2787c446c0c 100644
--- a/cmd/flux/install.go
+++ b/cmd/flux/install.go
@@ -41,13 +41,13 @@ If a previous version is installed, then an in-place upgrade will be performed.`
   flux install --version=latest --namespace=flux-system
 
   # Install a specific version and a series of components
-  flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
+  flux install --version=v0.0.7 --components="source-controller,kustomize-controller"
 
   # Install Flux onto tainted Kubernetes nodes
   flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
 
-  # Dry-run install with manifests preview
-  flux install --dry-run --verbose
+  # Dry-run install
+  flux install --export | kubectl apply --dry-run=client -f- 
 
   # Write install manifests to file
   flux install --export > flux-system.yaml`,
@@ -102,6 +102,7 @@ func init() {
 		"list of toleration keys used to schedule the components pods onto nodes with matching taints")
 	installCmd.Flags().MarkHidden("manifests")
 	installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
+	installCmd.Flags().MarkDeprecated("dry-run", "use 'flux install --export | kubectl apply --dry-run=client -f-'")
 	rootCmd.AddCommand(installCmd)
 }
 
@@ -188,24 +189,18 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 
 	logger.Successf("manifests build completed")
 	logger.Actionf("installing components in %s namespace", rootArgs.namespace)
-	applyOutput := utils.ModeStderrOS
-	if rootArgs.verbose {
-		applyOutput = utils.ModeOS
-	}
 
-	kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)}
 	if installArgs.dryRun {
-		kubectlArgs = append(kubectlArgs, "--dry-run=client")
-		applyOutput = utils.ModeOS
+		logger.Successf("install dry-run finished")
+		return nil
 	}
-	if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
+
+	applyOutput, err := utils.Apply(ctx, rootArgs.kubeconfig, rootArgs.kubecontext, filepath.Join(tmpDir, manifest.Path))
+	if err != nil {
 		return fmt.Errorf("install failed: %w", err)
 	}
 
-	if installArgs.dryRun {
-		logger.Successf("install dry-run finished")
-		return nil
-	}
+	fmt.Fprintln(os.Stderr, applyOutput)
 
 	kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
 	if err != nil {
diff --git a/cmd/flux/kustomization.go b/cmd/flux/kustomization.go
index 304d8065841a4b93bbb9844e7d334ff22cee211a..1151b7aa0ab322d923f31ac5956936c8994a9d26 100644
--- a/cmd/flux/kustomization.go
+++ b/cmd/flux/kustomization.go
@@ -19,7 +19,7 @@ package main
 import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 // kustomizev1.Kustomization
diff --git a/cmd/flux/kustomization_test.go b/cmd/flux/kustomization_test.go
index ca3b1c510706ea72d18ab27a8649ebd8dec142b7..275a061d6395015cc7b93d3f3ca91a295d17d210 100644
--- a/cmd/flux/kustomization_test.go
+++ b/cmd/flux/kustomization_test.go
@@ -14,7 +14,7 @@ func TestKustomizationFromGit(t *testing.T) {
 			"testdata/kustomization/create_source_git.golden",
 		},
 		{
-			"create kustomization tkfg --source=tkfg --path=./deploy/overlays/dev --prune=true --interval=5m --validation=client --health-check=Deployment/frontend.dev --health-check=Deployment/backend.dev --health-check-timeout=3m",
+			"create kustomization tkfg --source=tkfg --path=./deploy/overlays/dev --prune=true --interval=5m --health-check=Deployment/frontend.dev --health-check=Deployment/backend.dev --health-check-timeout=3m",
 			"testdata/kustomization/create_kustomization_from_git.golden",
 		},
 		{
diff --git a/cmd/flux/main.go b/cmd/flux/main.go
index 5bd8fa508a2c0eab70bf2f8561d138f13689d846..43a0f1abee324c82672a72a80b52f41ed365075f 100644
--- a/cmd/flux/main.go
+++ b/cmd/flux/main.go
@@ -43,7 +43,7 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.`,
   flux check --pre
 
   # Install the latest version of Flux
-  flux install --version=master
+  flux install
 
   # Create a source for a public Git repository
   flux create source git webapp-latest \
@@ -66,7 +66,6 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.`,
     --path="./deploy/webapp/" \
     --prune=true \
     --interval=5m \
-    --validation=client \
     --health-check="Deployment/backend.webapp" \
     --health-check="Deployment/frontend.webapp" \
     --health-check-timeout=2m
diff --git a/cmd/flux/reconcile_kustomization.go b/cmd/flux/reconcile_kustomization.go
index 48b7ec2ece223e584963e2b14fd4a22cd42cbbfc..fd8e3f8b167b019abd8793511007fa3a57f09845 100644
--- a/cmd/flux/reconcile_kustomization.go
+++ b/cmd/flux/reconcile_kustomization.go
@@ -20,7 +20,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 )
 
diff --git a/cmd/flux/resume_kustomization.go b/cmd/flux/resume_kustomization.go
index 78bc5e6645fffec34adb04b0a552eace5c532ac9..b1ac20728c8ceae60e032d3a5cda542db73c80a3 100644
--- a/cmd/flux/resume_kustomization.go
+++ b/cmd/flux/resume_kustomization.go
@@ -21,7 +21,7 @@ import (
 
 	"github.com/spf13/cobra"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 var resumeKsCmd = &cobra.Command{
diff --git a/cmd/flux/suspend_kustomization.go b/cmd/flux/suspend_kustomization.go
index 18d007644dc0c44c17adaacfaa822c00649a2e55..46d12276f77bbbb7a75d295b23770c8b29a5d8f6 100644
--- a/cmd/flux/suspend_kustomization.go
+++ b/cmd/flux/suspend_kustomization.go
@@ -19,7 +19,7 @@ package main
 import (
 	"github.com/spf13/cobra"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 )
 
 var suspendKsCmd = &cobra.Command{
diff --git a/cmd/flux/testdata/check/check_pre.golden b/cmd/flux/testdata/check/check_pre.golden
index 42b7acadeee07ebd5efebec4a076a1295006a36d..02ba78927fa9c4204ad47c149713174b683288e0 100644
--- a/cmd/flux/testdata/check/check_pre.golden
+++ b/cmd/flux/testdata/check/check_pre.golden
@@ -1,4 +1,3 @@
 ► checking prerequisites
-✔ kubectl {{ .clientVersion }} >=1.18.0-0
-✔ Kubernetes {{ .serverVersion }} >=1.16.0-0
+✔ Kubernetes {{ .serverVersion }} >=1.19.0-0
 ✔ prerequisites checks passed
diff --git a/cmd/flux/trace.go b/cmd/flux/trace.go
index 807cdaaf75cafe0a2d765f1685225d855a283b66..3b3b599de7497e0d397f6b6594ba30681f25f2b5 100644
--- a/cmd/flux/trace.go
+++ b/cmd/flux/trace.go
@@ -33,7 +33,7 @@ import (
 
 	"github.com/fluxcd/flux2/internal/utils"
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	fluxmeta "github.com/fluxcd/pkg/apis/meta"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 )
diff --git a/cmd/flux/uninstall.go b/cmd/flux/uninstall.go
index 2f559e699b017b1a9aa63dcd175719b097e45863..111e11195feb323e402139f9f8733a0230a4ace9 100644
--- a/cmd/flux/uninstall.go
+++ b/cmd/flux/uninstall.go
@@ -32,7 +32,7 @@ import (
 
 	"github.com/fluxcd/flux2/internal/utils"
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 )
 
diff --git a/go.mod b/go.mod
index 36b9003b7856a881ebfb73b6ee9922dc03f9979e..4dbe425489cfdca3063e2919bf3a6e2504571222 100644
--- a/go.mod
+++ b/go.mod
@@ -14,12 +14,13 @@ require (
 	github.com/fluxcd/notification-controller/api v0.17.0
 	github.com/fluxcd/pkg/apis/meta v0.10.0
 	github.com/fluxcd/pkg/runtime v0.12.0
+	github.com/fluxcd/pkg/ssa v0.0.1
 	github.com/fluxcd/pkg/ssh v0.0.5
 	github.com/fluxcd/pkg/untar v0.0.5
 	github.com/fluxcd/pkg/version v0.0.1
 	github.com/fluxcd/source-controller/api v0.16.0
 	github.com/go-git/go-git/v5 v5.4.2
-	github.com/google/go-cmp v0.5.5
+	github.com/google/go-cmp v0.5.6
 	github.com/google/go-containerregistry v0.2.0
 	github.com/manifoldco/promptui v0.7.0
 	github.com/mattn/go-shellwords v1.0.12
@@ -35,7 +36,7 @@ require (
 	sigs.k8s.io/cli-utils v0.25.1-0.20210608181808-f3974341173a
 	sigs.k8s.io/controller-runtime v0.10.1
 	sigs.k8s.io/kustomize/api v0.8.10
-	sigs.k8s.io/yaml v1.2.0
+	sigs.k8s.io/yaml v1.3.0
 )
 
 // drop LGPL dependency manifoldco/promptui -> juju/ansiterm
diff --git a/go.sum b/go.sum
index 1027aa93166de54482ce566631467142bb3e3c9e..55613654d7047a4ea36034fee5db90b090a0bc11 100644
--- a/go.sum
+++ b/go.sum
@@ -239,6 +239,8 @@ github.com/fluxcd/pkg/apis/meta v0.10.0 h1:N7wVGHC1cyPdT87hrDC7UwCwRwnZdQM46PBSL
 github.com/fluxcd/pkg/apis/meta v0.10.0/go.mod h1:CW9X9ijMTpNe7BwnokiUOrLl/h13miwVr/3abEQLbKE=
 github.com/fluxcd/pkg/runtime v0.12.0 h1:BPZZ8bBkimpqGAPXqOf3LTaw+tcw6HgbWyCuzbbsJGs=
 github.com/fluxcd/pkg/runtime v0.12.0/go.mod h1:EyaTR2TOYcjL5U//C4yH3bt2tvTgIOSXpVRbWxUn/C4=
+github.com/fluxcd/pkg/ssa v0.0.1 h1:XUMhPyziWC7JkRWFO/61lc/7Qu+/T1lCz2f7nvbO+vU=
+github.com/fluxcd/pkg/ssa v0.0.1/go.mod h1:QisgqnXXnHKNfdnrpJ3wQrwuto111mvdNcKkfe9Cwvk=
 github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
 github.com/fluxcd/pkg/ssh v0.0.5/go.mod h1:7jXPdXZpc0ttMNz2kD9QuMi3RNn/e0DOFbj0Tij/+Hs=
 github.com/fluxcd/pkg/untar v0.0.5 h1:UGI3Ch1UIEIaqQvMicmImL1s9npQa64DJ/ozqHKB7gk=
@@ -403,8 +405,9 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-containerregistry v0.2.0 h1:cWFYx+kOkKdyOET0pcp7GMCmxj7da40StvluSuSXWCg=
 github.com/google/go-containerregistry v0.2.0/go.mod h1:Ts3Wioz1r5ayWx8sS6vLcWltWcM1aqFjd/eVrkFhrWM=
 github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
@@ -1373,6 +1376,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
 sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
 sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go
index 91a9fa3c2f5a3cea1dfa9a3746a1fcf8cdc09d50..96f90490be1e17831b89dac7e1ab8c97c259ed63 100644
--- a/internal/bootstrap/bootstrap.go
+++ b/internal/bootstrap/bootstrap.go
@@ -30,7 +30,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	"github.com/fluxcd/pkg/apis/meta"
 
 	"github.com/fluxcd/flux2/pkg/manifestgen/install"
diff --git a/internal/bootstrap/bootstrap_plain_git.go b/internal/bootstrap/bootstrap_plain_git.go
index f7c25fe0942cfe8e449c448612e4d9d95280556c..ed7e09a53c5ca7f1dcaf68367118c97865afd9e4 100644
--- a/internal/bootstrap/bootstrap_plain_git.go
+++ b/internal/bootstrap/bootstrap_plain_git.go
@@ -33,7 +33,7 @@ import (
 	"sigs.k8s.io/kustomize/api/konfig"
 	"sigs.k8s.io/yaml"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 
 	"github.com/fluxcd/flux2/internal/bootstrap/git"
 	"github.com/fluxcd/flux2/internal/utils"
@@ -175,41 +175,14 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest
 		// Apply components using any existing customisations
 		kfile := filepath.Join(filepath.Dir(componentsYAML), konfig.DefaultKustomizationFileName())
 		if _, err := os.Stat(kfile); err == nil {
-			tmpDir, err := os.MkdirTemp("", "gotk-crds")
-			defer os.RemoveAll(tmpDir)
-
-			// Extract the CRDs from the components manifest
-			crdsYAML := filepath.Join(tmpDir, "gotk-crds.yaml")
-			if err := utils.ExtractCRDs(componentsYAML, crdsYAML); err != nil {
-				return err
-			}
-
-			// Apply the CRDs
-			b.logger.Actionf("installing toolkit.fluxcd.io CRDs")
-			kubectlArgs := []string{"apply", "-f", crdsYAML}
-			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil {
-				return err
-			}
-
-			// Wait for CRDs to be established
-			b.logger.Waitingf("waiting for CRDs to be reconciled")
-			kubectlArgs = []string{"wait", "--for", "condition=established", "-f", crdsYAML}
-			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil {
-				return err
-			}
-			b.logger.Successf("CRDs reconciled successfully")
-
 			// Apply the components and their patches
 			b.logger.Actionf("installing components in %q namespace", options.Namespace)
-			kubectlArgs = []string{"apply", "-k", filepath.Dir(componentsYAML)}
-			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil {
+			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, kfile); err != nil {
 				return err
 			}
 		} else {
 			// Apply the CRDs and controllers
-			b.logger.Actionf("installing components in %q namespace", options.Namespace)
-			kubectlArgs := []string{"apply", "-f", componentsYAML}
-			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil {
+			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, componentsYAML); err != nil {
 				return err
 			}
 		}
@@ -336,10 +309,10 @@ func (b *PlainGitBootstrapper) ReconcileSyncConfig(ctx context.Context, options
 
 	// Apply to cluster
 	b.logger.Actionf("applying sync manifests")
-	kubectlArgs := []string{"apply", "-k", filepath.Join(b.git.Path(), filepath.Dir(kusManifests.Path))}
-	if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil {
+	if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, filepath.Join(b.git.Path(), kusManifests.Path)); err != nil {
 		return err
 	}
+
 	b.logger.Successf("reconciled sync configuration")
 
 	return nil
diff --git a/internal/utils/apply.go b/internal/utils/apply.go
new file mode 100644
index 0000000000000000000000000000000000000000..bc1f6de2c8bd15c7fae3706bdcdb47717fed6fce
--- /dev/null
+++ b/internal/utils/apply.go
@@ -0,0 +1,81 @@
+package utils
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"fmt"
+	"os"
+	"path/filepath"
+	"time"
+
+	"github.com/fluxcd/pkg/ssa"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"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"
+)
+
+// 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)
+	if err != nil {
+		return "", err
+	}
+	restMapper, err := apiutil.NewDynamicRESTMapper(cfg)
+	if err != nil {
+		return "", err
+	}
+	kubeClient, err := client.New(cfg, client.Options{Mapper: restMapper})
+	if err != nil {
+		return "", err
+	}
+	kubePoller := polling.NewStatusPoller(kubeClient, restMapper)
+
+	resourceManager := ssa.NewResourceManager(kubeClient, kubePoller, ssa.Owner{
+		Field: "flux",
+		Group: "fluxcd.io",
+	})
+
+	objs, err := readObjects(manifestPath)
+	if err != nil {
+		return "", err
+	}
+
+	if len(objs) < 1 {
+		return "", fmt.Errorf("no Kubernetes objects found at: %s", manifestPath)
+	}
+
+	changeSet, err := resourceManager.ApplyAllStaged(ctx, objs, false, time.Minute)
+	if err != nil {
+		return "", err
+	}
+
+	return changeSet.String(), nil
+}
+
+func readObjects(manifestPath string) ([]*unstructured.Unstructured, error) {
+	if _, err := os.Stat(manifestPath); err != nil {
+		return nil, err
+	}
+
+	if filepath.Base(manifestPath) == konfig.DefaultKustomizationFileName() {
+		resources, err := kustomization.Build(filepath.Dir(manifestPath))
+		if err != nil {
+			return nil, err
+		}
+		return ssa.ReadObjects(bytes.NewReader(resources))
+	}
+
+	ms, err := os.Open(manifestPath)
+	if err != nil {
+		return nil, err
+	}
+	defer ms.Close()
+
+	return ssa.ReadObjects(bufio.NewReader(ms))
+}
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index 1181cc0b582cf60aa522848a4864565366029a3b..963b88e22452542de176d10f2ccf25feab33a2f3 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -45,7 +45,7 @@ import (
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
 	imageautov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
 	imagereflectv1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/runtime/dependency"
 	"github.com/fluxcd/pkg/version"
diff --git a/pkg/manifestgen/install/manifests.go b/pkg/manifestgen/install/manifests.go
index a864d8c9b134158bed1521e82fafaf37a0219a40..908eeec14896431dd515230d0bac5a3ec8fe8d41 100644
--- a/pkg/manifestgen/install/manifests.go
+++ b/pkg/manifestgen/install/manifests.go
@@ -25,13 +25,11 @@ import (
 	"path"
 	"path/filepath"
 	"strings"
-	"sync"
 
+	"github.com/fluxcd/pkg/untar"
 	"sigs.k8s.io/kustomize/api/filesys"
-	"sigs.k8s.io/kustomize/api/krusty"
-	kustypes "sigs.k8s.io/kustomize/api/types"
 
-	"github.com/fluxcd/pkg/untar"
+	"github.com/fluxcd/flux2/pkg/manifestgen/kustomization"
 )
 
 func fetch(ctx context.Context, url, version, dir string) error {
@@ -114,56 +112,13 @@ func generate(base string, options Options) error {
 	return nil
 }
 
-var kustomizeBuildMutex sync.Mutex
-
 func build(base, output string) error {
-	// TODO(stefan): temporary workaround for concurrent map read and map write bug
-	// https://github.com/kubernetes-sigs/kustomize/issues/3659
-	kustomizeBuildMutex.Lock()
-	defer kustomizeBuildMutex.Unlock()
-
-	kfile := filepath.Join(base, "kustomization.yaml")
-
-	fs := filesys.MakeFsOnDisk()
-	if !fs.Exists(kfile) {
-		return fmt.Errorf("%s not found", kfile)
-	}
-
-	// TODO(hidde): work around for a bug in kustomize causing it to
-	//  not properly handle absolute paths on Windows.
-	//  Convert the path to a relative path to the working directory
-	//  as a temporary fix:
-	//  https://github.com/kubernetes-sigs/kustomize/issues/2789
-	if filepath.IsAbs(base) {
-		wd, err := os.Getwd()
-		if err != nil {
-			return err
-		}
-		base, err = filepath.Rel(wd, base)
-		if err != nil {
-			return err
-		}
-	}
-
-	buildOptions := &krusty.Options{
-		DoLegacyResourceSort: true,
-		LoadRestrictions:     kustypes.LoadRestrictionsNone,
-		AddManagedbyLabel:    false,
-		DoPrune:              false,
-		PluginConfig:         kustypes.DisabledPluginConfig(),
-	}
-
-	k := krusty.MakeKustomizer(buildOptions)
-	m, err := k.Run(fs, base)
-	if err != nil {
-		return err
-	}
-
-	resources, err := m.AsYaml()
+	resources, err := kustomization.Build(base)
 	if err != nil {
 		return err
 	}
 
+	fs := filesys.MakeFsOnDisk()
 	if err := fs.WriteFile(output, resources); err != nil {
 		return err
 	}
diff --git a/pkg/manifestgen/kustomization/kustomization.go b/pkg/manifestgen/kustomization/kustomization.go
index bdce9fb237f986967409b1ffa238439c872013e6..676f64b707cd7218c92d171419d96dd058b7bbba 100644
--- a/pkg/manifestgen/kustomization/kustomization.go
+++ b/pkg/manifestgen/kustomization/kustomization.go
@@ -17,10 +17,14 @@ limitations under the License.
 package kustomization
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
+	"sync"
 
+	"sigs.k8s.io/kustomize/api/filesys"
 	"sigs.k8s.io/kustomize/api/konfig"
+	"sigs.k8s.io/kustomize/api/krusty"
 	"sigs.k8s.io/kustomize/api/provider"
 	kustypes "sigs.k8s.io/kustomize/api/types"
 	"sigs.k8s.io/yaml"
@@ -28,6 +32,8 @@ import (
 	"github.com/fluxcd/flux2/pkg/manifestgen"
 )
 
+// Generate scans the given directory for Kubernetes manifests and creates a kustomization.yaml
+// including all discovered manifests as resources.
 func Generate(options Options) (*manifestgen.Manifest, error) {
 	kfile := filepath.Join(options.TargetPath, konfig.DefaultKustomizationFileName())
 	abskfile := filepath.Join(options.BaseDir, kfile)
@@ -121,3 +127,57 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
 		Content: string(kd),
 	}, nil
 }
+
+var kustomizeBuildMutex sync.Mutex
+
+// Build takes a Kustomize overlays and returns the resulting manifests as multi-doc YAML.
+func Build(base string) ([]byte, error) {
+	// TODO(stefan): temporary workaround for concurrent map read and map write bug
+	// https://github.com/kubernetes-sigs/kustomize/issues/3659
+	kustomizeBuildMutex.Lock()
+	defer kustomizeBuildMutex.Unlock()
+
+	kfile := filepath.Join(base, konfig.DefaultKustomizationFileName())
+
+	fs := filesys.MakeFsOnDisk()
+	if !fs.Exists(kfile) {
+		return nil, fmt.Errorf("%s not found", kfile)
+	}
+
+	// TODO(hidde): work around for a bug in kustomize causing it to
+	//  not properly handle absolute paths on Windows.
+	//  Convert the path to a relative path to the working directory
+	//  as a temporary fix:
+	//  https://github.com/kubernetes-sigs/kustomize/issues/2789
+	if filepath.IsAbs(base) {
+		wd, err := os.Getwd()
+		if err != nil {
+			return nil, err
+		}
+		base, err = filepath.Rel(wd, base)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	buildOptions := &krusty.Options{
+		DoLegacyResourceSort: true,
+		LoadRestrictions:     kustypes.LoadRestrictionsNone,
+		AddManagedbyLabel:    false,
+		DoPrune:              false,
+		PluginConfig:         kustypes.DisabledPluginConfig(),
+	}
+
+	k := krusty.MakeKustomizer(buildOptions)
+	m, err := k.Run(fs, base)
+	if err != nil {
+		return nil, err
+	}
+
+	resources, err := m.AsYaml()
+	if err != nil {
+		return nil, err
+	}
+
+	return resources, nil
+}
diff --git a/pkg/manifestgen/sync/sync.go b/pkg/manifestgen/sync/sync.go
index 665cae16bb401db533bd474bfe78a8e8c457fa51..ddddbf894da004f615414905ad04b6595c226773 100644
--- a/pkg/manifestgen/sync/sync.go
+++ b/pkg/manifestgen/sync/sync.go
@@ -26,7 +26,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/yaml"
 
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	"github.com/fluxcd/pkg/apis/meta"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 
@@ -97,7 +97,6 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
 				Kind: sourcev1.GitRepositoryKind,
 				Name: options.Name,
 			},
-			Validation: "client",
 		},
 	}
 
diff --git a/pkg/manifestgen/sync/sync_test.go b/pkg/manifestgen/sync/sync_test.go
index 732442af51fdf3c13aa86f2689d3ebd1c4566650..175cb13394cd39e6d1fe21b0c903706be26f804f 100644
--- a/pkg/manifestgen/sync/sync_test.go
+++ b/pkg/manifestgen/sync/sync_test.go
@@ -20,10 +20,11 @@ package sync
 
 import (
 	"fmt"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
-	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 	"strings"
 	"testing"
+
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
+	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 )
 
 func TestGenerate(t *testing.T) {
diff --git a/tests/azure/README.md b/tests/azure/README.md
index ccc3496dee9a843b06050a4803a868f9b49214f5..80f99382ddc67b34a2334d8037332016ad721b85 100644
--- a/tests/azure/README.md
+++ b/tests/azure/README.md
@@ -30,14 +30,14 @@ Terraform instead of requiring it to be implemented in the test.
 
 The following tests are currently implemented:
 
-[x] Flux can be successfully installed on AKS using the CLI e.g.:
-[x] source-controller can clone Azure DevOps repositories (https+ssh)
-[x] image-reflector-controller can list tags from Azure Container Registry image repositories
-[x] kustomize-controller can decrypt secrets using SOPS and Azure Key Vault
-[x] image-automation-controller can create branches and push to Azure DevOps repositories (https+ssh)
-[x] notification-controller can send commit status to Azure DevOps
-[x] notification-controller can forward events to Azure Event Hub
-[x] source-controller can pull charts from Azure Container Registry Helm repositories
+- [x] Flux can be successfully installed on AKS using the CLI e.g.:
+- [x] source-controller can clone Azure DevOps repositories (https+ssh)
+- [x] image-reflector-controller can list tags from Azure Container Registry image repositories
+- [x] kustomize-controller can decrypt secrets using SOPS and Azure Key Vault
+- [x] image-automation-controller can create branches and push to Azure DevOps repositories (https+ssh)
+- [x] notification-controller can send commit status to Azure DevOps
+- [x] notification-controller can forward events to Azure Event Hub
+- [x] source-controller can pull charts from Azure Container Registry Helm repositories
 
 ## Give User Access
 
diff --git a/tests/azure/azure_test.go b/tests/azure/azure_test.go
index 1b304faab757245dbac3fa50011f9d0fc1096e01..6b564d503d9d944eea75dbdfa705f8d64ba3047a 100644
--- a/tests/azure/azure_test.go
+++ b/tests/azure/azure_test.go
@@ -30,7 +30,7 @@ import (
 
 	automationv1beta1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
 	reflectorv1beta1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	notiv1beta1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
 	"github.com/fluxcd/pkg/runtime/events"
diff --git a/tests/azure/go.mod b/tests/azure/go.mod
index 9f3f937f1fe4393bc5c85abdff17175396698cc1..3275cb7b6792764a8ba73e1e6e0f0554ed1a7e1e 100644
--- a/tests/azure/go.mod
+++ b/tests/azure/go.mod
@@ -4,14 +4,14 @@ go 1.16
 
 require (
 	github.com/Azure/azure-event-hubs-go/v3 v3.3.13
-	github.com/fluxcd/helm-controller/api v0.11.2
-	github.com/fluxcd/image-automation-controller/api v0.14.1
+	github.com/fluxcd/helm-controller/api v0.12.0
+	github.com/fluxcd/image-automation-controller/api v0.15.0
 	github.com/fluxcd/image-reflector-controller/api v0.12.0
-	github.com/fluxcd/kustomize-controller/api v0.14.1
-	github.com/fluxcd/notification-controller/api v0.16.0
+	github.com/fluxcd/kustomize-controller/api v0.15.1
+	github.com/fluxcd/notification-controller/api v0.17.0
 	github.com/fluxcd/pkg/apis/meta v0.10.1
 	github.com/fluxcd/pkg/runtime v0.12.1
-	github.com/fluxcd/source-controller/api v0.15.4
+	github.com/fluxcd/source-controller/api v0.16.0
 	github.com/hashicorp/terraform-exec v0.14.0
 	github.com/libgit2/git2go/v31 v31.6.1
 	github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
diff --git a/tests/azure/go.sum b/tests/azure/go.sum
index 7c62849a472952e20e9b100686872129443d63f9..fa98a1f74de9b13e22ad73b3eb47c70be6421d47 100644
--- a/tests/azure/go.sum
+++ b/tests/azure/go.sum
@@ -191,16 +191,16 @@ github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWc
 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/fluxcd/helm-controller/api v0.11.2 h1:IpzGEexjEa9DttikHF40kHFORhsxAeD2Z6SN6BZBA6o=
-github.com/fluxcd/helm-controller/api v0.11.2/go.mod h1:gLPpLa8NMQJ+b4pwP/sExAPkGdFWO1CKIh1Uu82O2gM=
-github.com/fluxcd/image-automation-controller/api v0.14.1 h1:8EDUs61Gi5HgSA9ou0rgFuDgvag+wpTrndizFhCGYwY=
-github.com/fluxcd/image-automation-controller/api v0.14.1/go.mod h1:22GZblh0CmaZItQpvCBe40i5ql/oCZllpLqkGmoglEQ=
+github.com/fluxcd/helm-controller/api v0.12.0 h1:68GKGZ5dHvOt4rx6gwQaOGliUksv7F/q8JQo2c0Tcis=
+github.com/fluxcd/helm-controller/api v0.12.0/go.mod h1:zWmzV0s2SU4rEIGLPTt+dsaMs40OsNQgSgOATgJmxB0=
+github.com/fluxcd/image-automation-controller/api v0.15.0 h1:KI350vt5JahE43D17VyLZFH4ZxtbnyHrekAd8AJsT5E=
+github.com/fluxcd/image-automation-controller/api v0.15.0/go.mod h1:XvrEEpM1rVU+x1gQeXB/dj56w1dmOJRraTxQWOiuNME=
 github.com/fluxcd/image-reflector-controller/api v0.12.0 h1:ghdbOUmbNaPi/jVfNnI3xzvhudXBZx6xUld/OLNSVXM=
 github.com/fluxcd/image-reflector-controller/api v0.12.0/go.mod h1:lgQHGFz29OHmDU5Jwg689C/M+P/f9ujt6NS0zCLT0BQ=
-github.com/fluxcd/kustomize-controller/api v0.14.1 h1:OsErJQ3U3ReYTAtkeFo1t8UW4sjISF0a+6wsz942MT0=
-github.com/fluxcd/kustomize-controller/api v0.14.1/go.mod h1:3RNiEd/XnYjSTGzMqDzDbQkOYpdPFrKuS+XdgWt9pds=
-github.com/fluxcd/notification-controller/api v0.16.0 h1:3vaIj3AJRUA4dsfISuok8URV1RUmoe9NFpCAZ+tjOeU=
-github.com/fluxcd/notification-controller/api v0.16.0/go.mod h1:t28GMWMLiLqho+ikpZrldv22/vmCsFdQR8vdJluxknc=
+github.com/fluxcd/kustomize-controller/api v0.15.1 h1:xyMta7ICzoSKNkRWejH2sflo3dF7umP6To74+3NhdTk=
+github.com/fluxcd/kustomize-controller/api v0.15.1/go.mod h1:OhnZuXBeDl4NqbDZgpYKRg8nmsmeUIddH3vX8wxym9A=
+github.com/fluxcd/notification-controller/api v0.17.0 h1:HrTX6EThmvbW3I+uKJyaggcNnRsLxogc6q7A3nXZ9tQ=
+github.com/fluxcd/notification-controller/api v0.17.0/go.mod h1:t28GMWMLiLqho+ikpZrldv22/vmCsFdQR8vdJluxknc=
 github.com/fluxcd/pkg/apis/kustomize v0.1.0/go.mod h1:gEl+W5cVykCC3RfrCaqe+Pz+j4lKl2aeR4dxsom/zII=
 github.com/fluxcd/pkg/apis/kustomize v0.2.0 h1:jhu2QHvs+j3Zo9rR6w8hkO3LSC6h3M37zY5ejufOmxY=
 github.com/fluxcd/pkg/apis/kustomize v0.2.0/go.mod h1:gEl+W5cVykCC3RfrCaqe+Pz+j4lKl2aeR4dxsom/zII=
@@ -210,8 +210,8 @@ github.com/fluxcd/pkg/apis/meta v0.10.1/go.mod h1:yUblM2vg+X8TE3A2VvJfdhkGmg+uqB
 github.com/fluxcd/pkg/runtime v0.12.0/go.mod h1:EyaTR2TOYcjL5U//C4yH3bt2tvTgIOSXpVRbWxUn/C4=
 github.com/fluxcd/pkg/runtime v0.12.1 h1:r0KQG80gKY1NMp62FggSEdFBV60ZfbnA2RHL9y06DOY=
 github.com/fluxcd/pkg/runtime v0.12.1/go.mod h1:9czAjokV0w22eYGR9/SQKUHXhvh7ISNVgc/6a6YMBE8=
-github.com/fluxcd/source-controller/api v0.15.4 h1:9aRcH/WKJWt7Bp954K/wzLRuiRiHuD2osvYp74GoP64=
-github.com/fluxcd/source-controller/api v0.15.4/go.mod h1:guUCCapjzE2kocwFreQTM/IGvtAglIJc4L97mokairo=
+github.com/fluxcd/source-controller/api v0.16.0 h1:xFz+K7lLg/82uOQp+a0g04GsgoWNfyzwXAoVQy4T/oI=
+github.com/fluxcd/source-controller/api v0.16.0/go.mod h1:guUCCapjzE2kocwFreQTM/IGvtAglIJc4L97mokairo=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
@@ -1023,34 +1023,41 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
 k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
 k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
 k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
+k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
 k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw=
 k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
 k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA=
 k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
 k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
+k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
 k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4=
 k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
 k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
 k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
 k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
+k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
 k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk=
 k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
 k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY=
 k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw=
 k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
+k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
 k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
 k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
 k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
 k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
+k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
 k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc=
 k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
 k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q=
 k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U=
 k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
+k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
 k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
 k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA=
 k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
 k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
+k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
 k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
 k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
 k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
@@ -1064,6 +1071,7 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ
 k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
 k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g=
 k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
diff --git a/tests/azure/util_test.go b/tests/azure/util_test.go
index 9b54e3ae22ede091ddaae85e940d16d1f19f1bc0..769d4c4e73a59a75383cc10459c7bb6065c2c992 100644
--- a/tests/azure/util_test.go
+++ b/tests/azure/util_test.go
@@ -23,7 +23,7 @@ import (
 	helmv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
 	automationv1beta1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
 	reflectorv1beta1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
-	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
 	notiv1beta1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"