Repository: replicatedhq/kots
Pull request #759 (2020-07-08 17:17:06)

better status messages while processing airgap bundles


Patch:
diff --git a/.github/workflows/kotsadm.yaml b/.github/workflows/kotsadm.yaml
index 2dc85f365..1b5eee8f1 100644
--- a/.github/workflows/kotsadm.yaml
+++ b/.github/workflows/kotsadm.yaml
@@ -89,8 +89,6 @@ jobs:
       uses: actions/checkout@v2
 
     - uses: azure/docker-login@v1
-      env:
-        DOCKER_CONFIG: ./kotsadm/migrations/.docker
       with:
         username: ${{ secrets.DOCKERHUB_USER }}
         password: ${{ secrets.DOCKERHUB_PASSWORD }}
@@ -103,8 +101,6 @@ jobs:
 
     - name: Build
       if: ${{ github.ref == 'refs/heads/master' }}
-      env:
-        DOCKER_CONFIG: ./.docker
       run: |
         make -C kotsadm/migrations schema-alpha
 
@@ -112,17 +108,8 @@ jobs:
       if: ${{ steps.get_tag.outputs.GIT_TAG != '' }}
       env:
         GIT_TAG: ${{ steps.get_tag.outputs.GIT_TAG }}
-        DOCKER_CONFIG: ./.docker
-      uses: ./actions/containers
-      with:
-        command: "make -C kotsadm/migrations schema-release"
-
-    - name: Upload airgap image
-      if: ${{ steps.get_tag.outputs.GIT_TAG != '' }}
-      uses: actions/upload-artifact@v2
-      with:
-        name: migrations-image
-        path: ./kotsadm/migrations/bin/docker-archive
+      run: |
+        make -C kotsadm/migrations schema-release
 
 
   test_web:
