diff --git a/inventory/sample/group_vars/k8s-cluster/addons.yml b/inventory/sample/group_vars/k8s-cluster/addons.yml
index 5925a4d2c7c7cef85c807e1d20975ae37c578a1e..32a86e4a51a2dc59cfe93c1fe4da7765536e0631 100644
--- a/inventory/sample/group_vars/k8s-cluster/addons.yml
+++ b/inventory/sample/group_vars/k8s-cluster/addons.yml
@@ -94,6 +94,10 @@ ingress_publish_status_address: ""
 #     operator: "Equal"
 #     value: ""
 #     effect: "NoSchedule"
+#   - key: "node-role.kubernetes.io/control-plane"
+#     operator: "Equal"
+#     value: ""
+#     effect: "NoSchedule"
 # ingress_nginx_namespace: "ingress-nginx"
 # ingress_nginx_insecure_port: 80
 # ingress_nginx_secure_port: 443
diff --git a/roles/kubernetes-apps/ansible/templates/coredns-deployment.yml.j2 b/roles/kubernetes-apps/ansible/templates/coredns-deployment.yml.j2
index 6a7253422285230330374415fa2595ad2290d960..d14dde08b00373779c3cb2b6b89d892e20e83b04 100644
--- a/roles/kubernetes-apps/ansible/templates/coredns-deployment.yml.j2
+++ b/roles/kubernetes-apps/ansible/templates/coredns-deployment.yml.j2
@@ -31,6 +31,8 @@ spec:
       tolerations:
         - key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
 {% if dns_extra_tolerations | default(None) %}
         {{ dns_extra_tolerations | list | to_nice_yaml(indent=2) | indent(8) }}
 {% endif %}
@@ -46,7 +48,11 @@ spec:
           - weight: 100
             preference:
               matchExpressions:
+{% if kube_version is version('v1.20.0', '<') %}
               - key: node-role.kubernetes.io/master
+{% else %}
+              - key: node-role.kubernetes.io/control-plane
+{% endif %}
                 operator: In
                 values:
                 - ""
diff --git a/roles/kubernetes-apps/ansible/templates/dashboard.yml.j2 b/roles/kubernetes-apps/ansible/templates/dashboard.yml.j2
index ea8c278458af04c2bb7bb365ee6c0b01f969554f..d75b2cd082103791f52c94a50e1d72f4f774e088 100644
--- a/roles/kubernetes-apps/ansible/templates/dashboard.yml.j2
+++ b/roles/kubernetes-apps/ansible/templates/dashboard.yml.j2
@@ -219,6 +219,8 @@ spec:
       tolerations:
         - key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
 {% endif %}
 
 ---
@@ -316,4 +318,6 @@ spec:
       tolerations:
         - key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
 {% endif %}
diff --git a/roles/kubernetes-apps/ansible/templates/dns-autoscaler.yml.j2 b/roles/kubernetes-apps/ansible/templates/dns-autoscaler.yml.j2
index ead631e07a02a48ff210726fdd707e1b0fdbeb55..b49c41264f7240f16f2f7bc0d9f6a89ed8edecf6 100644
--- a/roles/kubernetes-apps/ansible/templates/dns-autoscaler.yml.j2
+++ b/roles/kubernetes-apps/ansible/templates/dns-autoscaler.yml.j2
@@ -40,8 +40,9 @@ spec:
         kubernetes.io/os: linux
       tolerations:
         - effect: NoSchedule
-          operator: Equal
           key: node-role.kubernetes.io/master
+        - effect: NoSchedule
+          key: node-role.kubernetes.io/control-plane
       affinity:
         podAntiAffinity:
           requiredDuringSchedulingIgnoredDuringExecution:
@@ -54,7 +55,11 @@ spec:
           - weight: 100
             preference:
               matchExpressions:
+{% if kube_version is version('v1.20.0', '<') %}
               - key: node-role.kubernetes.io/master
+{% else %}
+              - key: node-role.kubernetes.io/control-plane
+{% endif %}
                 operator: In
                 values:
                 - ""
