diff --git a/roles/kubernetes-apps/cluster_roles/tasks/main.yml b/roles/kubernetes-apps/cluster_roles/tasks/main.yml
index 5bf6709495e050ba24d526bc1bc5b7c903536358..b58670c0f0de8176fc6138c574cce0907c676f5f 100644
--- a/roles/kubernetes-apps/cluster_roles/tasks/main.yml
+++ b/roles/kubernetes-apps/cluster_roles/tasks/main.yml
@@ -29,6 +29,52 @@
     - rbac_enabled
     - node_crb_manifest.changed
 
+- name: Kubernetes Apps | Add webhook ClusterRole that grants access to proxy, stats, log, spec, and metrics on a kubelet
+  template:
+    src: "node-webhook-cr.yml.j2"
+    dest: "{{ kube_config_dir }}/node-webhook-cr.yml"
+  register: node_webhook_cr_manifest
+  when:
+    - rbac_enabled
+    - kubelet_authorization_mode_webhook
+  tags: node-webhook
+
+- name: Apply webhook ClusterRole
+  kube:
+    name: "system:node-webhook"
+    kubectl: "{{bin_dir}}/kubectl"
+    resource: "clusterrole"
+    filename: "{{ kube_config_dir }}/node-webhook-cr.yml"
+    state: latest
+  when:
+    - rbac_enabled
+    - kubelet_authorization_mode_webhook
+    - node_webhook_cr_manifest.changed
+  tags: node-webhook
+
+- name: Kubernetes Apps | Add ClusterRoleBinding for system:nodes to webhook ClusterRole
+  template:
+    src: "node-webhook-crb.yml.j2"
+    dest: "{{ kube_config_dir }}/node-webhook-crb.yml"
+  register: node_webhook_crb_manifest
+  when:
+    - rbac_enabled
+    - kubelet_authorization_mode_webhook
+  tags: node-webhook
+
+- name: Grant system:nodes the webhook ClusterRole
+  kube:
+    name: "system:node-webhook"
+    kubectl: "{{bin_dir}}/kubectl"
+    resource: "clusterrolebinding"
+    filename: "{{ kube_config_dir }}/node-webhook-crb.yml"
+    state: latest
+  when:
+    - rbac_enabled
+    - kubelet_authorization_mode_webhook
+    - node_webhook_crb_manifest.changed
+  tags: node-webhook
+
 # This is not a cluster role, but should be run after kubeconfig is set on master
 - name: Write kube system namespace manifest
   template:
diff --git a/roles/kubernetes-apps/cluster_roles/templates/node-webhook-cr.yml.j2 b/roles/kubernetes-apps/cluster_roles/templates/node-webhook-cr.yml.j2
new file mode 100644
index 0000000000000000000000000000000000000000..0ac79d3e6ea052502214be705e4d02a078d3179b
--- /dev/null
+++ b/roles/kubernetes-apps/cluster_roles/templates/node-webhook-cr.yml.j2
@@ -0,0 +1,20 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+  annotations:
+    rbac.authorization.kubernetes.io/autoupdate: "true"
+  labels:
+    kubernetes.io/bootstrapping: rbac-defaults
+  name: system:node-webhook
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - nodes/proxy
+      - nodes/stats
+      - nodes/log
+      - nodes/spec
+      - nodes/metrics
+    verbs:
+      - "*"
\ No newline at end of file
diff --git a/roles/kubernetes-apps/cluster_roles/templates/node-webhook-crb.yml.j2 b/roles/kubernetes-apps/cluster_roles/templates/node-webhook-crb.yml.j2
new file mode 100644
index 0000000000000000000000000000000000000000..68aed5cb53cb87a99536f1f588505b470ae64452
--- /dev/null
+++ b/roles/kubernetes-apps/cluster_roles/templates/node-webhook-crb.yml.j2
@@ -0,0 +1,17 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  annotations:
+    rbac.authorization.kubernetes.io/autoupdate: "true"
+  labels:
+    kubernetes.io/bootstrapping: rbac-defaults
+  name: system:node-webhook
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: system:node-webhook
+subjects:
+- apiGroup: rbac.authorization.k8s.io
+  kind: Group
+  name: system:nodes
diff --git a/roles/kubernetes/node/templates/kubelet.kubeadm.env.j2 b/roles/kubernetes/node/templates/kubelet.kubeadm.env.j2
index e49b15f489a5cc13308f8df6793a5b3d321ce98f..93297accd28439c0776c9413a5a064a0ff1b5f4d 100644
--- a/roles/kubernetes/node/templates/kubelet.kubeadm.env.j2
+++ b/roles/kubernetes/node/templates/kubelet.kubeadm.env.j2
@@ -20,6 +20,9 @@ KUBELET_HOSTNAME="--hostname-override={{ kube_override_hostname }}"
 {% if kube_version | version_compare('v1.8', '<') %}
 --require-kubeconfig \
 {% endif %}
+{% if kubelet_authentication_token_webhook %}
+--authentication-token-webhook \
+{% endif %}
 --authorization-mode=Webhook \
 --client-ca-file={{ kube_cert_dir }}/ca.crt \
 --pod-manifest-path={{ kube_manifest_dir }} \
diff --git a/roles/kubernetes/node/templates/kubelet.standard.env.j2 b/roles/kubernetes/node/templates/kubelet.standard.env.j2
index cb7d83d35da8f6ab8d8acf06427b89f8ca1c5848..5c112c179d1e8951d996759726369694f6a31a28 100644
--- a/roles/kubernetes/node/templates/kubelet.standard.env.j2
+++ b/roles/kubernetes/node/templates/kubelet.standard.env.j2
@@ -33,6 +33,12 @@ KUBELET_HOSTNAME="--hostname-override={{ kube_override_hostname }}"
 {% else %}
 --fail-swap-on={{ kubelet_fail_swap_on|default(true)}} \
 {% endif %}
+{% if kubelet_authentication_token_webhook %}
+--authentication-token-webhook \
+{% endif %}
+{% if kubelet_authorization_mode_webhook %}
+--authorization-mode=Webhook \
+{% endif %}
 --enforce-node-allocatable={{ kubelet_enforce_node_allocatable }} {% endif %}{% endset %}
 
 {# DNS settings for kubelet #}
diff --git a/roles/kubespray-defaults/defaults/main.yaml b/roles/kubespray-defaults/defaults/main.yaml
index 8622d919f500b6d765b3245a4c97ee3442f45dbb..692c2e698352e84f1362137fbb344ed0c430cea1 100644
--- a/roles/kubespray-defaults/defaults/main.yaml
+++ b/roles/kubespray-defaults/defaults/main.yaml
@@ -197,6 +197,12 @@ openstack_lbaas_monitor_max_retries: "3"
 authorization_modes: ['Node', 'RBAC']
 rbac_enabled: "{{ 'RBAC' in authorization_modes or kubeadm_enabled }}"
 
+# When enabled, API bearer tokens (including service account tokens) can be used to authenticate to the kubelet’s HTTPS endpoint
+kubelet_authentication_token_webhook: false
+
+# When enabled, access to the kubelet API requires authorization by delegation to the API server
+kubelet_authorization_mode_webhook: false
+
 ## List of key=value pairs that describe feature gates for
 ## the k8s cluster.
 kube_feature_gates: