diff --git a/roles/etcd/defaults/main.yml b/roles/etcd/defaults/main.yml
index e2b1b83c74b3b4dbf5774006dc3b0028686f731b..caf2662f4d929fa07378a42d399aa6dfce3e9ff7 100644
--- a/roles/etcd/defaults/main.yml
+++ b/roles/etcd/defaults/main.yml
@@ -30,3 +30,6 @@ etcd_node_cert_hosts: "{{ groups['k8s-cluster'] | union(groups.get('calico-rr',
 etcd_compaction_retention: "8"
 
 etcd_vault_mount_path: etcd
+
+# Force clients like etcdctl to use TLS certs (different than peer security)
+etcd_secure_client: true
diff --git a/roles/etcd/handlers/backup.yml b/roles/etcd/handlers/backup.yml
index 9be90a5b1f416432e89cd82ea887432862d623a0..247b2ae004c1fc0306f8020f83720394cabcdfba 100644
--- a/roles/etcd/handlers/backup.yml
+++ b/roles/etcd/handlers/backup.yml
@@ -48,5 +48,7 @@
       snapshot save {{ etcd_backup_directory }}/snapshot.db
   environment:
     ETCDCTL_API: 3
+    ETCDCTL_CERT: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
   retries: 3
   delay: "{{ retry_stagger | random + 3 }}"
diff --git a/roles/etcd/handlers/main.yml b/roles/etcd/handlers/main.yml
index 2575c25a4900f7cb4c9895d41e50bf0713518f00..aca8522f52d1a67ac15af6a60de282d29dcf53fd 100644
--- a/roles/etcd/handlers/main.yml
+++ b/roles/etcd/handlers/main.yml
@@ -22,6 +22,8 @@
   uri:
     url: "https://{% if is_etcd_master %}{{ etcd_address }}{% else %}127.0.0.1{% endif %}:2379/health"
     validate_certs: no
+    client_cert: "{{ etcd_cert_dir }}/member-{{ inventory_hostname }}.pem"
+    client_key: "{{ etcd_cert_dir }}/member-{{ inventory_hostname }}-key.pem"
   register: result
   until: result.status is defined and result.status == 200
   retries: 10
diff --git a/roles/etcd/tasks/configure.yml b/roles/etcd/tasks/configure.yml
index e6fabaffb4de6fd785e1f90327d4efb2c862f6c8..02bc231722fde5dfa50d65460d2227ce6916be37 100644
--- a/roles/etcd/tasks/configure.yml
+++ b/roles/etcd/tasks/configure.yml
@@ -8,6 +8,9 @@
   when: is_etcd_master
   tags:
     - facts
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
 
 - name: Install etcd launch script
   template:
diff --git a/roles/etcd/tasks/join_member.yml b/roles/etcd/tasks/join_member.yml
index 53841a14408b9bb24df53a12e6b2903db34d336b..60315203b3220da8f9d3f80c1b59be3f14bc07ab 100644
--- a/roles/etcd/tasks/join_member.yml
+++ b/roles/etcd/tasks/join_member.yml
@@ -6,6 +6,9 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   when: target_node == inventory_hostname
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
 
 - include: refresh_config.yml
   vars:
@@ -39,3 +42,6 @@
   tags:
     - facts
   when: target_node == inventory_hostname
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
diff --git a/roles/etcd/tasks/set_cluster_health.yml b/roles/etcd/tasks/set_cluster_health.yml
index ec3a8b988c7d87356b2bf9734595904919eeb37a..955208633040ecea66768b3366c28960a05bcf3d 100644
--- a/roles/etcd/tasks/set_cluster_health.yml
+++ b/roles/etcd/tasks/set_cluster_health.yml
@@ -8,3 +8,6 @@
   when: is_etcd_master
   tags:
     - facts
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
diff --git a/roles/etcd/templates/etcd.env.j2 b/roles/etcd/templates/etcd.env.j2
index 00ac5d8449730ebf2769482b1ff3d2eb46ca8b0f..5f14d05b6e7e5af0d06d24788b9fc178767c9a8b 100644
--- a/roles/etcd/templates/etcd.env.j2
+++ b/roles/etcd/templates/etcd.env.j2
@@ -18,6 +18,8 @@ ETCD_AUTO_COMPACTION_RETENTION={{ etcd_compaction_retention }}
 ETCD_TRUSTED_CA_FILE={{ etcd_cert_dir }}/ca.pem
 ETCD_CERT_FILE={{ etcd_cert_dir }}/member-{{ inventory_hostname }}.pem
 ETCD_KEY_FILE={{ etcd_cert_dir }}/member-{{ inventory_hostname }}-key.pem
