diff --git a/inventory/sample/group_vars/all/all.yml b/inventory/sample/group_vars/all/all.yml
index c43d3a54c7a1f2b9ecacc94ab5379a07ae100f51..5b0ca479f91905a2f8749a1cf8ab37af9425537a 100644
--- a/inventory/sample/group_vars/all/all.yml
+++ b/inventory/sample/group_vars/all/all.yml
@@ -130,3 +130,6 @@ ntp_servers:
   - "1.pool.ntp.org iburst"
   - "2.pool.ntp.org iburst"
   - "3.pool.ntp.org iburst"
+
+## Used to control no_log attribute
+unsafe_show_logs: false
diff --git a/roles/bootstrap-os/defaults/main.yml b/roles/bootstrap-os/defaults/main.yml
index e9f33b670cdb117e37ed1eba4d4ca2e8d9e1d029..9b31456ff5d4e0d75eaf25053755c573bca1c372 100644
--- a/roles/bootstrap-os/defaults/main.yml
+++ b/roles/bootstrap-os/defaults/main.yml
@@ -25,3 +25,8 @@ override_system_hostname: true
 is_fedora_coreos: false
 
 skip_http_proxy_on_os_packages: false
+
+# If this is true, debug information will be displayed but
+# may contain some private data, so it is recommended to set it to false
+# in the production environment.
+unsafe_show_logs: false
diff --git a/roles/bootstrap-os/tasks/bootstrap-redhat.yml b/roles/bootstrap-os/tasks/bootstrap-redhat.yml
index 4a9913fe86e3bfbc7ff605bd83cc32f02f1d47ae..8f323882c7b2b74a919d575ff7525b4c561d759c 100644
--- a/roles/bootstrap-os/tasks/bootstrap-redhat.yml
+++ b/roles/bootstrap-os/tasks/bootstrap-redhat.yml
@@ -65,7 +65,7 @@
   notify: RHEL auto-attach subscription
   ignore_errors: true  # noqa ignore-errors
   become: true
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
   when:
     - rh_subscription_username is defined
     - rh_subscription_status.changed
diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml
index c444585563838463bf177e4e1e9f67b646a05db9..57bd2126d334edaae62cf58c83ad1d773a4cc14c 100644
--- a/roles/download/defaults/main.yml
+++ b/roles/download/defaults/main.yml
@@ -2,6 +2,11 @@
 local_release_dir: /tmp/releases
 download_cache_dir: /tmp/kubespray_cache
 
+# If this is true, debug information will be displayed but
+# may contain some private data, so it is recommended to set it to false
+# in the production environment.
+unsafe_show_logs: false
+
 # do not delete remote cache files after using them
 # NOTE: Setting this parameter to TRUE is only really useful when developing kubespray
 download_keep_remote_cache: false
diff --git a/roles/download/tasks/download_file.yml b/roles/download/tasks/download_file.yml
index b6d3ad1b6bf79d013d9d89e73f55269f17aa1bdb..376a15e8a2a9f4e3b284697fc18c821cf8a54a17 100644
--- a/roles/download/tasks/download_file.yml
+++ b/roles/download/tasks/download_file.yml
@@ -67,7 +67,7 @@
     retries: 4
     delay: "{{ retry_stagger | default(5) }}"
     environment: "{{ proxy_env }}"
-    no_log: true
+    no_log: "{{ not (unsafe_show_logs|bool) }}"
     loop: "{{ download.mirrors | default([download.url]) }}"
     loop_control:
       loop_var: mirror
@@ -100,7 +100,7 @@
     retries: 4
     delay: "{{ retry_stagger | default(5) }}"
     environment: "{{ proxy_env }}"
-    no_log: true
+    no_log: "{{ not (unsafe_show_logs|bool) }}"
 
   - name: download_file | Copy file back to ansible host file cache
     synchronize:
diff --git a/roles/download/tasks/prep_download.yml b/roles/download/tasks/prep_download.yml
index 769d653daddf906435b7137d24746306dbcc06a7..9419f24aac9090fc4a3a449966ac5f2b82c7f333 100644
--- a/roles/download/tasks/prep_download.yml
+++ b/roles/download/tasks/prep_download.yml
@@ -58,7 +58,7 @@
 
 - name: prep_download | Register docker images info
   shell: "{{ image_info_command }}"  # noqa 305 image_info_command contains pipe therefore requires shell
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
   register: docker_images
   failed_when: false
   changed_when: false
