diff --git a/pkg/api/v1alpha1/clusterctl_types.go b/pkg/api/v1alpha1/clusterctl_types.go
index e5a283dde..277bafc10 100644
--- a/pkg/api/v1alpha1/clusterctl_types.go
+++ b/pkg/api/v1alpha1/clusterctl_types.go
@@ -15,6 +15,7 @@
 package v1alpha1
 
 import (
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 )
@@ -27,6 +28,7 @@ type Clusterctl struct {
 	metav1.ObjectMeta `json:"metadata,omitempty"`
 
 	Providers   []*Provider  `json:"providers,omitempty"`
+	Action      ActionType   `json:"action,omitempty"`
 	InitOptions *InitOptions `json:"init-options,omitempty"`
 	MoveOptions *MoveOptions `json:"move-options,omitempty"`
 	// AdditionalComponentVariables are variables that will be available to clusterctl
@@ -73,8 +75,20 @@ type InitOptions struct {
 	// ControlPlaneProviders and versions (e.g. kubeadm:v0.3.0) to add to the management cluster.
 	// If unspecified, the kubeadm control plane provider latest release is used.
 	ControlPlaneProviders []string `json:"control-plane-providers,omitempty"`
+
+	// KubeConfigRef reference to KubeConfig document
+	KubeConfigRef *corev1.ObjectReference `json:"kubeConfigRef,omitempty"`
 }
 
+// ActionType for clusterctl
+type ActionType string
+
+// List of possible clusterctl actions
+const (
+	Init ActionType = "init"
+	Move ActionType = "move"
+)
+
 // Provider returns provider filtering by name and type
 func (c *Clusterctl) Provider(name string, providerType clusterctlv1.ProviderType) *Provider {
 	t := string(providerType)
diff --git a/pkg/api/v1alpha1/zz_generated.deepcopy.go b/pkg/api/v1alpha1/zz_generated.deepcopy.go
index 20d9997a2..8b1fa438d 100644
--- a/pkg/api/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/api/v1alpha1/zz_generated.deepcopy.go
@@ -73,6 +73,11 @@ func (in *InitOptions) DeepCopyInto(out *InitOptions) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.KubeConfigRef != nil {
+		in, out := &in.KubeConfigRef, &out.KubeConfigRef
+		*out = new(v1.ObjectReference)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InitOptions.
diff --git a/pkg/clusterctl/client/errors.go b/pkg/clusterctl/client/errors.go
index ccd6d7431..7eafc0752 100644
--- a/pkg/clusterctl/client/errors.go
+++ b/pkg/clusterctl/client/errors.go
@@ -36,3 +36,13 @@ type ErrProviderRepoNotFound struct {
 func (e ErrProviderRepoNotFound) Error() string {
 	return fmt.Sprintf("failed to find repository for provider %s of type %s", e.ProviderName, e.ProviderType)
 }
+
+// ErrUnknownExecutorAction is returned for unknown action parameter
+// in clusterctl configuration document
+type ErrUnknownExecutorAction struct {
+	Action string
+}
+
+func (e ErrUnknownExecutorAction) Error() string {
+	return fmt.Sprintf("unknown action type '%s'", e.Action)
+}
diff --git a/pkg/clusterctl/client/executor.go b/pkg/clusterctl/client/executor.go
new file mode 100644
index 000000000..695f6e6d5
--- /dev/null
+++ b/pkg/clusterctl/client/executor.go
@@ -0,0 +1,146 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package client
+
+import (
+	"io"
+	"path/filepath"
+
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
+	airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
+	"opendev.org/airship/airshipctl/pkg/document"
+	"opendev.org/airship/airshipctl/pkg/errors"
+	"opendev.org/airship/airshipctl/pkg/events"
+	"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
+	"opendev.org/airship/airshipctl/pkg/log"
+	"opendev.org/airship/airshipctl/pkg/phase/ifc"
+)
+
+var _ ifc.Executor = &ClusterctlExecutor{}
+
+// ClusterctlExecutor phase executor
+type ClusterctlExecutor struct {
+	Interface
+	bundle   document.Bundle
+	options  *airshipv1.Clusterctl
+	kubecfg  kubeconfig.Interface
+	dumpRoot string
+}
+
+// RegisterExecutor adds executor to phase executor registry
+func RegisterExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFactory) error {
+	obj := &airshipv1.Clusterctl{}
+	gvks, _, err := airshipv1.Scheme.ObjectKinds(obj)
+	if err != nil {
+		return err
+	}
+	registry[gvks[0]] = NewExecutor
+	return nil
+}
+
+// NewExecutor creates instance of 'clusterctl init' phase executor
+func NewExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) {
+	options := &airshipv1.Clusterctl{}
+	if err := cfg.ExecutorDocument.ToAPIObject(options, airshipv1.Scheme); err != nil {
+		return nil, err
+	}
+	tgtPath, err := cfg.AirshipSettings.Config.CurrentContextTargetPath()
+	if err != nil {
+		return nil, err
+	}
+	client, err := NewClient(tgtPath, cfg.AirshipSettings.Debug, options)
+	if err != nil {
+		return nil, err
+	}
+	return &ClusterctlExecutor{
+		Interface: client,
+		bundle:    cfg.ExecutorBundle,
+		options:   options,
+		kubecfg:   cfg.KubeConfig,
+		dumpRoot:  filepath.Dir(cfg.AirshipSettings.AirshipConfigPath),
+	}, nil
+}
+
+// Run clusterctl init as a phase runner
+func (c *ClusterctlExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
+	defer close(evtCh)
+	switch c.options.Action {
+	case airshipv1.Move:
+		c.move(opts, evtCh)
+	case airshipv1.Init:
+		c.init(opts, evtCh)
+	default:
+		c.handleErr(ErrUnknownExecutorAction{Action: string(c.options.Action)}, evtCh)
+	}
+}
+
+func (c *ClusterctlExecutor) move(_ ifc.RunOptions, evtCh chan events.Event) {
+	c.handleErr(errors.ErrNotImplemented{}, evtCh)
+}
+
+func (c *ClusterctlExecutor) init(opts ifc.RunOptions, evtCh chan events.Event) {
+	evtCh <- events.Event{
+		ClusterctlEvent: events.ClusterctlEvent{
+			Operation: events.ClusterctlInitStart,
+		},
+	}
+	kubeConfigFile, cleanup, err := c.kubecfg.WriteTempFile(c.dumpRoot)
+	if err != nil {
+		c.handleErr(err, evtCh)
+		return
+	}
+
+	defer cleanup()
+
+	if opts.DryRun {
+		// TODO (dukov) add more details to dry-run
+		log.Print("command 'clusterctl init' is going to be executed")
+		evtCh <- events.Event{
+			ClusterctlEvent: events.ClusterctlEvent{
+				Operation: events.ClusterctlInitEnd,
+			},
+		}
+		return
+	}
+	err = c.Init(kubeConfigFile, "")
+	if err != nil {
+		c.handleErr(err, evtCh)
+	}
+	evtCh <- events.Event{
+		ClusterctlEvent: events.ClusterctlEvent{
+			Operation: events.ClusterctlInitEnd,
+		},
+	}
+}
+
+func (c *ClusterctlExecutor) handleErr(err error, evtCh chan events.Event) {
+	evtCh <- events.Event{
+		Type: events.ErrorType,
+		ErrorEvent: events.ErrorEvent{
+			Error: err,
+		},
+	}
+}
+
+// Validate executor configuration and documents
+func (c *ClusterctlExecutor) Validate() error {
+	return errors.ErrNotImplemented{}
+}
+
+// Render executor documents
+func (c *ClusterctlExecutor) Render(_ io.Writer, _ ifc.RenderOptions) error {
+	return errors.ErrNotImplemented{}
+}
diff --git a/pkg/clusterctl/client/executor_test.go b/pkg/clusterctl/client/executor_test.go
new file mode 100644
index 000000000..064754836
--- /dev/null
+++ b/pkg/clusterctl/client/executor_test.go
@@ -0,0 +1,262 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package client_test
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
+	cctlclient "opendev.org/airship/airshipctl/pkg/clusterctl/client"
+	"opendev.org/airship/airshipctl/pkg/config"
+	"opendev.org/airship/airshipctl/pkg/document"
+	"opendev.org/airship/airshipctl/pkg/environment"
+	airerrors "opendev.org/airship/airshipctl/pkg/errors"
+	"opendev.org/airship/airshipctl/pkg/events"
+	"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
+	"opendev.org/airship/airshipctl/pkg/phase/ifc"
+	"opendev.org/airship/airshipctl/testutil/fs"
+)
+
+var (
+	executorConfigTmpl = `
+apiVersion: airshipit.org/v1alpha1
+kind: Clusterctl
+metadata:
+  name: clusterctl-v1
+action: %s
+init-options:
+  core-provider: "cluster-api:v0.3.3"
+  kubeConfigRef:
+    apiVersion: airshipit.org/v1alpha1
+    kind: KubeConfig
+    name: sample-name
+providers:
+  - name: "cluster-api"
+    type: "CoreProvider"
+    versions:
+      v0.3.3: manifests/function/capi/v0.3.3`
+)
+
+func TestRegisterExecutor(t *testing.T) {
+	registry := make(map[schema.GroupVersionKind]ifc.ExecutorFactory)
+	expectedGVK := schema.GroupVersionKind{
+		Group:   "airshipit.org",
+		Version: "v1alpha1",
+		Kind:    "Clusterctl",
+	}
+	err := cctlclient.RegisterExecutor(registry)
+	require.NoError(t, err)
+
+	_, found := registry[expectedGVK]
+	assert.True(t, found)
+}
+
+func TestNewExecutor(t *testing.T) {
+	sampleCfgDoc := executorDoc(t, "init")
+	bundle, err := document.NewBundleByPath("testdata/executor_init")
+	require.NoError(t, err)
+
+	testCases := []struct {
+		name        string
+		settings    *environment.AirshipCTLSettings
+		expectedErr error
+	}{
+		{
+			name:     "New Clusterctl Executor",
+			settings: sampleSettings(),
+		},
+		{
+			name: "New Clusterctl Executor",
+			settings: func() *environment.AirshipCTLSettings {
+				s := sampleSettings()
+				s.Config.CurrentContext = "non-existent-ctx"
+				return s
+			}(),
+			expectedErr: config.ErrMissingConfig{What: "Context with name 'non-existent-ctx'"},
+		},
+	}
+	for _, test := range testCases {
+		tt := test
+		t.Run(tt.name, func(t *testing.T) {
+			_, actualErr := cctlclient.NewExecutor(ifc.ExecutorConfig{
+				ExecutorDocument: sampleCfgDoc,
+				ExecutorBundle:   bundle,
+				AirshipSettings:  tt.settings,
+			})
+			assert.Equal(t, tt.expectedErr, actualErr)
+		})
+	}
+	require.NoError(t, err)
+}
+
+func TestExecutorRun(t *testing.T) {
+	errTmpFile := errors.New("TmpFile error")
+
+	testCases := []struct {
+		name        string
+		cfgDoc      document.Document
+		fs          document.FileSystem
+		bundlePath  string
+		expectedEvt []events.Event
+	}{
+		{
+			name:       "Error unknown action",
+			cfgDoc:     executorDoc(t, "someAction"),
+			bundlePath: "testdata/executor_init",
+			expectedEvt: []events.Event{
+				wrapError(cctlclient.ErrUnknownExecutorAction{Action: "someAction"}),
+			},
+		},
+		{
+			name:   "Error temporary file",
+			cfgDoc: executorDoc(t, "init"),
+			fs: fs.MockFileSystem{
+				MockTempFile: func(string, string) (document.File, error) {
+					return nil, errTmpFile
+				},
+			},
+			bundlePath: "testdata/executor_init",
+			expectedEvt: []events.Event{
+				{
+					ClusterctlEvent: events.ClusterctlEvent{
+						Operation: events.ClusterctlInitStart,
+					},
+				},
+				wrapError(errTmpFile),
+			},
+		},
+		{
+			name:   "Regular Run init",
+			cfgDoc: executorDoc(t, "init"),
+			fs: fs.MockFileSystem{
+				MockTempFile: func(string, string) (document.File, error) {
+					return fs.TestFile{
+						MockName:  func() string { return "filename" },
+						MockWrite: func() (int, error) { return 0, nil },
+						MockClose: func() error { return nil },
+					}, nil
+				},
+				MockRemoveAll: func() error { return nil },
+			},
+			bundlePath: "testdata/executor_init",
+			expectedEvt: []events.Event{
+				{
+					ClusterctlEvent: events.ClusterctlEvent{
+						Operation: events.ClusterctlInitStart,
+					},
+				},
+				{
+					ClusterctlEvent: events.ClusterctlEvent{
+						Operation: events.ClusterctlInitEnd,
+					},
+				},
+			},
+		},
+		{
+			name:        "Regular Run move",
+			cfgDoc:      executorDoc(t, "move"),
+			bundlePath:  "testdata/executor_move",
+			expectedEvt: []events.Event{wrapError(airerrors.ErrNotImplemented{})},
+		},
+	}
+	for _, test := range testCases {
+		tt := test
+		t.Run(tt.name, func(t *testing.T) {
+			bundle, err := document.NewBundleByPath(tt.bundlePath)
+			require.NoError(t, err)
+			kubeCfg := kubeconfig.NewKubeConfig(
+				kubeconfig.FromByte([]byte("someKubeConfig")),
+				kubeconfig.InjectFileSystem(tt.fs),
+			)
+			executor, err := cctlclient.NewExecutor(
+				ifc.ExecutorConfig{
+					ExecutorDocument: tt.cfgDoc,
+					ExecutorBundle:   bundle,
+					AirshipSettings:  sampleSettings(),
+					KubeConfig:       kubeCfg,
+				})
+			require.NoError(t, err)
+			ch := make(chan events.Event)
+			go executor.Run(ch, ifc.RunOptions{Debug: true, DryRun: true})
+			var actualEvt []events.Event
+			for evt := range ch {
+				actualEvt = append(actualEvt, evt)
+			}
+			assert.Equal(t, tt.expectedEvt, actualEvt)
+		})
+	}
+}
+
+func TestExecutorValidate(t *testing.T) {
+	sampleCfgDoc := executorDoc(t, "init")
+	bundle, err := document.NewBundleByPath("testdata/executor_init")
+	require.NoError(t, err)
+	executor, err := cctlclient.NewExecutor(
+		ifc.ExecutorConfig{
+			ExecutorDocument: sampleCfgDoc,
+			ExecutorBundle:   bundle,
+			AirshipSettings:  sampleSettings(),
+		})
+	require.NoError(t, err)
+	expectedErr := airerrors.ErrNotImplemented{}
+	actualErr := executor.Validate()
+	assert.Equal(t, expectedErr, actualErr)
+}
+func TestExecutorRender(t *testing.T) {
+	sampleCfgDoc := executorDoc(t, "init")
+	bundle, err := document.NewBundleByPath("testdata/executor_init")
+	require.NoError(t, err)
+	expectedErr := airerrors.ErrNotImplemented{}
+
+	executor, err := cctlclient.NewExecutor(
+		ifc.ExecutorConfig{
+			ExecutorDocument: sampleCfgDoc,
+			ExecutorBundle:   bundle,
+			AirshipSettings:  sampleSettings(),
+		})
+	require.NoError(t, err)
+	actualOut := &bytes.Buffer{}
+	actualErr := executor.Render(actualOut, ifc.RenderOptions{})
+	assert.Equal(t, expectedErr, actualErr)
+}
+
+func sampleSettings() *environment.AirshipCTLSettings {
+	cfg := config.NewConfig()
+	cfg.Manifests[config.AirshipDefaultManifest].TargetPath = "./testdata"
+	return &environment.AirshipCTLSettings{Config: cfg, AirshipConfigPath: "."}
+}
+
+func executorDoc(t *testing.T, action string) document.Document {
+	cfg := []byte(fmt.Sprintf(executorConfigTmpl, action))
+	cfgDoc, err := document.NewDocumentFromBytes(cfg)
+	require.NoError(t, err)
+	return cfgDoc
+}
+
+func wrapError(err error) events.Event {
+	return events.Event{
+		Type: events.ErrorType,
+		ErrorEvent: events.ErrorEvent{
+			Error: err,
+		},
+	}
+}
diff --git a/pkg/clusterctl/client/testdata/executor_init/kubeconfig.yaml b/pkg/clusterctl/client/testdata/executor_init/kubeconfig.yaml
new file mode 100644
index 000000000..fccb7aa59
--- /dev/null
+++ b/pkg/clusterctl/client/testdata/executor_init/kubeconfig.yaml
@@ -0,0 +1,24 @@
+apiVersion: airshipit.org/v1alpha1
+kind: KubeConfig
+metadata:
+  name: sample-name
+config:
+  apiVersion: v1
+  kind: Config
+  clusters:
+  - cluster:
+      certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+      server: https://10.23.25.101:6443
+    name: dummycluster_ephemeral
+  contexts:
+  - context:
+      cluster: dummycluster_ephemeral
+      user: kubernetes-admin
+    name: dummy_cluster
+  current-context: dummy_cluster
+  preferences: {}
+  users:
+  - name: kubernetes-admin
+    user:
+      client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
+      client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBeHVGZE5HUlhwdDdDVkhScDlrQzdRVnA2WDIyWVR4a2REK0dSa2ZHYzN2cVhwTTlpCmFsdWlIaWdYY1hSQ09qZzBwbjNsT2RuajF5RmFmakZGdDVnNUtjT25TSllQZkFsWkZYS0pDaFFDdHIweW00N28KUVJKQ0tWUVhteXF3UlpCWlRiUU16NEFhcjVqaUNEdkhhNElkSzh3VkdMN2d2MFNKWWFXQVBiK2hkWkdjeGNyVApncytQbzZpNTJoOXZCMTg2dk83UTVVUkxpM0dTY284Rnc5TksvWFY1bGhkeVFFTlhjNlVzUGdYQzdURG52U3ZECmZ2VDZFbGU5V3JDOXloMXgvb1A4OVpqU09LRENPTElHZUNCWnFieEJCekJLZkRQakEyVmJFbjFMWmdFU2htYTYKVlJGQmxoajE2MENra0MxTGMzMVBwUHBuOGxGQzBacDNaODFaSnNzT3MyTzR3MHVFQnAwc0hFZy9NRG05VmsxbQpORjIwTFJLZUxaQlBYbUlkbkhCT3F2aU1NOElsY1M3djc2cXFNOVZaT0lVcjZ1T3BKb3BtTlI5U0lrWUVGV3VkCkI4RVBpeVlXeDAzVEt1aVpybzF6Z3Zra3FaQlpJYStDNkdiZWFlVnZWQ0pOaU82dDFFOE5KKytYNElJYWVua0UKaitCbW5ZQzRlei9ra2xUWjZ4V2o4dVVRNjNCSDNCYkRCYXJUOS94WXEzR1pPVFhuYjBtKzA4VUMzVEtZRlh3KwpXOTV1Nmx0dVBLZUwrVldiWTF0N081N0g1N1FreVdSVm1wOXNORXFmc25wZ21zWmlZRTlTMEZhRWhqZWhraFRVCk5DdndnZ2VjWjl0V0ZsUExRd2ZZQUVDNjlRK29wRlU3ZytMVVRYSHdEcko0N0pNS3VuSDhrQ1Rtc1owQ0F3RUEKQVFLQ0FnQUJ2U1N3ZVpRZW5HSDhsUXY4SURMQzdvU1ZZd0xxNWlCUDdEdjJsN00wYStKNWlXcWwzV2s4ZEVOSQpOYWtDazAwNmkyMCtwVDROdW5mdEZJYzBoTHN6TjBlMkpjRzY1dVlGZnZ2ZHY3RUtZZnNZU3hhU3d4TWJBMlkxCmNCa2NjcGVsUzBhMVpieFYvck16T1RxVUlRNGFQTzJPU3RUeU55b3dWVjhhcXh0QlNPV2pBUlA2VjlBOHNSUDIKNlVGeVFnM2thdjRla3d0S0M5TW85MEVvcGlkSXNnYy9IYk5kQm5tMFJDUnY0bU1DNmVPTXp0NGx0UVNldG0rcwpaRkUwZkM5cjkwRjE4RUVlUjZHTEYxdGhIMzlKTWFFcjYrc3F6TlZXU1VPVGxNN2M5SE55QTJIcnJudnhVUVNOCmF3SkZWSEFOY1hJSjBqcW9icmR6MTdMbGtIRVFGczNLdjRlcDR3REJKMlF0eisxdUFvY1JoV3ZSaWJxWEQ3THgKVmpPdGRyT1h3ZFQxY2ZrKzZRc1RMWUFKR3ptdDdsY1M2QjNnYzJHWmNJWGwyNVlqTUQ1ZVhpa1dEc3hYWmt1UAorb3MzVGhxeGZIS25ITmxtYk9SSVpDMW92Q1NkSTRWZVpzalk0MUs5K0dNaXdXSk1kektpRkp3NlR2blRSUldTCkxod2EzUTlBVmMvTEg0SC9PbU9qWDc0QTNZSWwrRDFVUHd3VzAvMmw4S3BNM0VWZ21XalJMV1ZIRnBNTGJNSlcKZVZKd3dKUmF3bWZLdHZ6bU9KRHlhTXJJblhqTDMvSE1EaWtwU3JhRzFyTnc1SUozOXJZdEFIUUQ1L1VuZlRkSApLNXVjakVucTdPdDMyR1ozcHJvRTU1ZGFBY0hQbktuOGpYZ1ZKTUQyOWh5cEZvL2ZRUUtDQVFFQStBbjRoSDFFCm9GK3FlcWlvYXR3N2cwaVdQUDNCeklxOEZWbWtsRlZBYVF5U28wU2QxWFBybmErR0RFQVd0cHlsVjF5ZkZkR2oKSHc4YXU5NnpUZnRuNWZCRkQxWG1NTkNZeTcrM293V3ArK1NwYUMvMTYzN1dvb3lLRjBjVFNvcWEzZEVuRUtSSwp4TGF2a0lFUTI3OXRBNFVUK0dVK3pTb0NPUFBNNE1JS3poR0FDczZ1anRySzFNcXpwK0JhYldzRlBuN2J1bStVCkRHSFIrNCtab2tBL1Q2N2luYlRxZUwwVzJCNjRMckFURHpZL3Y4NlRGbW1aallEaHRKR1JIWVZUOU9XSXR0RVkKNnZtUDN0a1dOTWt0R2w4bTFiQ0FHQ1JlcGtycUhxWXNMWG5GQ2ZZSFFtOXNpaGgvM3JFVjZ1MUYxZCt0U3JFMgprU1ZVOHhVWDUwbHFNUUtDQVFFQXpVTjZaS0lRNldkT09FR3ZyMExRL1hVczI0bUczN3lGMjhJUDJEcWFBWWVzCnJza2xTdjdlSU9TZWV3MW1CRHVCRkl2bkZvcTVsRlA3cXhWcEIyWjNNSGlDMVNaclZSZjlQTjdCNGFzcmNyMCsKdDB2S0NXWFFIaTVQQXhucXdYb2E2N0Q1bnkwdnlvV0lVUXAyZEZMdkIwQmp0b3MvajJFaHpJZk5WMm1UOW15bgpWQXZOWEdtZnc4SVJCL1diMGkzQ3c0Wityb1l1dTJkRHo2UUwzUFVvN1hLS3ljZzR1UzU1eksvcWZPc09lYm5mCnpsd3ZqbGxNSitmVFFHNzMrQnpINE5IWGs2akZZQzU4eXBrdXd0cmJmYk1pSkZOWThyV1ptL01Nd1VDWlZDQ3kKeUlxQ3FHQVB6b2kyU05zSEtaTlJqN3ZZQ3dQQVd6TzFidjFGcC9hM0xRS0NBUUVBeG0zTGw4cFROVzF6QjgrWApkRzJkV3FpZU1FcmRXRklBcDUvZ1R4NW9lZUdxQ2QxaDJ4cHlldUtwZlhGaitsRVU0Ty9qQU9TRjk5bndqQzFjCkNsMit2Ni9ZdjZ6N2l6L0ZqUEpoNlpRbGFiT0RaeXMvTkZkelEvVGtvRHluRFRJWE5LOFc3blJRc0ZCcDRWT3YKZGUwTlBBeWhiazBvMFo3eXlqY1lSeEpVN0lnSmhCdldmOGcvRGI3ZnZNUjU4eUR6d0F4aW9pS1RNTmlzMFBBUAplMEtrbzQySUU1eGhHNWhDQjBHRUhTMlZBYzFuY0gzRkk5LzFETVAzVEtwTGltOVlQQW5JdG1CTzYrUWNtYTNYCjJ3QzZDV2ZudkhvSDc4aGd3KzRZbjg1V2QwYjhQN3pJRC9qdHZ3aGNlMzMxeDh4cjJ1Nm5ScUxBd1pzNCs0SjcKYmZkSWNRS0NBUUFDL2JlNzNheTNhZnoyenVZN2ZKTEZEcjhQbCtweU9qSU5LTC9JVzlwQXFYUjN1NUNpamlJNApnbnhZdUxKQzM0Y2JBSXJtaGpEOEcxa3dmZ2hneGpwNFoxa290LzJhYU5ZVTIvNGhScmhFWE1PY01pdUloWVpKCjJrem1jNnM3RklkdDVjOU5aWUFyeUZSYk1mYlY3UnQwbEppZllWb1V3Y3FYUzJkUG5jYzlNUW9qTEdUYXN1TlUKRy9EWmw5ZWtjV3hFSXlLWGNuY2QzZnhiK3p6OUJFbUxaRDduZjlacnhHU2IrZmhGeDdzWFJRRWc1YkQvdHdkbwpFWFcvbTU1YmJEZnhhNzFqZG5NaDJxdVEzRGlWT0ZFNGZMTERxcjlDRWlsaDMySFJNeHJJNGcwWTVRUFFaazMwCnFZTldmbktWUllOTHYrWC9DeGZ6ZkVacGpxRkVPRkVsQW9JQkFRQ0t6R2JGdmx6d1BaUmh4czd2VXYxOXlIUXAKQzFmR3gwb0tpRDFSNWZwWVBrT0VRQWVudEFKRHNyYVRsNy9rSDY5V09VbUQ1T3gxbWpyRFB0a1M4WnhXYlJXeApGYjJLK3JxYzRtcGFacGROV09OTkszK3RNZmsrb0FRcWUySU1JV253NUhmbVpjNE1QY0t0bkZQYlJTTkF0aktwCkQ2aG9oL3BXMmdjRFA0cVpNWVZvRW04MVZYZEZDUGhOYitNYnUvU3gyaFB4U0dXYTVGaTczeEtwWWp5M3BISlQKWFoyY2lHN0VNQ3NKZW9HS2FRdmNCY1kvNGlSRGFoV0hWcmlsSVhJQXJQdXdmVUIybzZCZFR0allHeU5sZ2NmeApxWEt4aXBTaEE2VlNienVnR3pkdEdNeEUyekRHVEkxOXFSQy96OUNEREM1ZTJTQUZqbEJUV0QyUHJjcU4KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
\ No newline at end of file
diff --git a/pkg/clusterctl/client/testdata/executor_init/kustomization.yaml b/pkg/clusterctl/client/testdata/executor_init/kustomization.yaml
new file mode 100644
index 000000000..64b49bda4
--- /dev/null
+++ b/pkg/clusterctl/client/testdata/executor_init/kustomization.yaml
@@ -0,0 +1,2 @@
+resources:
+  - kubeconfig.yaml
\ No newline at end of file
diff --git a/pkg/clusterctl/client/testdata/executor_init_empty/kustomization.yaml b/pkg/clusterctl/client/testdata/executor_init_empty/kustomization.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/pkg/clusterctl/client/testdata/executor_move/kubeconfig.yaml b/pkg/clusterctl/client/testdata/executor_move/kubeconfig.yaml
new file mode 100644
index 000000000..fccb7aa59
--- /dev/null
+++ b/pkg/clusterctl/client/testdata/executor_move/kubeconfig.yaml
@@ -0,0 +1,24 @@
+apiVersion: airshipit.org/v1alpha1
+kind: KubeConfig
+metadata:
+  name: sample-name
+config:
+  apiVersion: v1
+  kind: Config
+  clusters:
+  - cluster:
+      certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+      server: https://10.23.25.101:6443
+    name: dummycluster_ephemeral
+  contexts:
+  - context:
+      cluster: dummycluster_ephemeral
+      user: kubernetes-admin
+    name: dummy_cluster
+  current-context: dummy_cluster
+  preferences: {}
+  users:
+  - name: kubernetes-admin
+    user:
+      client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
+      client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBeHVGZE5HUlhwdDdDVkhScDlrQzdRVnA2WDIyWVR4a2REK0dSa2ZHYzN2cVhwTTlpCmFsdWlIaWdYY1hSQ09qZzBwbjNsT2RuajF5RmFmakZGdDVnNUtjT25TSllQZkFsWkZYS0pDaFFDdHIweW00N28KUVJKQ0tWUVhteXF3UlpCWlRiUU16NEFhcjVqaUNEdkhhNElkSzh3VkdMN2d2MFNKWWFXQVBiK2hkWkdjeGNyVApncytQbzZpNTJoOXZCMTg2dk83UTVVUkxpM0dTY284Rnc5TksvWFY1bGhkeVFFTlhjNlVzUGdYQzdURG52U3ZECmZ2VDZFbGU5V3JDOXloMXgvb1A4OVpqU09LRENPTElHZUNCWnFieEJCekJLZkRQakEyVmJFbjFMWmdFU2htYTYKVlJGQmxoajE2MENra0MxTGMzMVBwUHBuOGxGQzBacDNaODFaSnNzT3MyTzR3MHVFQnAwc0hFZy9NRG05VmsxbQpORjIwTFJLZUxaQlBYbUlkbkhCT3F2aU1NOElsY1M3djc2cXFNOVZaT0lVcjZ1T3BKb3BtTlI5U0lrWUVGV3VkCkI4RVBpeVlXeDAzVEt1aVpybzF6Z3Zra3FaQlpJYStDNkdiZWFlVnZWQ0pOaU82dDFFOE5KKytYNElJYWVua0UKaitCbW5ZQzRlei9ra2xUWjZ4V2o4dVVRNjNCSDNCYkRCYXJUOS94WXEzR1pPVFhuYjBtKzA4VUMzVEtZRlh3KwpXOTV1Nmx0dVBLZUwrVldiWTF0N081N0g1N1FreVdSVm1wOXNORXFmc25wZ21zWmlZRTlTMEZhRWhqZWhraFRVCk5DdndnZ2VjWjl0V0ZsUExRd2ZZQUVDNjlRK29wRlU3ZytMVVRYSHdEcko0N0pNS3VuSDhrQ1Rtc1owQ0F3RUEKQVFLQ0FnQUJ2U1N3ZVpRZW5HSDhsUXY4SURMQzdvU1ZZd0xxNWlCUDdEdjJsN00wYStKNWlXcWwzV2s4ZEVOSQpOYWtDazAwNmkyMCtwVDROdW5mdEZJYzBoTHN6TjBlMkpjRzY1dVlGZnZ2ZHY3RUtZZnNZU3hhU3d4TWJBMlkxCmNCa2NjcGVsUzBhMVpieFYvck16T1RxVUlRNGFQTzJPU3RUeU55b3dWVjhhcXh0QlNPV2pBUlA2VjlBOHNSUDIKNlVGeVFnM2thdjRla3d0S0M5TW85MEVvcGlkSXNnYy9IYk5kQm5tMFJDUnY0bU1DNmVPTXp0NGx0UVNldG0rcwpaRkUwZkM5cjkwRjE4RUVlUjZHTEYxdGhIMzlKTWFFcjYrc3F6TlZXU1VPVGxNN2M5SE55QTJIcnJudnhVUVNOCmF3SkZWSEFOY1hJSjBqcW9icmR6MTdMbGtIRVFGczNLdjRlcDR3REJKMlF0eisxdUFvY1JoV3ZSaWJxWEQ3THgKVmpPdGRyT1h3ZFQxY2ZrKzZRc1RMWUFKR3ptdDdsY1M2QjNnYzJHWmNJWGwyNVlqTUQ1ZVhpa1dEc3hYWmt1UAorb3MzVGhxeGZIS25ITmxtYk9SSVpDMW92Q1NkSTRWZVpzalk0MUs5K0dNaXdXSk1kektpRkp3NlR2blRSUldTCkxod2EzUTlBVmMvTEg0SC9PbU9qWDc0QTNZSWwrRDFVUHd3VzAvMmw4S3BNM0VWZ21XalJMV1ZIRnBNTGJNSlcKZVZKd3dKUmF3bWZLdHZ6bU9KRHlhTXJJblhqTDMvSE1EaWtwU3JhRzFyTnc1SUozOXJZdEFIUUQ1L1VuZlRkSApLNXVjakVucTdPdDMyR1ozcHJvRTU1ZGFBY0hQbktuOGpYZ1ZKTUQyOWh5cEZvL2ZRUUtDQVFFQStBbjRoSDFFCm9GK3FlcWlvYXR3N2cwaVdQUDNCeklxOEZWbWtsRlZBYVF5U28wU2QxWFBybmErR0RFQVd0cHlsVjF5ZkZkR2oKSHc4YXU5NnpUZnRuNWZCRkQxWG1NTkNZeTcrM293V3ArK1NwYUMvMTYzN1dvb3lLRjBjVFNvcWEzZEVuRUtSSwp4TGF2a0lFUTI3OXRBNFVUK0dVK3pTb0NPUFBNNE1JS3poR0FDczZ1anRySzFNcXpwK0JhYldzRlBuN2J1bStVCkRHSFIrNCtab2tBL1Q2N2luYlRxZUwwVzJCNjRMckFURHpZL3Y4NlRGbW1aallEaHRKR1JIWVZUOU9XSXR0RVkKNnZtUDN0a1dOTWt0R2w4bTFiQ0FHQ1JlcGtycUhxWXNMWG5GQ2ZZSFFtOXNpaGgvM3JFVjZ1MUYxZCt0U3JFMgprU1ZVOHhVWDUwbHFNUUtDQVFFQXpVTjZaS0lRNldkT09FR3ZyMExRL1hVczI0bUczN3lGMjhJUDJEcWFBWWVzCnJza2xTdjdlSU9TZWV3MW1CRHVCRkl2bkZvcTVsRlA3cXhWcEIyWjNNSGlDMVNaclZSZjlQTjdCNGFzcmNyMCsKdDB2S0NXWFFIaTVQQXhucXdYb2E2N0Q1bnkwdnlvV0lVUXAyZEZMdkIwQmp0b3MvajJFaHpJZk5WMm1UOW15bgpWQXZOWEdtZnc4SVJCL1diMGkzQ3c0Wityb1l1dTJkRHo2UUwzUFVvN1hLS3ljZzR1UzU1eksvcWZPc09lYm5mCnpsd3ZqbGxNSitmVFFHNzMrQnpINE5IWGs2akZZQzU4eXBrdXd0cmJmYk1pSkZOWThyV1ptL01Nd1VDWlZDQ3kKeUlxQ3FHQVB6b2kyU05zSEtaTlJqN3ZZQ3dQQVd6TzFidjFGcC9hM0xRS0NBUUVBeG0zTGw4cFROVzF6QjgrWApkRzJkV3FpZU1FcmRXRklBcDUvZ1R4NW9lZUdxQ2QxaDJ4cHlldUtwZlhGaitsRVU0Ty9qQU9TRjk5bndqQzFjCkNsMit2Ni9ZdjZ6N2l6L0ZqUEpoNlpRbGFiT0RaeXMvTkZkelEvVGtvRHluRFRJWE5LOFc3blJRc0ZCcDRWT3YKZGUwTlBBeWhiazBvMFo3eXlqY1lSeEpVN0lnSmhCdldmOGcvRGI3ZnZNUjU4eUR6d0F4aW9pS1RNTmlzMFBBUAplMEtrbzQySUU1eGhHNWhDQjBHRUhTMlZBYzFuY0gzRkk5LzFETVAzVEtwTGltOVlQQW5JdG1CTzYrUWNtYTNYCjJ3QzZDV2ZudkhvSDc4aGd3KzRZbjg1V2QwYjhQN3pJRC9qdHZ3aGNlMzMxeDh4cjJ1Nm5ScUxBd1pzNCs0SjcKYmZkSWNRS0NBUUFDL2JlNzNheTNhZnoyenVZN2ZKTEZEcjhQbCtweU9qSU5LTC9JVzlwQXFYUjN1NUNpamlJNApnbnhZdUxKQzM0Y2JBSXJtaGpEOEcxa3dmZ2hneGpwNFoxa290LzJhYU5ZVTIvNGhScmhFWE1PY01pdUloWVpKCjJrem1jNnM3RklkdDVjOU5aWUFyeUZSYk1mYlY3UnQwbEppZllWb1V3Y3FYUzJkUG5jYzlNUW9qTEdUYXN1TlUKRy9EWmw5ZWtjV3hFSXlLWGNuY2QzZnhiK3p6OUJFbUxaRDduZjlacnhHU2IrZmhGeDdzWFJRRWc1YkQvdHdkbwpFWFcvbTU1YmJEZnhhNzFqZG5NaDJxdVEzRGlWT0ZFNGZMTERxcjlDRWlsaDMySFJNeHJJNGcwWTVRUFFaazMwCnFZTldmbktWUllOTHYrWC9DeGZ6ZkVacGpxRkVPRkVsQW9JQkFRQ0t6R2JGdmx6d1BaUmh4czd2VXYxOXlIUXAKQzFmR3gwb0tpRDFSNWZwWVBrT0VRQWVudEFKRHNyYVRsNy9rSDY5V09VbUQ1T3gxbWpyRFB0a1M4WnhXYlJXeApGYjJLK3JxYzRtcGFacGROV09OTkszK3RNZmsrb0FRcWUySU1JV253NUhmbVpjNE1QY0t0bkZQYlJTTkF0aktwCkQ2aG9oL3BXMmdjRFA0cVpNWVZvRW04MVZYZEZDUGhOYitNYnUvU3gyaFB4U0dXYTVGaTczeEtwWWp5M3BISlQKWFoyY2lHN0VNQ3NKZW9HS2FRdmNCY1kvNGlSRGFoV0hWcmlsSVhJQXJQdXdmVUIybzZCZFR0allHeU5sZ2NmeApxWEt4aXBTaEE2VlNienVnR3pkdEdNeEUyekRHVEkxOXFSQy96OUNEREM1ZTJTQUZqbEJUV0QyUHJjcU4KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
\ No newline at end of file
diff --git a/pkg/clusterctl/client/testdata/executor_move/kustomization.yaml b/pkg/clusterctl/client/testdata/executor_move/kustomization.yaml
new file mode 100644
index 000000000..64b49bda4
--- /dev/null
+++ b/pkg/clusterctl/client/testdata/executor_move/kustomization.yaml
@@ -0,0 +1,2 @@
+resources:
+  - kubeconfig.yaml
\ No newline at end of file
diff --git a/pkg/events/events.go b/pkg/events/events.go
index 1ab4e8a34..730c8a14b 100644
--- a/pkg/events/events.go
+++ b/pkg/events/events.go
@@ -31,6 +31,8 @@ const (
 	StatusPollerType
 	// WaitType is event emitted when airshipctl is waiting for something
 	WaitType
+	// ClusterctlType event emitted by Clusterctl executor
+	ClusterctlType
 )
 
 // Event holds all possible events that can be produced by airship
@@ -39,9 +41,29 @@ type Event struct {
 	ApplierEvent      applyevent.Event
 	ErrorEvent        ErrorEvent
 	StatusPollerEvent statuspollerevent.Event
+	ClusterctlEvent   ClusterctlEvent
 }
 
 // ErrorEvent is produced when error is encountered
 type ErrorEvent struct {
 	Error error
 }
+
+// ClusterctlOperation type
+type ClusterctlOperation int
+
+const (
+	// ClusterctlInitStart operation
+	ClusterctlInitStart ClusterctlOperation = iota
+	// ClusterctlInitEnd operation
+	ClusterctlInitEnd
+	// ClusterctlMoveStart operation
+	ClusterctlMoveStart
+	// ClusterctlMoveEnd operation
+	ClusterctlMoveEnd
+)
+
+// ClusterctlEvent is prodiced by clusterctl executor
+type ClusterctlEvent struct {
+	Operation ClusterctlOperation
+}
diff --git a/pkg/phase/errors.go b/pkg/phase/errors.go
index 8739f66cc..499b2fd82 100644
--- a/pkg/phase/errors.go
+++ b/pkg/phase/errors.go
@@ -29,3 +29,13 @@ type ErrExecutorNotFound struct {
 func (e ErrExecutorNotFound) Error() string {
 	return fmt.Sprintf("executor identified by '%s' is not found", e.GVK)
 }
+
+// ErrExecutorRegistration is a wrapper for executor registration errors
+type ErrExecutorRegistration struct {
+	ExecutorName string
+	Err          error
+}
+
+func (e ErrExecutorRegistration) Error() string {
+	return fmt.Sprintf("failed to register executor %s, registration function returned %s", e.ExecutorName, e.Err.Error())
+}
diff --git a/pkg/phase/phase.go b/pkg/phase/phase.go
index 3659d26d9..3971c3361 100644
--- a/pkg/phase/phase.go
+++ b/pkg/phase/phase.go
@@ -21,6 +21,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
+	clusterctl "opendev.org/airship/airshipctl/pkg/clusterctl/client"
 	"opendev.org/airship/airshipctl/pkg/config"
 	"opendev.org/airship/airshipctl/pkg/document"
 	"opendev.org/airship/airshipctl/pkg/environment"
@@ -38,7 +39,10 @@ type ExecutorRegistry func() map[schema.GroupVersionKind]ifc.ExecutorFactory
 // DefaultExecutorRegistry returns map with executor factories
 func DefaultExecutorRegistry() map[schema.GroupVersionKind]ifc.ExecutorFactory {
 	execMap := make(map[schema.GroupVersionKind]ifc.ExecutorFactory)
-	// add executors here
+
+	if err := clusterctl.RegisterExecutor(execMap); err != nil {
+		log.Fatal(ErrExecutorRegistration{ExecutorName: "clusterctl", Err: err})
+	}
 	return execMap
 }