diff --git a/docs/upgrading.rst b/docs/upgrading.rst
index fed8c7e95a887d6bf9acdac6df155c8035b8e928..091b9fafe2a468398432e88b6aca4e6f2df0846f 100644
--- a/docs/upgrading.rst
+++ b/docs/upgrading.rst
@@ -58,7 +58,8 @@ these applications form the script manually.
    # Execute the upgrade preparation script
    ./rename-to-stackspin.sh
 
-After this, you need to manually re-install the applications by running
+After this, you need to update secrets and Flux in the cluster by running
+``install/install-stackspin.sh``. Then re-install applications by running
 ``install/install-app.sh <app>`` from the Stackspin repository. See the
 application specific upgrade guides below.
 
diff --git a/install/generate_secrets.py b/install/generate_secrets.py
index bf6cf0e013fa225ba6afb3c40e1690c64c8b33b9..6ff53ac011cc29c9e4142f3d15812ffff1f9a27c 100644
--- a/install/generate_secrets.py
+++ b/install/generate_secrets.py
@@ -56,14 +56,17 @@ def create_variables_secret(app_name, env):
         with open(variables_filename) as template_file:
             lines = template_file.read()
             secret_name, secret_namespace = get_secret_metadata(lines)
-            if get_kubernetes_secret(secret_name, secret_namespace) is None:
-                print(f"Adding secret {secret_name} in namespace"
-                      f" {secret_namespace} to cluster.")
-                template = env.from_string(lines)
-                store_kubernetes_secret(template.render(), secret_namespace)
-            else:
+            new_secret_dict = yaml.safe_load(env.from_string(lines).render())
+            current_secret_data = get_kubernetes_secret_data(secret_name,
+                    secret_namespace)
+            if current_secret_data is not None:
                 print(f"Secret {secret_name} in namespace {secret_namespace}"
-                      " already exists. Not generating new secrets.")
+                      " already exists. Merging...")
+                # Merge dicts. Values from current_secret_data take precedence
+                new_secret_dict['data'] |= current_secret_data
+            print(f"Storing secret {secret_name} in namespace"
+                  f" {secret_namespace} in cluster.")
+            store_kubernetes_secret(new_secret_dict, secret_namespace)
     else:
         print(f'File {variables_filename} does not exist.')
 
@@ -77,7 +80,7 @@ def create_basic_auth_secret(app_name, env):
             lines = template_file.read()
             secret_name, secret_namespace = get_secret_metadata(lines)
 
-            if get_kubernetes_secret(secret_name, secret_namespace) is None:
+            if get_kubernetes_secret_data(secret_name, secret_namespace) is None:
                 basic_auth_username = 'admin'
                 basic_auth_password = generate_password(32)
                 basic_auth_htpasswd = gen_htpasswd(
@@ -91,7 +94,8 @@ def create_basic_auth_secret(app_name, env):
                             'pass': basic_auth_password,
                             'htpasswd': basic_auth_htpasswd
                 })
-                store_kubernetes_secret(template.render(), secret_namespace)
+                secret_dict = yaml.safe_load(template.render())
+                store_kubernetes_secret(secret_dict, secret_namespace)
             else:
                 print(f"Secret {secret_name} in namespace {secret_namespace}"
                       " already exists. Not generating new secrets.")
@@ -100,18 +104,18 @@ def create_basic_auth_secret(app_name, env):
 
 def get_secret_metadata(yaml_string):
     """Returns secret name and namespace from metadata field in a yaml string"""
-    secret_info = yaml.safe_load(yaml_string)
-    secret_name = secret_info['metadata']['name']
+    secret_dict = yaml.safe_load(yaml_string)
+    secret_name = secret_dict['metadata']['name']
     # default namespace is flux-system, but other namespace can be
     # provided in secret metadata
-    if 'namespace' in secret_info['metadata']:
-        secret_namespace = secret_info['metadata']['namespace']
+    if 'namespace' in secret_dict['metadata']:
+        secret_namespace = secret_dict['metadata']['namespace']
     else:
         secret_namespace = 'flux-system'
     return secret_name, secret_namespace
 
 
-def get_kubernetes_secret(secret_name, namespace):
+def get_kubernetes_secret_data(secret_name, namespace):
     """Returns the contents of a kubernetes secret or None if the secret does not exist."""
     try:
         secret = API.read_namespaced_secret(secret_name, namespace).data
@@ -122,13 +126,12 @@ def get_kubernetes_secret(secret_name, namespace):
         return None
     return secret
 
-def store_kubernetes_secret(secret_string, namespace):
+def store_kubernetes_secret(secret_dict, namespace):
     """Converts secret_string into a yaml object and adds it to the cluster"""
-    secret_yaml = yaml.safe_load(secret_string)
     api_client = client.api_client.ApiClient()
     api_response = create_from_yaml(
             api_client,
-            yaml_objects=[secret_yaml],
+            yaml_objects=[secret_dict],
             namespace=namespace)
     print(f"Secret created with api response: {api_response}")