diff --git a/roles/etcd/defaults/main.yml b/roles/etcd/defaults/main.yml
index 79ed16493aeff21087e52db7a828cdd52028d154..1f11e8ddcd600975e374bcd8bd12003b026d5e2b 100644
--- a/roles/etcd/defaults/main.yml
+++ b/roles/etcd/defaults/main.yml
@@ -115,3 +115,8 @@ etcd_retries: 4
 # ETCD 3.5.x issue
 # https://groups.google.com/a/kubernetes.io/g/dev/c/B7gJs88XtQc/m/rSgNOzV2BwAJ?utm_medium=email&utm_source=footer
 etcd_experimental_initial_corrupt_check: true
+
+# If this is true, debug information will be displayed but
+# may contain some private data, so it is recommended to set it to false
+# in the production environment.
+unsafe_show_logs: false
diff --git a/roles/etcd/tasks/gen_certs_script.yml b/roles/etcd/tasks/gen_certs_script.yml
index cf5580bb81cec954a4ecf78cbea5d5f227a5679a..fb619bdb0e2c6690c6a7cbd19649e3f7cd1fb00a 100644
--- a/roles/etcd/tasks/gen_certs_script.yml
+++ b/roles/etcd/tasks/gen_certs_script.yml
@@ -142,7 +142,7 @@
   args:
     executable: /bin/bash
     warn: false
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
   register: etcd_node_certs
   check_mode: no
   delegate_to: "{{ groups['etcd'][0] }}"
@@ -154,7 +154,7 @@
   shell: "set -o pipefail && base64 -d <<< '{{ etcd_node_certs.stdout|quote }}' | tar xz -C {{ etcd_cert_dir }}"
   args:
     executable: /bin/bash
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
   changed_when: false
   when: (('calico_rr' in groups and inventory_hostname in groups['calico_rr']) or
         inventory_hostname in groups['k8s_cluster']) and
diff --git a/roles/kubernetes-apps/csi_driver/vsphere/defaults/main.yml b/roles/kubernetes-apps/csi_driver/vsphere/defaults/main.yml
index 95a2c5e9b8bae89d1aae140e115a1a1ffe8d450f..93beca307fb43fbbd0b9943ab85cecf66b6305ac 100644
--- a/roles/kubernetes-apps/csi_driver/vsphere/defaults/main.yml
+++ b/roles/kubernetes-apps/csi_driver/vsphere/defaults/main.yml
@@ -21,3 +21,8 @@ csi_endpoint: '{% if external_vsphere_version >= "7.0u1" %}/csi{% else %}/var/li
 vsphere_csi_aggressive_node_drain: False
 vsphere_csi_aggressive_node_unreachable_timeout: 300
 vsphere_csi_aggressive_node_not_ready_timeout: 300
+
+# If this is true, debug information will be displayed but
+# may contain some private data, so it is recommended to set it to false
+# in the production environment.
+unsafe_show_logs: false
diff --git a/roles/kubernetes-apps/csi_driver/vsphere/tasks/main.yml b/roles/kubernetes-apps/csi_driver/vsphere/tasks/main.yml
index ea711ebafed7fc962f23638072256546a5ee0cea..c2cf62ab9eef79512381117f7c60728d37fb5586 100644
--- a/roles/kubernetes-apps/csi_driver/vsphere/tasks/main.yml
+++ b/roles/kubernetes-apps/csi_driver/vsphere/tasks/main.yml
@@ -30,14 +30,14 @@
   command: "{{ kubectl }} create secret generic vsphere-config-secret --from-file=csi-vsphere.conf={{ kube_config_dir }}/vsphere-csi-cloud-config -n kube-system --dry-run --save-config -o yaml"
   register: vsphere_csi_secret_manifest
   when: inventory_hostname == groups['kube_control_plane'][0]
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
 
 - name: vSphere CSI Driver | Apply a CSI secret manifest
   command:
     cmd: "{{ kubectl }} apply -f -"
     stdin: "{{ vsphere_csi_secret_manifest.stdout }}"
   when: inventory_hostname == groups['kube_control_plane'][0]
-  no_log: true
+  no_log: "{{ not (unsafe_show_logs|bool) }}"
 
 - name: vSphere CSI Driver | Apply Manifests
   kube:
diff --git a/tests/common/_kubespray_test_settings.yml b/tests/common/_kubespray_test_settings.yml
index 4bf56618a43ce41bba5b940e168c2f81a76865bd..67da05c50e2cb6afda6b834bbdcaf83cbb7394cd 100644
--- a/tests/common/_kubespray_test_settings.yml
+++ b/tests/common/_kubespray_test_settings.yml
@@ -2,3 +2,4 @@
 # Kubespray settings for tests
 deploy_netchecker: true
 dns_min_replicas: 1
+unsafe_show_logs: true