diff --git a/roles/kubernetes-apps/cloud_controller/oci/templates/oci-cloud-provider.yml.j2 b/roles/kubernetes-apps/cloud_controller/oci/templates/oci-cloud-provider.yml.j2
index 7ed87603cf30beeed93f085a6165c657fdcd5d42..071432401fb641e6c7277f4395b0b1ea2fee4a33 100644
--- a/roles/kubernetes-apps/cloud_controller/oci/templates/oci-cloud-provider.yml.j2
+++ b/roles/kubernetes-apps/cloud_controller/oci/templates/oci-cloud-provider.yml.j2
@@ -36,7 +36,11 @@ spec:
       hostNetwork: true
       dnsPolicy: ClusterFirstWithHostNet
       nodeSelector:
+{% if kube_version is version('v1.20.0', '<') %}
         node-role.kubernetes.io/master: ""
+{% else %}
+        node-role.kubernetes.io/control-plane: ""
+{% endif %}
       tolerations:
       - key: node.cloudprovider.kubernetes.io/uninitialized
         value: "true"
@@ -44,6 +48,9 @@ spec:
       - key: node-role.kubernetes.io/master
         operator: Exists
         effect: NoSchedule
+      - key: node-role.kubernetes.io/control-plane
+        operator: Exists
+        effect: NoSchedule
       volumes:
         - name: cfg
           secret:
diff --git a/roles/kubernetes-apps/csi_driver/azuredisk/templates/azure-csi-azuredisk-controller.yml.j2 b/roles/kubernetes-apps/csi_driver/azuredisk/templates/azure-csi-azuredisk-controller.yml.j2
index ab7a540f89c5bcf4e80f4594c5e4360cdbeb5e70..659c9b965b749a3ec42d49cf4f298cd1e4d5256b 100644
--- a/roles/kubernetes-apps/csi_driver/azuredisk/templates/azure-csi-azuredisk-controller.yml.j2
+++ b/roles/kubernetes-apps/csi_driver/azuredisk/templates/azure-csi-azuredisk-controller.yml.j2
@@ -21,8 +21,8 @@ spec:
       priorityClassName: system-cluster-critical
       tolerations:
         - key: "node-role.kubernetes.io/master"
-          operator: "Equal"
-          value: "true"
+          effect: "NoSchedule"
+        - key: "node-role.kubernetes.io/control-plane"
           effect: "NoSchedule"
       containers:
         - name: csi-provisioner
diff --git a/roles/kubernetes-apps/csi_driver/vsphere/templates/vsphere-csi-controller-ss.yml.j2 b/roles/kubernetes-apps/csi_driver/vsphere/templates/vsphere-csi-controller-ss.yml.j2
index 24651d90d175ebbbea7affba81c05ff6ba690518..b762b496d3e163784c763446ae096302d0cc31b4 100644
--- a/roles/kubernetes-apps/csi_driver/vsphere/templates/vsphere-csi-controller-ss.yml.j2
+++ b/roles/kubernetes-apps/csi_driver/vsphere/templates/vsphere-csi-controller-ss.yml.j2
@@ -19,11 +19,18 @@ spec:
     spec:
       serviceAccountName: vsphere-csi-controller
       nodeSelector:
+{% if kube_version is version('v1.20.0', '<') %}
         node-role.kubernetes.io/master: ""
+{% else %}
+        node-role.kubernetes.io/control-plane: ""
+{% endif %}
       tolerations:
         - operator: "Exists"
           key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - operator: "Exists"
+          key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
       dnsPolicy: "Default"
       containers:
         - name: csi-attacher
diff --git a/roles/kubernetes-apps/external_cloud_controller/openstack/templates/external-openstack-cloud-controller-manager-ds.yml.j2 b/roles/kubernetes-apps/external_cloud_controller/openstack/templates/external-openstack-cloud-controller-manager-ds.yml.j2
index 295ecee2df38edbfdced68df55a3c443ec848962..c623fecceb70b7a0d752009cd9c8a5fca54da883 100644
--- a/roles/kubernetes-apps/external_cloud_controller/openstack/templates/external-openstack-cloud-controller-manager-ds.yml.j2
+++ b/roles/kubernetes-apps/external_cloud_controller/openstack/templates/external-openstack-cloud-controller-manager-ds.yml.j2
@@ -24,7 +24,11 @@ spec:
         k8s-app: openstack-cloud-controller-manager
     spec:
       nodeSelector:
+{% if kube_version is version('v1.20.0', '<') %}
         node-role.kubernetes.io/master: ""
