From a800ed094b40aac9e73ac5115bf8506ef53c1db1 Mon Sep 17 00:00:00 2001
From: Jonas Kongslund <jonas@kongslund.net>
Date: Sun, 21 Jan 2018 14:34:37 +0400
Subject: [PATCH] Added support for webhook authentication/authorization on the
 secure kubelet endpoint

---
 .../cluster_roles/tasks/main.yml              | 46 +++++++++++++++++++
 .../templates/node-webhook-cr.yml.j2          | 19 ++++++++
 .../templates/node-webhook-crb.yml.j2         | 17 +++++++
 .../node/templates/kubelet.kubeadm.env.j2     |  3 ++
 .../node/templates/kubelet.standard.env.j2    |  6 +++
 roles/kubespray-defaults/defaults/main.yaml   |  6 +++
 6 files changed, 97 insertions(+)
 create mode 100644 roles/kubernetes-apps/cluster_roles/templates/node-webhook-cr.yml.j2
 create mode 100644 roles/kubernetes-apps/cluster_roles/templates/node-webhook-crb.yml.j2

diff --git a/roles/kubernetes-apps/cluster_roles/tasks/main.yml b/roles/kubernetes-apps/cluster_roles/tasks/main.yml
index 5bf670949..b58670c0f 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 000000000..3f32c2599
--- /dev/null
+++ b/roles/kubernetes-apps/cluster_roles/templates/node-webhook-cr.yml.j2
@@ -0,0 +1,19 @@
+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 000000000..68aed5cb5
--- /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 e49b15f48..93297accd 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 cb7d83d35..5c112c179 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 8622d919f..692c2e698 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:
-- 
GitLab