diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index f3ede26c..4d3e60b4 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -80,6 +80,8 @@ jobs:
         run: |
           kubectl -n impersonation apply -f ./config/testdata/impersonation
           kubectl -n impersonation wait kustomizations/podinfo --for=condition=ready --timeout=4m
+          kubectl -n impersonation delete kustomizations/podinfo
+          until kubectl -n impersonation get deploy/podinfo 2>&1 | grep NotFound ; do sleep 2; done
       - name: Run image overide tests
         run: |
           kubectl -n override-test apply -f ./config/testdata/overrides
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index 2323bde3..8084ff74 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -13,6 +13,15 @@ rules:
   verbs:
   - create
   - patch
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  - serviceaccounts
+  verbs:
+  - get
+  - list
+  - watch
 - apiGroups:
   - kustomize.toolkit.fluxcd.io
   resources:
diff --git a/controllers/kustomization_controller.go b/controllers/kustomization_controller.go
index 4327c7ee..eae1846b 100644
--- a/controllers/kustomization_controller.go
+++ b/controllers/kustomization_controller.go
@@ -65,6 +65,7 @@ import (
 // +kubebuilder:rbac:groups=kustomize.toolkit.fluxcd.io,resources=kustomizations/finalizers,verbs=get;create;update;patch;delete
 // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=buckets;gitrepositories,verbs=get;list;watch
 // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=buckets/status;gitrepositories/status,verbs=get
+// +kubebuilder:rbac:groups="",resources=secrets;serviceaccounts,verbs=get;list;watch
 // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
 
 // KustomizationReconciler reconciles a Kustomization object
diff --git a/controllers/kustomization_impersonation.go b/controllers/kustomization_impersonation.go
index 00b826b5..63fc2018 100644
--- a/controllers/kustomization_impersonation.go
+++ b/controllers/kustomization_impersonation.go
@@ -28,6 +28,7 @@ import (
 	"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/controller-runtime/pkg/client/config"
 
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 )
@@ -92,12 +93,49 @@ func (ki *KustomizeImpersonation) GetServiceAccountToken(ctx context.Context) (s
 	return token, nil
 }
 
+// GetClient creates a controller-runtime client for talking to a Kubernetes API server.
+// If KubeConfig is set, will use the kubeconfig bytes from the Kubernetes secret.
+// If ServiceAccountName is set, will use the cluster provided kubeconfig impersonating the SA.
+// If --kubeconfig is set, will use the kubeconfig file at that location.
+// Otherwise will assume running in cluster and use the cluster provided kubeconfig.
 func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client, *polling.StatusPoller, error) {
 	if ki.kustomization.Spec.KubeConfig == nil {
-		// TODO: implement impersonation overrides for in-cluster
+		if ki.kustomization.Spec.ServiceAccountName != "" {
+			return ki.clientForServiceAccount(ctx)
+		}
+
 		return ki.Client, ki.statusPoller, nil
 	}
+	return ki.clientForKubeConfig(ctx)
+}
+
+func (ki *KustomizeImpersonation) clientForServiceAccount(ctx context.Context) (client.Client, *polling.StatusPoller, error) {
+	token, err := ki.GetServiceAccountToken(ctx)
+	if err != nil {
+		return nil, nil, err
+	}
+	restConfig, err := config.GetConfig()
+	if err != nil {
+		return nil, nil, err
+	}
+	restConfig.BearerToken = token
+
+	restMapper, err := apiutil.NewDynamicRESTMapper(restConfig)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	client, err := client.New(restConfig, client.Options{Mapper: restMapper})
+	if err != nil {
+		return nil, nil, err
+	}
 
+	statusPoller := polling.NewStatusPoller(client, restMapper)
+	return client, statusPoller, err
+
+}
+
+func (ki *KustomizeImpersonation) clientForKubeConfig(ctx context.Context) (client.Client, *polling.StatusPoller, error) {
 	kubeConfigBytes, err := ki.getKubeConfig(ctx)
 	if err != nil {
 		return nil, nil, err
@@ -108,15 +146,11 @@ func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client,
 		return nil, nil, err
 	}
 
-	// TODO: implement impersonation overrides on the target cluster restConfig
-
 	restMapper, err := apiutil.NewDynamicRESTMapper(restConfig)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	// this client does not have a cache like the normal controller-runtime default client
-	// this is intentional but one could be added
 	client, err := client.New(restConfig, client.Options{Mapper: restMapper})
 	if err != nil {
 		return nil, nil, err