@@ -695,14 +682,7 @@ jobs:
       id: get_tag
       shell: bash
       run: echo ::set-output name=GIT_TAG::${GITHUB_REF/refs\/tags\//}
-
-    - name: Download migrations
-      if: ${{ steps.get_tag.outputs.GIT_TAG != '' }}
-      uses: actions/download-artifact@v2
-      with:
-        name: migrations-image
-        path: ./docker-archive
-
+  
     - name: Download kotsadm image
       if: ${{ steps.get_tag.outputs.GIT_TAG != '' }}
       uses: actions/download-artifact@v2
diff --git a/cmd/kots/cli/admin-console-upgrade.go b/cmd/kots/cli/admin-console-upgrade.go
index 13d2cd341..88b687b95 100644
--- a/cmd/kots/cli/admin-console-upgrade.go
+++ b/cmd/kots/cli/admin-console-upgrade.go
@@ -52,14 +52,6 @@ func AdminConsoleUpgradeCmd() *cobra.Command {
 				Namespace:             v.GetString("namespace"),
 				KubernetesConfigFlags: kubernetesConfigFlags,
 				ForceUpgradeKurl:      v.GetBool("force-upgrade-kurl"),
-
-				KotsadmOptions: kotsadmtypes.KotsadmOptions{
-					OverrideVersion:   v.GetString("kotsadm-tag"),
-					OverrideRegistry:  v.GetString("kotsadm-registry"),
-					OverrideNamespace: v.GetString("kotsadm-namespace"),
-					Username:          v.GetString("registry-username"),
-					Password:          v.GetString("registry-password"),
-				},
 			}
 
 			timeout, err := time.ParseDuration(v.GetString("wait-duration"))
@@ -69,6 +61,10 @@ func AdminConsoleUpgradeCmd() *cobra.Command {
 
 			upgradeOptions.Timeout = timeout
 
+			kotsadm.OverrideVersion = v.GetString("kotsadm-tag")
+			kotsadm.OverrideRegistry = v.GetString("kotsadm-registry")
+			kotsadm.OverrideNamespace = v.GetString("kotsadm-namespace")
+
 			log := logger.NewLogger()
 
 			if upgradeOptions.Namespace != "default" {
diff --git a/cmd/kots/cli/install.go b/cmd/kots/cli/install.go
index 6b25b9246..28093bc90 100644
--- a/cmd/kots/cli/install.go
+++ b/cmd/kots/cli/install.go
@@ -74,6 +74,10 @@ func InstallCmd() *cobra.Command {
 				namespace = enteredNamespace
 			}
 
+			kotsadm.OverrideVersion = v.GetString("kotsadm-tag")
+			kotsadm.OverrideRegistry = v.GetString("kotsadm-registry")
+			kotsadm.OverrideNamespace = v.GetString("kotsadm-namespace")
+
 			applicationMetadata, err := pull.PullApplicationMetadata(upstream)
 			if err != nil {
 				return errors.Wrap(err, "failed to pull app metadata")
@@ -124,14 +128,6 @@ func InstallCmd() *cobra.Command {
 				IncludeMinio:              v.GetBool("deploy-minio"),
 				IncludeDockerDistribution: v.GetBool("deploy-dockerdistribution"),
 				Timeout:                   time.Minute * 2,
-
-				KotsadmOptions: kotsadmtypes.KotsadmOptions{
-					OverrideVersion:   v.GetString("kotsadm-tag"),
-					OverrideRegistry:  v.GetString("kotsadm-registry"),
-					OverrideNamespace: v.GetString("kotsadm-namespace"),
-					Username:          v.GetString("registry-username"),
-					Password:          v.GetString("registry-password"),
-				},
 			}
 
 			timeout, err := time.ParseDuration(v.GetString("wait-duration"))
@@ -226,14 +222,12 @@ func InstallCmd() *cobra.Command {
 	cmd.Flags().String("repo", "", "repo uri to use when installing a helm chart")
 	cmd.Flags().StringSlice("set", []string{}, "values to pass to helm when running helm template")
 
-	cmd.Flags().String("kotsadm-registry", "", "set to override the registry of kotsadm images")
-	cmd.Flags().String("registry-username", "", "user name to use to authenticate with the registry")
-	cmd.Flags().String("registry-password", "", "password to use to authenticate with the registry")
-
 	// the following group of flags are useful for testing, but we don't want to pollute the help screen with them
 	cmd.Flags().String("kotsadm-tag", "", "set to override the tag of kotsadm. this may create an incompatible deployment because the version of kots and kotsadm are designed to work together")
+	cmd.Flags().String("kotsadm-registry", "", "set to override the registry of kotsadm image. this may create an incompatible deployment because the version of kots and kotsadm are designed to work together")
 	cmd.Flags().String("kotsadm-namespace", "", "set to override the namespace of kotsadm image. this may create an incompatible deployment because the version of kots and kotsadm are designed to work together")
 	cmd.Flags().MarkHidden("kotsadm-tag")
+	cmd.Flags().MarkHidden("kotsadm-registry")
 	cmd.Flags().MarkHidden("kotsadm-namespace")
 
 	// the following group of flags are experiemental and can be used to pull and push images during install time
diff --git a/design/_template.md b/design/_template.md
index d0be03347..b83893325 100644
--- a/design/_template.md
+++ b/design/_template.md
@@ -37,10 +37,6 @@ The same applies to changes in CRDs, YAML examples, and so on.
 
 Ideally the changes should be made in sequence so that the work required to implement this design can be done incrementally, possibly in parallel.
 
-## Testing
-
-Write a summary of how this enhancement will be tested to ensure there are no regressions in the future.
-
 ## Alternatives Considered
 
 If there are alternative high level or detailed designs that were not pursued they should be called out here with a brief explanation of why they were not pursued.
diff --git a/design/airgap-existing-cluster.md b/design/airgap-existing-cluster.md
deleted file mode 100644
index 9dcdfe6dd..000000000
--- a/design/airgap-existing-cluster.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Support for installing KOTS Admin Console in Airgapped Clusters
-
-## Goals
-
-- Install kotsadm to an existing cluster where the cluster does not have internet access
-- Install kotsadm to an existing cluster from a workstation where the workstation does not have internet access at the time of installation
-- Support different credentials for push / pull (workstation / cluster) to the local registry
-- Support temporary/dynamic and persistent/static credentials for pushing kotsadm images to the registry
-- Support only persistent/static credentials for pulling kotsadm images from the airgapped registry
-- Support different credentials for pushing vs pulling images to the local registry
-
-## Non Goals
-
-- Create a single installer for kotsadm + application
-- Create a single download for kotsadm, kots plugin, application and license
-- Unattended, automatic installs of kotsadm to existing clusters in airgap mode
-- Support for installing versions of KOTS different from the KOTS CLI version installed
-
-## Background
-
-It's not currently possible to install KOTS Admin Console into an existing cluster that doesn't have outbound internet access.
-
-## High-Level Design
-
-Airgap Workstation: the computer with kubectl access to the airgap cluster
-Public Workstation: the computer with access to the internet
-
-From the public workstation:
-1. The user downloads the kots plugin suitable for Airgap Workstation.
-1. The user downloads the kotsadm archive containing kots container images
-1. The user downloads the airgap bundle of the application
-1. The user copies the kots plugin, the kotsadm archive and the application airgap bundle onto a medium (eg a USB stick) that can be transfered into the airgapped network.
-
-From the airgap workstation:
-1. The user will install the kots plugin 
-1. The user will run a `kubectl kots` command to copy the container images in the kotsadm archive to the local registry, providing registry details for pushing
-1. The user will install kotsadm to the cluster using the kots plugin via `kots install` passing local registry information which will be used to generate the kotsadm yaml and image pull secrets (if neccessary)
-1. The user will install the application and license using the existing airgap installation process 
-
-## Detailed Design
-
-The CI process, on tag, will create the kotsadm archive and include it in the GitHub Release.
-The filename will be `kots_airgap_<version>.tar.gz` and this file contains .tar file exports of all kotsadm images.
-The files SHOULD be stored in the archive in the same format as application airgap files are stored.
-
-Add a `kots admin-console push-images` to the kots cli to retag and push all kotsadm images to an authenticated registry that is accessible from the cluster, using the desired push credentials.
-This new command is used to copy all of the KOTS Admin Console images from one location to another.
-
-Example:
-
-```
-kubectl kots admin-console push-images ./kotsadm-1.16.1.tar.gz registry.somebigbank.com/my-app \
-  --registry-username push-user \
-  --registry-password abcdef
-```
-
-Stretch: `--registry-username` and `--registry-password` are both optional.
-If not present, attempt to authenticate using the already authenticated local docker credentials.
-Stretch: if still not authenticated, prompt for username/password, use these to push but do not save locally.
-Stretch: if username is specified and password is not, prompt for password to use, do not save locally.
-
-KOTS will then load the images from the file in the first parameter, retag them to the local registry and push. 
-All images will retain the same image name and tag, just the registry, namespace will change.
-
-At this point, the images are in the registry, but not running in the cluster yet.
-A workflow could scan these images before continuing.
-
-Next, add a flag to `kots install` to collect / rewrite local registry endpoint/namespace into kots manifests, using the desired pull credentials.
-This will assume that the images are already in the destination.
-
-For example:
-
-```
-kubectl kots install --kotsadm-registry registry.somebigbank.com/my-app \
-  --registry-username pull-user \
-  --registry-password fedcba \
-  app-name
-```
-
-If a `registry-username` and `registry-password` are provided, an `imagePullSecret` will be created and deployed with the registry credentials and added to all kotsadm pods.
-
-The only difference between the command above and an online installation is that the `image` tag will be rewritten in all KOTS Admin Console manifests to point to `registry.somebigbank.com/my-app` and an `imagePullSecret` MAY be added.
-All image names and tags will be unchanged.
-For example, the kotsadm-operator will be `registry.somebigbank.com/my-app/kotsadm-operator:v1.16.1`.
-
-Stretch: Additionally, a new `--yaml` flag will be added to have `kots` only generate the yaml (not apply) to support gitops workflows.
-
-## Limitations
-
-- No support for custom branding in airgap installations to existing clusters
-- No support for `requireMinimalRBACPrivileges` set to `true` (all installs will be cluster admin, which matches all use cases of KOTS install today)
-
-## Assumptions
-
-- The airgap workstation will have kubectl access to the cluster
-- The airgap workstation must have push access to an image registry that the cluster has pull access 
-- The cluster credentials to pull from the local registry is either unauthenticated or static and persistent credentials (i.e. no Vault integration or other dynamically generated credentials will be supported)
-
-## Testing
-
-TBD
-
-## Alternatives Considered
-
-
-
-## Security Considerations
-
-- No open security considerations
diff --git a/kotsadm/migrations/Makefile b/kotsadm/migrations/Makefile
index 751af9f94..ce9eaf22b 100644
--- a/kotsadm/migrations/Makefile
+++ b/kotsadm/migrations/Makefile
@@ -8,10 +8,6 @@ schema-alpha: build_schema
 .PHONY: schema-release
 schema-release: IMAGE = kotsadm/${PROJECT_NAME}:${GIT_TAG}
 schema-release: build_schema
-	mkdir -p bin/docker-archive/${PROJECT_NAME}
-	skopeo copy docker-daemon:kotsadm/${PROJECT_NAME}:${GIT_TAG} docker-archive:bin/docker-archive/${PROJECT_NAME}/${GIT_TAG}
-	mkdir -p bin/docker-archive/postgres
-	skopeo copy docker://postgres:10.7 docker-archive:bin/docker-archive/postgres/${GIT_TAG}
 
 .PHONY: build-ttl-ci.sh
 build-ttl-ci.sh: IMAGE = ttl.sh/${UUID}/${PROJECT_NAME}:2h
diff --git a/kotsadm/pkg/airgap/airgap.go b/kotsadm/pkg/airgap/airgap.go
index 561899960..6a494e854 100644
--- a/kotsadm/pkg/airgap/airgap.go
+++ b/kotsadm/pkg/airgap/airgap.go
@@ -115,6 +115,10 @@ func CreateAppFromAirgap(pendingApp *PendingApp, airgapBundle multipart.File, re
 	defer os.RemoveAll(tmpFile.Name())
 
 	// Extract it
+	if err := task.SetTaskStatus("airgap-install", "Extracting files...", "running"); err != nil {
+		return errors.Wrap(err, "failed to set task status")
+	}
+
 	// we seem to need a lot of temp dirs here... maybe too many?
 	archiveDir, err := version.ExtractArchiveToTempDirectory(tmpFile.Name())
 	if err != nil {
@@ -122,10 +126,6 @@ func CreateAppFromAirgap(pendingApp *PendingApp, airgapBundle multipart.File, re
 	}
 	defer os.RemoveAll(archiveDir)
 
-	if err := task.SetTaskStatus("airgap-install", "Processing app package...", "running"); err != nil {
-		return errors.Wrap(err, "failed to set task status")
-	}
-
 	// extract the release
 	workspace, err := ioutil.TempDir("", "kots-airgap")
 	if err != nil {
@@ -144,6 +144,10 @@ func CreateAppFromAirgap(pendingApp *PendingApp, airgapBundle multipart.File, re
 	}
 	defer os.RemoveAll(tmpRoot)
 
+	if err := task.SetTaskStatus("airgap-install", "Reading license data...", "running"); err != nil {
+		return errors.Wrap(err, "failed to set task status")
+	}
+
 	decode := scheme.Codecs.UniversalDeserializer().Decode
 	obj, _, err := decode([]byte(pendingApp.LicenseData), nil, nil)
 	if err != nil {
diff --git a/kotsadm/pkg/airgap/update.go b/kotsadm/pkg/airgap/update.go
index daa16326a..dc1499467 100644
--- a/kotsadm/pkg/airgap/update.go
+++ b/kotsadm/pkg/airgap/update.go
@@ -95,12 +95,21 @@ func UpdateAppFromAirgap(a *app.App, airgapBundle multipart.File) (finalError er
 	if err != nil {
 		return errors.Wrap(err, "failed to create temp file")
 	}
+
+	if err := task.SetTaskStatus("update-download", "Copying package...", "running"); err != nil {
+		return errors.Wrap(err, "failed to set task status")
+	}
+
 	_, err = io.Copy(tmpFile, airgapBundle)
 	if err != nil {
 		return errors.Wrap(err, "failed to copy temp airgap")
 	}
 	defer os.RemoveAll(tmpFile.Name())
 
+	if err := task.SetTaskStatus("update-download", "Extracting files...", "running"); err != nil {
+		return errors.Wrap(err, "failed to set task status")
+	}
+
 	airgapRoot, err := version.ExtractArchiveToTempDirectory(tmpFile.Name())
 	if err != nil {
 		return errors.Wrap(err, "failed to extract archive")
@@ -116,6 +125,10 @@ func UpdateAppFromAirgap(a *app.App, airgapBundle multipart.File) (finalError er
 		appNamespace = os.Getenv("KOTSADM_TARGET_NAMESPACE")
 	}
 
+	if err := task.SetTaskStatus("update-download", "Creating app version...", "running"); err != nil {
+		return errors.Wrap(err, "failed to set task status")
+	}
+
 	appSequence, err := version.GetNextAppSequence(a.ID, &a.CurrentSequence)
 	if err != nil {
 		return errors.Wrap(err, "failed to get new app sequence")
diff --git a/kotsadm/pkg/handlers/snapshots.go b/kotsadm/pkg/handlers/snapshots.go
index 465f9b9c8..48f233a30 100644
--- a/kotsadm/pkg/handlers/snapshots.go
+++ b/kotsadm/pkg/handlers/snapshots.go
@@ -1,10 +1,8 @@
 package handlers
 
 import (
-	"context"
 	"encoding/json"
 	"net/http"
-	"os"
 	"strings"
 
 	"github.com/pkg/errors"
@@ -13,9 +11,6 @@ import (
 	"github.com/replicatedhq/kots/kotsadm/pkg/session"
 	"github.com/replicatedhq/kots/kotsadm/pkg/snapshot"
 	snapshottypes "github.com/replicatedhq/kots/kotsadm/pkg/snapshot/types"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/client-go/kubernetes"
-	"sigs.k8s.io/controller-runtime/pkg/client/config"
 )
 
 type GlobalSnapshotSettingsResponse struct {
@@ -36,11 +31,10 @@ type UpdateGlobalSnapshotSettingsRequest struct {
 	Bucket   string `json:"bucket"`
 	Path     string `json:"path"`
 
-	AWS      *snapshottypes.StoreAWS    `json:"aws"`
-	Google   *snapshottypes.StoreGoogle `json:"gcp"`
-	Azure    *snapshottypes.StoreAzure  `json:"azure"`
-	Other    *snapshottypes.StoreOther  `json:"other"`
-	Internal bool                       `json:"internal"`
+	AWS    *snapshottypes.StoreAWS    `json:"aws"`
+	Google *snapshottypes.StoreGoogle `json:"gcp"`
+	Azure  *snapshottypes.StoreAzure  `json:"azure"`
+	Other  *snapshottypes.StoreOther  `json:"other"`
 }
 
 func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
@@ -117,7 +111,6 @@ func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
 		store.Azure = nil
 		store.Google = nil
 		store.Other = nil
-		store.Internal = nil
 
 		store.AWS.UseInstanceRole = updateGlobalSnapshotSettingsRequest.AWS.UseInstanceRole
 		if store.AWS.UseInstanceRole {
@@ -155,7 +148,6 @@ func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
 		store.AWS = nil
 		store.Azure = nil
 		store.Other = nil
-		store.Internal = nil
 
 		store.Google.UseInstanceRole = updateGlobalSnapshotSettingsRequest.Google.UseInstanceRole
 		if store.Google.UseInstanceRole {
@@ -196,7 +188,6 @@ func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
 		store.AWS = nil
 		store.Google = nil
 		store.Other = nil
-		store.Internal = nil
 
 		if updateGlobalSnapshotSettingsRequest.Azure.ResourceGroup != "" {
 			store.Azure.ResourceGroup = updateGlobalSnapshotSettingsRequest.Azure.ResourceGroup
@@ -233,7 +224,6 @@ func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
 		store.AWS = nil
 		store.Google = nil
 		store.Azure = nil
-		store.Internal = nil
 
 		if updateGlobalSnapshotSettingsRequest.Other.AccessKeyID != "" {
 			store.Other.AccessKeyID = updateGlobalSnapshotSettingsRequest.Other.AccessKeyID
@@ -259,52 +249,6 @@ func UpdateGlobalSnapshotSettings(w http.ResponseWriter, r *http.Request) {
 			JSON(w, 400, globalSnapshotSettingsResponse)
 			return
 		}
-	} else if updateGlobalSnapshotSettingsRequest.Internal {
-		if !kurl.IsKurl() {
-			globalSnapshotSettingsResponse.Error = "cannot use internal storage on a non-kurl cluster"
-			JSON(w, 400, globalSnapshotSettingsResponse)
-			return
-		}
-
-		if store.Internal == nil {
-			store.Internal = &snapshottypes.StoreInternal{}
-		}
-		store.AWS = nil
-		store.Google = nil
-		store.Azure = nil
-		store.Other = nil
-
-		cfg, err := config.GetConfig()
-		if err != nil {
-			globalSnapshotSettingsResponse.Error = "failed to get cluster config"
-			JSON(w, 400, globalSnapshotSettingsResponse)
-			return
-		}
-
-		clientset, err := kubernetes.NewForConfig(cfg)
-		if err != nil {
-			globalSnapshotSettingsResponse.Error = "failed to create clientset"
-			JSON(w, 400, globalSnapshotSettingsResponse)
-			return
-		}
-
-		secret, err := clientset.CoreV1().Secrets(os.Getenv("POD_NAMESPACE")).Get(context.TODO(), "kotsadm-s3", metav1.GetOptions{})
-		if err != nil {
-			logger.Error(err)
-			globalSnapshotSettingsResponse.Error = err.Error()
-			JSON(w, 400, globalSnapshotSettingsResponse)
-			return
-		}
-
-		store.Provider = "aws"
-		store.Bucket = string(secret.Data["velero-local-bucket"])
-		store.Path = ""
-
-		store.Internal.AccessKeyID = string(secret.Data["access-key-id"])
-		store.Internal.SecretAccessKey = string(secret.Data["secret-access-key"])
-		store.Internal.Endpoint = string(secret.Data["endpoint"])
-		store.Internal.ObjectStoreClusterIP = string(secret.Data["object-store-cluster-ip"])
-		store.Internal.Region = "us-east-1"
 	}
 
 	if err := snapshot.ValidateStore(store); err != nil {
diff --git a/kotsadm/pkg/snapshot/store.go b/kotsadm/pkg/snapshot/store.go
index fd8e61174..4871bdc0e 100644
--- a/kotsadm/pkg/snapshot/store.go
+++ b/kotsadm/pkg/snapshot/store.go
@@ -4,7 +4,6 @@ import (
 	"bufio"
 	"bytes"
 	"context"
-	"fmt"
 	"strings"
 	"time"
 
@@ -154,18 +153,6 @@ func UpdateGlobalStore(store *types.Store) (*velerov1.BackupStorageLocation, err
 		kotsadmVeleroBackendStorageLocation.Spec.Config["s3Url"] = store.Other.Endpoint
 
 		// create or update the secret
-	} else if store.Internal != nil {
-		kotsadmVeleroBackendStorageLocation.Spec.Config["region"] = store.Internal.Region
-		kotsadmVeleroBackendStorageLocation.Spec.Config["s3Url"] = store.Internal.Endpoint
-		kotsadmVeleroBackendStorageLocation.Spec.Config["publicUrl"] = fmt.Sprintf("http://%s", store.Internal.ObjectStoreClusterIP)
-
-		// delete the secret
-		if currentSecretErr == nil {
-			err = clientset.CoreV1().Secrets(kotsadmVeleroBackendStorageLocation.Namespace).Delete(context.TODO(), "cloud-credentials", metav1.DeleteOptions{})
-			if err != nil {
-				return nil, errors.Wrap(err, "failed to delete internal secret")
-			}
-		}
 	} else if store.Google != nil {
 		if store.Google.UseInstanceRole {
 			kotsadmVeleroBackendStorageLocation.Spec.Config["serviceAccount"] = store.Google.ServiceAccount
@@ -198,7 +185,7 @@ func UpdateGlobalStore(store *types.Store) (*velerov1.BackupStorageLocation, err
 				}
 				_, err = clientset.CoreV1().Secrets(kotsadmVeleroBackendStorageLocation.Namespace).Create(context.TODO(), &toCreate, metav1.CreateOptions{})
 				if err != nil {
-					return nil, errors.Wrap(err, "failed to create google secret")
+					return nil, errors.Wrap(err, "failed to create aws secret")
 				}
 			} else {
 				// update
@@ -209,7 +196,7 @@ func UpdateGlobalStore(store *types.Store) (*velerov1.BackupStorageLocation, err
 				currentSecret.Data["cloud"] = []byte(store.Google.JSONFile)
 				_, err = clientset.CoreV1().Secrets(kotsadmVeleroBackendStorageLocation.Namespace).Update(context.TODO(), currentSecret, metav1.UpdateOptions{})
 				if err != nil {
-					return nil, errors.Wrap(err, "failed to update google secret")
+					return nil, errors.Wrap(err, "failed to update aws secret")
 				}
 			}
 		}
@@ -245,7 +232,7 @@ func UpdateGlobalStore(store *types.Store) (*velerov1.BackupStorageLocation, err
 			}
 			_, err = clientset.CoreV1().Secrets(kotsadmVeleroBackendStorageLocation.Namespace).Create(context.TODO(), &toCreate, metav1.CreateOptions{})
 			if err != nil {
-				return nil, errors.Wrap(err, "failed to create azure secret")
+				return nil, errors.Wrap(err, "failed to create aws secret")
 			}
 		} else {
 			// update
@@ -256,7 +243,7 @@ func UpdateGlobalStore(store *types.Store) (*velerov1.BackupStorageLocation, err
 			currentSecret.Data["cloud"] = providers.RenderAzureConfig(config)
 			_, err = clientset.CoreV1().Secrets(kotsadmVeleroBackendStorageLocation.Namespace).Update(context.TODO(), currentSecret, metav1.UpdateOptions{})
 			if err != nil {
-				return nil, errors.Wrap(err, "failed to update azure secret")
+				return nil, errors.Wrap(err, "failed to update aws secret")
 			}
 		}
 	}
@@ -469,13 +456,6 @@ func ValidateStore(store *types.Store) error {
 		return nil
 	}
 
-	if store.Internal != nil {
-		if err := validateInternal(store.Internal, store.Bucket); err != nil {
-			return errors.Wrap(err, "failed to validate S3-compatible configuration")
-		}
-		return nil
-	}
-
 	return errors.New("no valid configuration found")
 }
 
@@ -627,32 +607,6 @@ func validateOther(storeOther *types.StoreOther, bucket string) error {
 	return nil
 }
 
-func validateInternal(storeInternal *types.StoreInternal, bucket string) error {
-	s3Config := &aws.Config{
-		Region:           aws.String(storeInternal.Region),
-		Endpoint:         aws.String(storeInternal.Endpoint),
-		DisableSSL:       aws.Bool(true), // TODO: this needs to be configurable
-		S3ForcePathStyle: aws.Bool(true),
-	}
-
-	if storeInternal.AccessKeyID != "" && storeInternal.SecretAccessKey != "" {
-		s3Config.Credentials = credentials.NewStaticCredentials(storeInternal.AccessKeyID, storeInternal.SecretAccessKey, "")
-	}
-
-	newSession := session.New(s3Config)
-	s3Client := s3.New(newSession)
-
-	_, err := s3Client.HeadBucket(&s3.HeadBucketInput{
-		Bucket: aws.String(bucket),
-	})
-
-	if err != nil {
-		return errors.Wrap(err, "bucket does not exist")
-	}
-
-	return nil
-}
-
 func Redact(store *types.Store) error {
 	if store == nil {
 		return nil
diff --git a/kotsadm/pkg/snapshot/types/types.go b/kotsadm/pkg/snapshot/types/types.go
index 7659f3d83..7b0b2f9ec 100644
--- a/kotsadm/pkg/snapshot/types/types.go
+++ b/kotsadm/pkg/snapshot/types/types.go
@@ -32,23 +32,14 @@ type StoreOther struct {
 	Endpoint        string `json:"endpoint"`
 }
 
-type StoreInternal struct {
-	Region               string `json:"region"`
-	AccessKeyID          string `json:"accessKeyID"`
-	SecretAccessKey      string `json:"secretAccessKey"` // added for unmarshaling, redacted on marshaling
-	Endpoint             string `json:"endpoint"`
-	ObjectStoreClusterIP string `json:"objectStoreClusterIP"`
-}
-
 type Store struct {
-	Provider string         `json:"provider"`
-	Bucket   string         `json:"bucket"`
-	Path     string         `json:"path"`
-	AWS      *StoreAWS      `json:"aws,omitempty"`
-	Azure    *StoreAzure    `json:"azure,omitempty"`
-	Google   *StoreGoogle   `json:"gcp,omitempty"`
-	Other    *StoreOther    `json:"other,omitempty"`
-	Internal *StoreInternal `json:"internal,omitempty"`
+	Provider string       `json:"provider"`
+	Bucket   string       `json:"bucket"`
+	Path     string       `json:"path"`
+	AWS      *StoreAWS    `json:"aws,omitempty"`
+	Azure    *StoreAzure  `json:"azure,omitempty"`
+	Google   *StoreGoogle `json:"gcp,omitempty"`
+	Other    *StoreOther  `json:"other,omitempty"`
 }
 
 type Backup struct {
diff --git a/kotsadm/web/src/components/AirgapUploadProgress.jsx b/kotsadm/web/src/components/AirgapUploadProgress.jsx
index b1f510e4b..3320206d2 100644
--- a/kotsadm/web/src/components/AirgapUploadProgress.jsx
+++ b/kotsadm/web/src/components/AirgapUploadProgress.jsx
@@ -84,13 +84,16 @@ class AirgapUploadProgress extends React.Component {
     } catch {
       // empty
     }
-
+    
     let statusDiv = (
       <div
-        className={`u-marginTop--20 u-color--dustyGray u-fontWeight--medium u-lineHeight--medium u-textAlign--center`}
+        className={`u-marginTop--20 u-fontWeight--medium u-lineHeight--medium u-textAlign--center`}
       >
-        <p className="u-marginBottom--5">{statusMsg}</p>
-        <p>This may take a while depending on your network connection and size of your bundle</p>
+        <div className="flex flex1 u-marginBottom--10 justifyContent--center alignItems--center u-color--tundora">
+          {statusMsg && <Loader className="flex u-marginRight--5" size="24" />}
+          <p>{statusMsg}</p>
+        </div>
+        <p className="u-color--dustyGray">This may take a while depending on your network connection and size of your bundle</p>
       </div>
     );
 
diff --git a/kotsadm/web/src/components/snapshots/SnapshotStorageDestination.jsx b/kotsadm/web/src/components/snapshots/SnapshotStorageDestination.jsx
index 043ab8809..051f56c57 100644
--- a/kotsadm/web/src/components/snapshots/SnapshotStorageDestination.jsx
+++ b/kotsadm/web/src/components/snapshots/SnapshotStorageDestination.jsx
@@ -297,9 +297,6 @@ class SnapshotStorageDestination extends Component {
       case "other":
         await this.snapshotProviderS3Compatible();
         break;
-      case "internal":
-        await this.snapshotProviderInternal();
-        break;
     }
   }
 
@@ -331,11 +328,6 @@ class SnapshotStorageDestination extends Component {
     this.props.updateSettings(payload);
   }
 
-  snapshotProviderInternal = async () => {
-    const payload = { internal: true };
-    this.props.updateSettings(payload);
-  }
-
   renderIcons = (destination) => {
     if (destination) {
       return <span className={`icon snapshotDestination--${destination.value}`} />;
@@ -347,7 +339,7 @@ class SnapshotStorageDestination extends Component {
   getDestinationLabel = (destination, label) => {
     return (
       <div style={{ alignItems: "center", display: "flex" }}>
-        <span style={{ fontSize: 18, marginRight: "10px", minWidth: 16, textAlign: "center" }}>{this.renderIcons(destination)}</span>
+        <span style={{ fontSize: 18, marginRight: "10px" }}>{this.renderIcons(destination)}</span>
         <span style={{ fontSize: 14, lineHeight: "16px" }}>{label}</span>
       </div>
     );
@@ -578,11 +570,6 @@ class SnapshotStorageDestination extends Component {
           </div>
         )
 
-      case "internal":
-        return (
-          null
-        )
-
       default:
         return (
           <div>No snapshot destination is selected</div>
@@ -615,7 +602,7 @@ class SnapshotStorageDestination extends Component {
             if (snapshotSettings.isKurl) {
               availableDestinations.push({
                 value: "internal",
-                label: "Internal Storage (Default)",
+                label: "Internal Storage",
               });
             }
             break;
diff --git a/kotsadm/web/src/scss/utilities/icons.scss b/kotsadm/web/src/scss/utilities/icons.scss
index 189cce155..e76cb91bd 100644
--- a/kotsadm/web/src/scss/utilities/icons.scss
+++ b/kotsadm/web/src/scss/utilities/icons.scss
@@ -595,11 +595,6 @@
   width: 16px;
   height: 16px;
 }
-.icon.snapshotDestination--internal {
-  background-position: -182px -378px;
-  width: 16px;
-  height: 16px;
-}
 .icon.awsIcon {
   background-position: -185px -725px;
   width: 27px;
diff --git a/kotskinds/apis/kots/v1beta1/config_types.go b/kotskinds/apis/kots/v1beta1/config_types.go
index e4b014057..c682b3c89 100644
--- a/kotskinds/apis/kots/v1beta1/config_types.go
+++ b/kotskinds/apis/kots/v1beta1/config_types.go
@@ -60,7 +60,6 @@ type ConfigGroup struct {
 	Name        string       `json:"name"`
 	Title       string       `json:"title"`
 	Description string       `json:"description,omitempty"`
-	When        string       `json:"when,omitempty"`
 	Items       []ConfigItem `json:"items,omitempty"`
 }
 
diff --git a/pkg/kotsadm/api_objects.go b/pkg/kotsadm/api_objects.go
index c450da243..6c45633f0 100644
--- a/pkg/kotsadm/api_objects.go
+++ b/pkg/kotsadm/api_objects.go
@@ -183,7 +183,8 @@ func updateApiDeployment(deployment *appsv1.Deployment, deployOptions types.Depl
 		return errors.New("failed to find kotsadm-api container in deployment")
 	}
 
-	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm-api:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions))
+	// image
+	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm-api:%s", kotsadmRegistry(), kotsadmTag())
 
 	// copy the env vars from the desired to existing. this could undo a change that the user had.
 	// we don't know which env vars we set and which are user edited. this method avoids deleting
@@ -217,15 +218,6 @@ func apiDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 		}
 	}
 
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	deployment := &appsv1.Deployment{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "apps/v1",
@@ -252,10 +244,9 @@ func apiDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 					SecurityContext:    &securityContext,
 					ServiceAccountName: "kotsadm-api",
 					RestartPolicy:      corev1.RestartPolicyAlways,
-					ImagePullSecrets:   pullSecrets,
 					Containers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/kotsadm-api:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm-api:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "kotsadm-api",
 							Ports: []corev1.ContainerPort{
diff --git a/pkg/kotsadm/kotsadm_objects.go b/pkg/kotsadm/kotsadm_objects.go
index 66ea6465a..949ea228f 100644
--- a/pkg/kotsadm/kotsadm_objects.go
+++ b/pkg/kotsadm/kotsadm_objects.go
@@ -170,7 +170,7 @@ func updateKotsadmDeployment(deployment *appsv1.Deployment, deployOptions types.
 	}
 
 	// image
-	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions))
+	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(), kotsadmTag())
 
 	// copy the env vars from the desired to existing. this could undo a change that the user had.
 	// we don't know which env vars we set and which are user edited. this method avoids deleting
@@ -205,14 +205,6 @@ func kotsadmDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 	}
 
 	backupSize := resource.MustParse("1Gi")
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
 
 	deployment := &appsv1.Deployment{
 		TypeMeta: metav1.TypeMeta{
@@ -257,10 +249,9 @@ func kotsadmDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 					},
 					ServiceAccountName: "kotsadm",
 					RestartPolicy:      corev1.RestartPolicyAlways,
-					ImagePullSecrets:   pullSecrets,
 					InitContainers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "restore-db",
 							Command: []string{
@@ -287,7 +278,7 @@ func kotsadmDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 							},
 						},
 						{
-							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "restore-s3",
 							Command: []string{
@@ -339,7 +330,7 @@ func kotsadmDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 					},
 					Containers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "kotsadm",
 							Ports: []corev1.ContainerPort{
diff --git a/pkg/kotsadm/kotsadm_version.go b/pkg/kotsadm/kotsadm_version.go
index 27717c5a4..6dc36f0d7 100644
--- a/pkg/kotsadm/kotsadm_version.go
+++ b/pkg/kotsadm/kotsadm_version.go
@@ -5,20 +5,25 @@ import (
 	"strings"
 
 	"github.com/Masterminds/semver"
-	"github.com/replicatedhq/kots/pkg/docker/registry"
-	"github.com/replicatedhq/kots/pkg/kotsadm/types"
 	"github.com/replicatedhq/kots/pkg/version"
-	corev1 "k8s.io/api/core/v1"
+)
+
+var (
+	OverrideVersion   = ""
+	OverrideRegistry  = ""
+	OverrideNamespace = ""
 )
 
 // return "alpha" for all invalid versions of kots,
 // kotsadm tag that matches this version for others
-func kotsadmTag(options types.KotsadmOptions) string {
-	if options.OverrideVersion != "" {
-		return options.OverrideVersion
+func kotsadmTag() string {
+	if OverrideVersion != "" {
+		return OverrideVersion
 	}
 
-	return kotsadmTagForVersionString(version.Version())
+	kotsVersion := version.Version()
+
+	return kotsadmTagForVersionString(kotsVersion)
 }
 
 func kotsadmTagForVersionString(kotsVersion string) string {
@@ -38,44 +43,18 @@ func kotsadmTagForVersionString(kotsVersion string) string {
 	return kotsVersion
 }
 
-func kotsadmRegistry(options types.KotsadmOptions) string {
-	if options.OverrideRegistry == "" {
-		if options.OverrideNamespace == "" {
+func kotsadmRegistry() string {
+	if OverrideRegistry == "" {
+		if OverrideNamespace == "" {
 			return "kotsadm"
 		} else {
-			return options.OverrideNamespace
+			return OverrideNamespace
 		}
 	}
 
-	registry := options.OverrideRegistry
-	namespace := options.OverrideNamespace
-
-	hostParts := strings.Split(options.OverrideRegistry, "/")
-	if len(hostParts) == 2 {
-		registry = hostParts[0]
-		namespace = hostParts[1]
+	if OverrideNamespace == "" {
+		return fmt.Sprintf("%s/kotsadm", OverrideRegistry)
 	}
 
-	if namespace == "" {
-		// note that this makes it impossible to have a registry without a namespace
-		// keeping for backwards compatibility
-		return fmt.Sprintf("%s/kotsadm", registry)
-	}
-
-	return fmt.Sprintf("%s/%s", registry, namespace)
-}
-
-func kotsadmPullSecret(namespace string, options types.KotsadmOptions) *corev1.Secret {
-	if options.OverrideRegistry == "" || options.Username == "" || options.Password == "" {
-		return nil
-	}
-
-	secret, _ := registry.PullSecretForRegistries([]string{options.OverrideRegistry}, options.Username, options.Password, namespace)
-	if secret == nil {
-		return nil
-	}
-
-	secret.ObjectMeta.Name = types.PrivateKotsadmRegistrySecret
-
-	return secret
+	return fmt.Sprintf("%s/%s", OverrideRegistry, OverrideNamespace)
 }
diff --git a/pkg/kotsadm/main.go b/pkg/kotsadm/main.go
index 279af7b6b..bb3e393bf 100644
--- a/pkg/kotsadm/main.go
+++ b/pkg/kotsadm/main.go
@@ -343,10 +343,6 @@ func ensureKotsadm(deployOptions types.DeployOptions, clientset *kubernetes.Clie
 		}
 	}
 
-	if err := ensureKotsadmPullSecrets(&deployOptions, clientset); err != nil {
-		return errors.Wrap(err, "failed to ensure postgres")
-	}
-
 	if err := ensurePostgres(deployOptions, clientset); err != nil {
 		return errors.Wrap(err, "failed to ensure postgres")
 	}
diff --git a/pkg/kotsadm/minio_objects.go b/pkg/kotsadm/minio_objects.go
index d6790ab59..be0eed1f4 100644
--- a/pkg/kotsadm/minio_objects.go
+++ b/pkg/kotsadm/minio_objects.go
@@ -51,15 +51,6 @@ func minioStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet {
 		}
 	}
 
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	statefulset := &appsv1.StatefulSet{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "apps/v1",
@@ -108,8 +99,7 @@ func minioStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet {
 					},
 				},
 				Spec: corev1.PodSpec{
-					SecurityContext:  &securityContext,
-					ImagePullSecrets: pullSecrets,
+					SecurityContext: &securityContext,
 					Volumes: []corev1.Volume{
 						{
 							Name: "kotsadm-minio",
@@ -128,7 +118,7 @@ func minioStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet {
 					},
 					Containers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/minio:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/minio:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullIfNotPresent,
 							Name:            "kotsadm-minio",
 							Command: []string{
diff --git a/pkg/kotsadm/operator_objects.go b/pkg/kotsadm/operator_objects.go
index d57a59cc1..8647c6aaf 100644
--- a/pkg/kotsadm/operator_objects.go
+++ b/pkg/kotsadm/operator_objects.go
@@ -164,7 +164,7 @@ func updateOperatorDeployment(deployment *appsv1.Deployment, deployOptions types
 	}
 
 	// image
-	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm-operator:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions))
+	deployment.Spec.Template.Spec.Containers[containerIdx].Image = fmt.Sprintf("%s/kotsadm-operator:%s", kotsadmRegistry(), kotsadmTag())
 
 	// copy the env vars from the desired to existing. this could undo a change that the user had.
 	// we don't know which env vars we set and which are user edited. this method avoids deleting
@@ -198,15 +198,6 @@ func operatorDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 		}
 	}
 
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	deployment := &appsv1.Deployment{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "apps/v1",
@@ -233,10 +224,9 @@ func operatorDeployment(deployOptions types.DeployOptions) *appsv1.Deployment {
 					SecurityContext:    &securityContext,
 					ServiceAccountName: "kotsadm-operator",
 					RestartPolicy:      corev1.RestartPolicyAlways,
-					ImagePullSecrets:   pullSecrets,
 					Containers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/kotsadm-operator:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm-operator:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "kotsadm-operator",
 							Env: []corev1.EnvVar{
diff --git a/pkg/kotsadm/postgres_objects.go b/pkg/kotsadm/postgres_objects.go
index 627048a28..d528a2159 100644
--- a/pkg/kotsadm/postgres_objects.go
+++ b/pkg/kotsadm/postgres_objects.go
@@ -1,7 +1,6 @@
 package kotsadm
 
 import (
-	"fmt"
 	"os"
 
 	"github.com/replicatedhq/kots/pkg/kotsadm/types"
@@ -16,17 +15,6 @@ import (
 func postgresStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet {
 	size := resource.MustParse("1Gi")
 
-	image := "postgres:10.7"
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		image = fmt.Sprintf("%s/postgres:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions))
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	if deployOptions.LimitRange != nil {
 		var allowedMax *resource.Quantity
 		var allowedMin *resource.Quantity
@@ -102,8 +90,7 @@ func postgresStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet
 					}),
 				},
 				Spec: corev1.PodSpec{
-					SecurityContext:  &securityContext,
-					ImagePullSecrets: pullSecrets,
+					SecurityContext: &securityContext,
 					Volumes: []corev1.Volume{
 						{
 							Name: "kotsadm-postgres",
@@ -116,7 +103,7 @@ func postgresStatefulset(deployOptions types.DeployOptions) *appsv1.StatefulSet
 					},
 					Containers: []corev1.Container{
 						{
-							Image:           image,
+							Image:           "postgres:10.7",
 							ImagePullPolicy: corev1.PullIfNotPresent,
 							Name:            "kotsadm-postgres",
 							Ports: []corev1.ContainerPort{
diff --git a/pkg/kotsadm/restore_job.go b/pkg/kotsadm/restore_job.go
index a93e07163..2a0a6da4b 100644
--- a/pkg/kotsadm/restore_job.go
+++ b/pkg/kotsadm/restore_job.go
@@ -11,7 +11,6 @@ import (
 )
 
 func restoreJob(backupName string, namespace string, isOpenShift bool) *batchv1.Job {
-	deployOptions := types.DeployOptions{} // TODO: make this real
 	var securityContext corev1.PodSecurityContext
 	if !isOpenShift {
 		securityContext = corev1.PodSecurityContext{
@@ -20,15 +19,6 @@ func restoreJob(backupName string, namespace string, isOpenShift bool) *batchv1.
 		}
 	}
 
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	job := &batchv1.Job{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "batch/v1",
@@ -50,10 +40,9 @@ func restoreJob(backupName string, namespace string, isOpenShift bool) *batchv1.
 					SecurityContext:    &securityContext,
 					RestartPolicy:      corev1.RestartPolicyNever,
 					ServiceAccountName: "kotsadm",
-					ImagePullSecrets:   pullSecrets,
 					Containers: []corev1.Container{
 						{
-							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+							Image:           fmt.Sprintf("%s/kotsadm:%s", kotsadmRegistry(), kotsadmTag()),
 							ImagePullPolicy: corev1.PullAlways,
 							Name:            "kotsadm-restore",
 							Command: []string{
diff --git a/pkg/kotsadm/schemahero_objects.go b/pkg/kotsadm/schemahero_objects.go
index 7591edcdb..3d7ddf909 100644
--- a/pkg/kotsadm/schemahero_objects.go
+++ b/pkg/kotsadm/schemahero_objects.go
@@ -21,15 +21,6 @@ func migrationsPod(deployOptions types.DeployOptions) *corev1.Pod {
 		}
 	}
 
-	var pullSecrets []corev1.LocalObjectReference
-	if s := kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil {
-		pullSecrets = []corev1.LocalObjectReference{
-			{
-				Name: s.ObjectMeta.Name,
-			},
-		}
-	}
-
 	pod := &corev1.Pod{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: "v1",
@@ -41,12 +32,11 @@ func migrationsPod(deployOptions types.DeployOptions) *corev1.Pod {
 			Labels:    types.GetKotsadmLabels(),
 		},
 		Spec: corev1.PodSpec{
-			SecurityContext:  &securityContext,
-			RestartPolicy:    corev1.RestartPolicyOnFailure,
-			ImagePullSecrets: pullSecrets,
+			SecurityContext: &securityContext,
+			RestartPolicy:   corev1.RestartPolicyOnFailure,
 			Containers: []corev1.Container{
 				{
-					Image:           fmt.Sprintf("%s/kotsadm-migrations:%s", kotsadmRegistry(deployOptions.KotsadmOptions), kotsadmTag(deployOptions.KotsadmOptions)),
+					Image:           fmt.Sprintf("%s/kotsadm-migrations:%s", kotsadmRegistry(), kotsadmTag()),
 					ImagePullPolicy: corev1.PullAlways,
 					Name:            name,
 					Env: []corev1.EnvVar{
diff --git a/pkg/kotsadm/secrets.go b/pkg/kotsadm/secrets.go
index 864c3ced4..b994039bd 100644
--- a/pkg/kotsadm/secrets.go
+++ b/pkg/kotsadm/secrets.go
@@ -73,32 +73,15 @@ func getSecretsYAML(deployOptions *types.DeployOptions) (map[string][]byte, erro
 	}
 	docs["secret-s3.yaml"] = s3.Bytes()
 
-	var tokenSecret bytes.Buffer
-	if err := s.Encode(apiClusterTokenSecret(*deployOptions), &tokenSecret); err != nil {
+	var secret bytes.Buffer
+	if err := s.Encode(apiClusterTokenSecret(*deployOptions), &secret); err != nil {
 		return nil, errors.Wrap(err, "failed to marshal api cluster token secret")
 	}
-	docs["secret-api-cluster-token.yaml"] = tokenSecret.Bytes()
-
-	// this secret is optional
-	if secret := privateKotsadmRegistrySecret(*deployOptions); secret != nil {
-		var registrySecret bytes.Buffer
-		if err := s.Encode(secret, &registrySecret); err != nil {
-			return nil, errors.Wrap(err, "failed to marshal private kotsadm registry secret")
-		}
-		docs["private-kotsadm-registry-secret.yaml"] = registrySecret.Bytes()
-	}
+	docs["secret-api-cluster-token.yaml"] = secret.Bytes()
 
 	return docs, nil
 }
 
-func ensureKotsadmPullSecrets(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error {
-	if err := ensurePrivateKotsadmRegistrySecret(*deployOptions, clientset); err != nil {
-		return errors.Wrap(err, "failed to ensure private kotsadm registry secret")
-	}
-
-	return nil
-}
-
 func ensureSecrets(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error {
 	if err := ensureJWTSessionSecret(deployOptions.Namespace, clientset); err != nil {
 		return errors.Wrap(err, "failed to ensure jwt session secret")
@@ -345,7 +328,7 @@ func ensureAPIClusterTokenSecret(deployOptions types.DeployOptions, clientset *k
 
 		_, err := clientset.CoreV1().Secrets(deployOptions.Namespace).Create(context.TODO(), apiClusterTokenSecret(deployOptions), metav1.CreateOptions{})
 		if err != nil {
-			return errors.Wrap(err, "failed to create cluster token secret")
+			return errors.Wrap(err, "Failed to create cluster token secret")
 		}
 	}
 
@@ -371,24 +354,3 @@ func getAPIClusterToken(namespace string, clientset *kubernetes.Clientset) (stri
 
 	return string(tokenBytes), nil
 }
-
-func ensurePrivateKotsadmRegistrySecret(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error {
-	_, err := clientset.CoreV1().Secrets(deployOptions.Namespace).Get(context.TODO(), types.PrivateKotsadmRegistrySecret, metav1.GetOptions{})
-	if err != nil {
-		if !kuberneteserrors.IsNotFound(err) {
-			return errors.Wrap(err, "failed to get existing private kotsadm registry secret")
-		}
-
-		secret := privateKotsadmRegistrySecret(deployOptions)
-		if secret == nil {
-			return nil
-		}
-
-		_, err := clientset.CoreV1().Secrets(deployOptions.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
-		if err != nil {
-			return errors.Wrap(err, "failed to create private kotsadm registry secret")
-		}
-	}
-
-	return nil
-}
diff --git a/pkg/kotsadm/secrets_objects.go b/pkg/kotsadm/secrets_objects.go
index 21e2ddbbd..007d59679 100644
--- a/pkg/kotsadm/secrets_objects.go
+++ b/pkg/kotsadm/secrets_objects.go
@@ -130,7 +130,3 @@ func apiClusterTokenSecret(deployOptions types.DeployOptions) *corev1.Secret {
 		},
 	}
 }
-
-func privateKotsadmRegistrySecret(deployOptions types.DeployOptions) *corev1.Secret {
-	return kotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions)
-}
diff --git a/pkg/kotsadm/types/constants.go b/pkg/kotsadm/types/constants.go
index 222ec0d37..9a95e71bc 100644
--- a/pkg/kotsadm/types/constants.go
+++ b/pkg/kotsadm/types/constants.go
@@ -4,7 +4,6 @@ const KotsadmKey = "kots.io/kotsadm"
 const KotsadmLabelValue = "true"
 
 const ClusterTokenSecret = "kotsadm-cluster-token"
-const PrivateKotsadmRegistrySecret = "kotsadm-private-registry"
 
 const VeleroKey = "kots.io/backup-type"
 const VeleroLabelConsoleValue = "admin-console"
diff --git a/pkg/kotsadm/types/deployoptions.go b/pkg/kotsadm/types/deployoptions.go
index 44e30b8e4..aa86d6635 100644
--- a/pkg/kotsadm/types/deployoptions.go
+++ b/pkg/kotsadm/types/deployoptions.go
@@ -32,6 +32,4 @@ type DeployOptions struct {
 	IncludeMinio              bool
 	IncludeDockerDistribution bool
 	Timeout                   time.Duration
-
-	KotsadmOptions KotsadmOptions
 }
diff --git a/pkg/kotsadm/types/registryoptions.go b/pkg/kotsadm/types/registryoptions.go
deleted file mode 100644
index 91653afac..000000000
--- a/pkg/kotsadm/types/registryoptions.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package types
-
-type KotsadmOptions struct {
-	OverrideVersion   string
-	OverrideRegistry  string
-	OverrideNamespace string
-	Username          string
-	Password          string
-}
diff --git a/pkg/kotsadm/types/upgradeoptions.go b/pkg/kotsadm/types/upgradeoptions.go
index b3c3993b4..fcd59b5d9 100644
--- a/pkg/kotsadm/types/upgradeoptions.go
+++ b/pkg/kotsadm/types/upgradeoptions.go
@@ -11,6 +11,4 @@ type UpgradeOptions struct {
 	KubernetesConfigFlags *genericclioptions.ConfigFlags
 	ForceUpgradeKurl      bool
 	Timeout               time.Duration
-
-	KotsadmOptions KotsadmOptions
 }


Test patch:
diff --git a/pkg/kotsadm/kotsad_version_test.go b/pkg/kotsadm/kotsad_version_test.go
index 148912b6f..c1e6bba14 100644
--- a/pkg/kotsadm/kotsad_version_test.go
+++ b/pkg/kotsadm/kotsad_version_test.go
@@ -3,7 +3,6 @@ package kotsadm
 import (
 	"testing"
 
-	"github.com/replicatedhq/kots/pkg/kotsadm/types"
 	"github.com/stretchr/testify/assert"
 	"go.undefinedlabs.com/scopeagent"
 )
@@ -37,14 +36,11 @@ func Test_kotsadmRegistry(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			scopetest := scopeagent.StartTest(t)
 			defer scopetest.End()
+			OverrideVersion = test.overrideVersion
+			OverrideRegistry = test.overrideRegistry
+			OverrideNamespace = test.overrideNamespace
 
-			options := types.KotsadmOptions{
-				OverrideVersion:   test.overrideVersion,
-				OverrideRegistry:  test.overrideRegistry,
-				OverrideNamespace: test.overrideNamespace,
-			}
-
-			actual := kotsadmRegistry(options)
+			actual := kotsadmRegistry()
 			assert.Equal(t, test.expected, actual)
 		})
 	}