+ETCD_CLIENT_CERT_AUTH={{ etcd_secure_client | lower}}
+
 ETCD_PEER_TRUSTED_CA_FILE={{ etcd_cert_dir }}/ca.pem
 ETCD_PEER_CERT_FILE={{ etcd_cert_dir }}/member-{{ inventory_hostname }}.pem
 ETCD_PEER_KEY_FILE={{ etcd_cert_dir }}/member-{{ inventory_hostname }}-key.pem
diff --git a/roles/kubernetes/master/tasks/pre-upgrade.yml b/roles/kubernetes/master/tasks/pre-upgrade.yml
index 81da334337cd536f3efa3f4a1dd2cced69ef34df..3a9fe64174ab48d93792960c63a40df1d5409561 100644
--- a/roles/kubernetes/master/tasks/pre-upgrade.yml
+++ b/roles/kubernetes/master/tasks/pre-upgrade.yml
@@ -3,6 +3,8 @@
   command: "{{ bin_dir }}/etcdctl --peers={{ etcd_access_addresses }} ls /registry/minions"
   environment:
     ETCDCTL_API: 2
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
   register: old_data_exists
   delegate_to: "{{groups['etcd'][0]}}"
   changed_when: false
diff --git a/roles/network_plugin/calico/rr/tasks/main.yml b/roles/network_plugin/calico/rr/tasks/main.yml
index 2dad16fb15f11ad5297387cd5e2241fd3abcac9a..5b893f38e378e5bf3e9bf924c8ab7b30c035cf27 100644
--- a/roles/network_plugin/calico/rr/tasks/main.yml
+++ b/roles/network_plugin/calico/rr/tasks/main.yml
@@ -57,6 +57,9 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   delegate_to: "{{groups['etcd'][0]}}"
+  environment:
+    ETCDCTL_CERT: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
 
 - meta: flush_handlers
 
diff --git a/roles/network_plugin/calico/tasks/main.yml b/roles/network_plugin/calico/tasks/main.yml
index a3c54043766aaa2585d313b369cef21d0646bb8d..2a2d2f6f8b0a7d06570df4fcea2cc0e2f59eade6 100644
--- a/roles/network_plugin/calico/tasks/main.yml
+++ b/roles/network_plugin/calico/tasks/main.yml
@@ -83,6 +83,8 @@
   uri:
     url: https://localhost:2379/health
     validate_certs: no
+    client_cert: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    client_key: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
   register: result
   until: result.status == 200 or result.status == 401
   retries: 10
diff --git a/roles/network_plugin/canal/tasks/main.yml b/roles/network_plugin/canal/tasks/main.yml
index 4e83292c81f3a86daf4adf5f9315928a2b41ae8f..7eeb93919e4a0c5fe5d8d4fe0ba952424d44a98b 100644
--- a/roles/network_plugin/canal/tasks/main.yml
+++ b/roles/network_plugin/canal/tasks/main.yml
@@ -34,6 +34,9 @@
   delegate_to: "{{groups['etcd'][0]}}"
   changed_when: false
   run_once: true
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
 
 - name: Canal | Create canal node manifests
   template:
diff --git a/roles/network_plugin/canal/templates/cni-canal.conflist.j2 b/roles/network_plugin/canal/templates/cni-canal.conflist.j2
index 04a88c5b9def1a1f631fa207823e2fb2476853c1..13b58a0db9253e8c5c40b937d84b6b65c13ab44c 100644
--- a/roles/network_plugin/canal/templates/cni-canal.conflist.j2
+++ b/roles/network_plugin/canal/templates/cni-canal.conflist.j2
@@ -7,6 +7,9 @@
       "delegate": {
         "type": "calico",
         "etcd_endpoints": "{{ etcd_access_addresses }}",
+        "etcd_key_file": "{{ canal_cert_dir }}/key.pem",
+        "etcd_cert_file": "{{ canal_cert_dir }}/cert.crt",
+        "etcd_ca_cert_file": "{{ canal_cert_dir }}/ca_cert.crt",
         "log_level": "info",
         "policy": {
           "type": "k8s"
diff --git a/scripts/collect-info.yaml b/scripts/collect-info.yaml
index e10cb7b2ce26ed17c9216d0f09c8fbec6d5d6e5c..1a0e2307b7ef575cc9174033779f3cb9d8f429f1 100644
--- a/scripts/collect-info.yaml
+++ b/scripts/collect-info.yaml
@@ -8,6 +8,7 @@
     bin_dir: /usr/local/bin
     system_namespace: kube-system
     ansible_ssh_pipelining: true
+    etcd_cert_dir: /etc/ssl/etcd/ssl
     commands:
       - name: timedate_info
         cmd: timedatectl status
@@ -85,6 +86,10 @@
       - /var/log/calico/felix/current
       - /var/log/calico/confd/current
 
+  environment:
+    ETCDCTL_CERT_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}.pem"
+    ETCDCTL_KEY_FILE: "{{ etcd_cert_dir }}/node-{{ inventory_hostname }}-key.pem"
+
   tasks:
     - set_fact:
         etcd_access_addresses: |-