+{% else %}
+        node-role.kubernetes.io/control-plane: ""
+{% endif %}
       securityContext:
         runAsUser: 1001
       tolerations:
@@ -33,6 +37,8 @@ spec:
         effect: NoSchedule
       - key: node-role.kubernetes.io/master
         effect: NoSchedule
+      - key: node-role.kubernetes.io/control-plane
+        effect: NoSchedule
       serviceAccountName: cloud-controller-manager
       containers:
         - name: openstack-cloud-controller-manager
diff --git a/roles/kubernetes-apps/external_cloud_controller/vsphere/templates/external-vsphere-cloud-controller-manager-ds.yml.j2 b/roles/kubernetes-apps/external_cloud_controller/vsphere/templates/external-vsphere-cloud-controller-manager-ds.yml.j2
index 8bd4e641015ad1364a790b8dd67f23a8b8e6bd94..dc1b7ffda581f817d615e6167738419913b7ecff 100644
--- a/roles/kubernetes-apps/external_cloud_controller/vsphere/templates/external-vsphere-cloud-controller-manager-ds.yml.j2
+++ b/roles/kubernetes-apps/external_cloud_controller/vsphere/templates/external-vsphere-cloud-controller-manager-ds.yml.j2
@@ -24,7 +24,11 @@ spec:
         k8s-app: vsphere-cloud-controller-manager
     spec:
       nodeSelector:
+{% if kube_version is version('v1.20.0', '<') %}
         node-role.kubernetes.io/master: ""
+{% else %}
+        node-role.kubernetes.io/control-plane: ""
+{% endif %}
       securityContext:
         runAsUser: 0
       tolerations:
@@ -33,6 +37,8 @@ spec:
         effect: NoSchedule
       - key: node-role.kubernetes.io/master
         effect: NoSchedule
+      - key: node-role.kubernetes.io/control-plane
+        effect: NoSchedule
       serviceAccountName: cloud-controller-manager
       containers:
         - name: vsphere-cloud-controller-manager
diff --git a/roles/kubernetes-apps/ingress_controller/ambassador/templates/cr-ambassador-installation.yml.j2 b/roles/kubernetes-apps/ingress_controller/ambassador/templates/cr-ambassador-installation.yml.j2
index d1a6fb216090f7495c160b5c9607c7f458fa35e6..8449cd5b8a0e83650c918add91bdecadddc8c24d 100644
--- a/roles/kubernetes-apps/ingress_controller/ambassador/templates/cr-ambassador-installation.yml.j2
+++ b/roles/kubernetes-apps/ingress_controller/ambassador/templates/cr-ambassador-installation.yml.j2
@@ -16,7 +16,8 @@ spec:
   helmValues:
     tolerations:
       - key: "node-role.kubernetes.io/master"
-        operator: Equal
+        effect: NoSchedule
+      - key: "node-role.kubernetes.io/control-plane"
         effect: NoSchedule
     deploymentTool: amb-oper-kubespray
 {% if ingress_ambassador_host_network %}
@@ -34,4 +35,4 @@ spec:
           port: 443
           hostPort: {{ ingress_ambassador_secure_port }}
           targetPort: 8443
-          protocol: TCP
\ No newline at end of file
+          protocol: TCP
diff --git a/roles/kubernetes-apps/metallb/templates/metallb.yml.j2 b/roles/kubernetes-apps/metallb/templates/metallb.yml.j2
index af4c0f2156bded51a4d6c30e52f04ab4517edd76..392c021375ba88ee2caa2c3f94bbfdd99369a8eb 100644
--- a/roles/kubernetes-apps/metallb/templates/metallb.yml.j2
+++ b/roles/kubernetes-apps/metallb/templates/metallb.yml.j2
@@ -345,6 +345,8 @@ spec:
       tolerations:
       - effect: NoSchedule
         key: node-role.kubernetes.io/master
+      - effect: NoSchedule
+        key: node-role.kubernetes.io/control-plane
 ---
 apiVersion: apps/v1
 kind: Deployment
