diff --git a/cmd/gotk/bootstrap_gitlab.go b/cmd/gotk/bootstrap_gitlab.go
index f94824d7c835f40e71b7e645219ed6289b193615..3426b7f4e1fa052566214bf18630d80855a2127f 100644
--- a/cmd/gotk/bootstrap_gitlab.go
+++ b/cmd/gotk/bootstrap_gitlab.go
@@ -26,6 +26,8 @@ import (
 	"time"
 
 	"github.com/spf13/cobra"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/fluxcd/pkg/git"
 )
@@ -41,14 +43,17 @@ the bootstrap command will perform an upgrade if needed.`,
 	Example: `  # Create a GitLab API token and export it as an env var
   export GITLAB_TOKEN=<my-token>
 
-  # Run bootstrap for a private repo owned by a GitLab group
+  # Run bootstrap for a private repo using HTTPS token authentication 
   gotk bootstrap gitlab --owner=<group> --repository=<repo name>
 
+  # Run bootstrap for a private repo using SSH authentication
+  gotk bootstrap gitlab --owner=<group> --repository=<repo name> --ssh-hostname=gitlab.com
+
   # Run bootstrap for a repository path
   gotk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
 
   # Run bootstrap for a public repository on a personal account
-  gotk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true 
+  gotk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
 
   # Run bootstrap for a private repo hosted on a GitLab server 
   gotk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
@@ -77,7 +82,7 @@ func init() {
 	bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
 	bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
 	bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
-	bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, defaults to hostname if not specified")
+	bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, when specified a deploy key will be added to the repository")
 	bootstrapGitLabCmd.Flags().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
 
 	bootstrapCmd.AddCommand(bootstrapGitLabCmd)
@@ -172,34 +177,54 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 		logger.Successf("install completed")
 	}
 
-	// setup SSH deploy key
-	if shouldCreateDeployKey(ctx, kubeClient, namespace) {
-		logger.Actionf("configuring deploy key")
-		u, err := url.Parse(repository.GetSSH())
-		if err != nil {
-			return fmt.Errorf("git URL parse failed: %w", err)
-		}
+	repoURL := repository.GetURL()
 
-		key, err := generateDeployKey(ctx, kubeClient, u, namespace)
-		if err != nil {
-			return fmt.Errorf("generating deploy key failed: %w", err)
+	if glSSHHostname != "" {
+		// setup SSH deploy key
+		repoURL = repository.GetSSH()
+		if shouldCreateDeployKey(ctx, kubeClient, namespace) {
+			logger.Actionf("configuring deploy key")
+			u, err := url.Parse(repoURL)
+			if err != nil {
+				return fmt.Errorf("git URL parse failed: %w", err)
+			}
+
+			key, err := generateDeployKey(ctx, kubeClient, u, namespace)
+			if err != nil {
+				return fmt.Errorf("generating deploy key failed: %w", err)
+			}
+
+			keyName := "gotk"
+			if glPath != "" {
+				keyName = fmt.Sprintf("gotk-%s", glPath)
+			}
+
+			if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
+				return err
+			} else if changed {
+				logger.Successf("deploy key configured")
+			}
 		}
-
-		keyName := "gotk"
-		if glPath != "" {
-			keyName = fmt.Sprintf("gotk-%s", glPath)
+	} else {
+		// setup HTTPS token auth
+		secret := corev1.Secret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      namespace,
+				Namespace: namespace,
+			},
+			StringData: map[string]string{
+				"username": "git",
+				"password": glToken,
+			},
 		}
-
-		if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
+		if err := upsertSecret(ctx, kubeClient, secret); err != nil {
 			return err
-		} else if changed {
-			logger.Successf("deploy key configured")
 		}
 	}
 
 	// configure repo synchronization
 	logger.Actionf("generating sync manifests")
-	if err := generateSyncManifests(repository.GetSSH(), bootstrapBranch, namespace, namespace, glPath, tmpDir, glInterval); err != nil {
+	if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, glPath, tmpDir, glInterval); err != nil {
 		return err
 	}
 
diff --git a/docs/cmd/gotk_bootstrap_gitlab.md b/docs/cmd/gotk_bootstrap_gitlab.md
index 34cdd2c13c82a5a02c39a330e9ac6685692d346c..68f066a0eb69e7a4ae5b1bf571d66cdf27195d6f 100644
--- a/docs/cmd/gotk_bootstrap_gitlab.md
+++ b/docs/cmd/gotk_bootstrap_gitlab.md
@@ -20,14 +20,17 @@ gotk bootstrap gitlab [flags]
   # Create a GitLab API token and export it as an env var
   export GITLAB_TOKEN=<my-token>
 
-  # Run bootstrap for a private repo owned by a GitLab group
+  # Run bootstrap for a private repo using HTTPS token authentication 
   gotk bootstrap gitlab --owner=<group> --repository=<repo name>
 
+  # Run bootstrap for a private repo using SSH authentication
+  gotk bootstrap gitlab --owner=<group> --repository=<repo name> --ssh-hostname=gitlab.com
+
   # Run bootstrap for a repository path
   gotk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
 
   # Run bootstrap for a public repository on a personal account
-  gotk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true 
+  gotk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
 
   # Run bootstrap for a private repo hosted on a GitLab server 
   gotk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
@@ -48,7 +51,7 @@ gotk bootstrap gitlab [flags]
       --personal              is personal repository
       --private               is private repository (default true)
       --repository string     GitLab repository name
-      --ssh-hostname string   GitLab SSH hostname, defaults to hostname if not specified
+      --ssh-hostname string   GitLab SSH hostname, when specified a deploy key will be added to the repository
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/guides/installation.md b/docs/guides/installation.md
index 457167deea5b33c4c77955b2a175d6123d2a20b0..589d23479d9d61d5cd51c5353832b5b8b81c4678 100644
--- a/docs/guides/installation.md
+++ b/docs/guides/installation.md
@@ -154,6 +154,22 @@ gotk bootstrap gitlab \
   --personal
 ```
 
+To run the bootstrap for a repository using deploy keys for authentication, you have to specify the SSH hostname:
+
+```sh
+gotk bootstrap gitlab \
+  --ssh-hostname=gitlab.com \
+  --owner=my-gitlab-username \
+  --repository=my-repository \
+  --branch=master \
+  --path=my-cluster
+```
+
+!!! hint "Authentication"
+    When providing the `--ssh-hostname`, a read-only (SSH) deploy key will be added 
+    to your repository, otherwise your GitLab personal token will be used to
+    authenticate against the HTTPS endpoint instead.
+
 Run the bootstrap for a repository owned by a GitLab group:
 
 ```sh