diff --git a/roles/kubernetes-apps/metrics_server/templates/metrics-server-deployment.yaml.j2 b/roles/kubernetes-apps/metrics_server/templates/metrics-server-deployment.yaml.j2
index d636d6ad9dbe938b23da29daeeb96990baed3ef5..746d7c3524449bfd817aa55167a96f78792bfc74 100644
--- a/roles/kubernetes-apps/metrics_server/templates/metrics-server-deployment.yaml.j2
+++ b/roles/kubernetes-apps/metrics_server/templates/metrics-server-deployment.yaml.j2
@@ -126,6 +126,8 @@ spec:
       tolerations:
         - key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
 {% endif %}
       affinity:
         nodeAffinity:
@@ -133,7 +135,11 @@ spec:
           - weight: 100
             preference:
               matchExpressions:
+{% if kube_version is version('v1.20.0', '<') %}
               - key: node-role.kubernetes.io/master
+{% else %}
+              - key: node-role.kubernetes.io/control-plane
+{% endif %}
                 operator: In
                 values:
                 - ""
diff --git a/roles/kubernetes-apps/policy_controller/calico/templates/calico-kube-controllers.yml.j2 b/roles/kubernetes-apps/policy_controller/calico/templates/calico-kube-controllers.yml.j2
index c1db6b68572514dbc4405c0fcea37d89e00c155a..f861d918d72e217edfec672bd666710164c95a74 100644
--- a/roles/kubernetes-apps/policy_controller/calico/templates/calico-kube-controllers.yml.j2
+++ b/roles/kubernetes-apps/policy_controller/calico/templates/calico-kube-controllers.yml.j2
@@ -26,6 +26,8 @@ spec:
       tolerations:
         - key: node-role.kubernetes.io/master
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          effect: NoSchedule
       priorityClassName: system-cluster-critical
       containers:
         - name: calico-kube-controllers
diff --git a/roles/kubernetes/master/tasks/kubeadm-setup.yml b/roles/kubernetes/master/tasks/kubeadm-setup.yml
index 43655a30de68a7a6b6086dcd55f150a29b2036a5..1cef72396d14e816b413fa8495e43304f7696820 100644
--- a/roles/kubernetes/master/tasks/kubeadm-setup.yml
+++ b/roles/kubernetes/master/tasks/kubeadm-setup.yml
@@ -226,7 +226,7 @@
 
 # FIXME(mattymo): from docs: If you don't want to taint your control-plane node, set this field to an empty slice, i.e. `taints: {}` in the YAML file.
 - name: kubeadm | Remove taint for master with node role
-  command: "{{ bin_dir }}/kubectl --kubeconfig {{ kube_config_dir }}/admin.conf taint node {{ inventory_hostname }} node-role.kubernetes.io/master:NoSchedule-"
+  command: "{{ bin_dir }}/kubectl --kubeconfig {{ kube_config_dir }}/admin.conf taint node {{ inventory_hostname }} node-role.kubernetes.io/master:NoSchedule- node-role.kubernetes.io/control-plane:NoSchedule-"
   delegate_to: "{{ groups['kube-master'] | first }}"
   when: inventory_hostname in groups['kube-node']
   failed_when: false
diff --git a/roles/network_plugin/calico/templates/calico-typha.yml.j2 b/roles/network_plugin/calico/templates/calico-typha.yml.j2
index c23e93d465e0461f916776b1cab7543a9512aeea..143a1711e53470736f32b46f2cc9206d094ea431 100644
--- a/roles/network_plugin/calico/templates/calico-typha.yml.j2
+++ b/roles/network_plugin/calico/templates/calico-typha.yml.j2
@@ -54,6 +54,9 @@ spec:
         - key: node-role.kubernetes.io/master
           operator: Exists
           effect: NoSchedule
+        - key: node-role.kubernetes.io/control-plane
+          operator: Exists
+          effect: NoSchedule
       # Since Calico can't network a pod until Typha is up, we need to run Typha itself
       # as a host-networked pod.
       serviceAccountName: calico-node
diff --git a/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2 b/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
index 12711527642576a12fa0297a88a380e740a7326a..5e76f8e6a856be36400f387dcd1c43cce7ae1777 100644
--- a/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
+++ b/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
@@ -414,6 +414,9 @@ spec:
        - key: "node-role.kubernetes.io/master"
          effect: "NoSchedule"
          operator: "Exists"
+       - key: "node-role.kubernetes.io/control-plane"
+         effect: "NoSchedule"
+         operator: "Exists"
       serviceAccountName: k8s-nfn-sa
       containers:
         - name: nfn-operator