metropolis/node/kubernetes: move worker services to KubernetesWorker nodes

This finalizes the Big Split. After this change, nodes will only run a
kubelet (and related services) if they have a KubernetesWorker role
attached.

The first node in a new cluster now starts out with KubernetesController
and ConsensusMember. All joined nodes start with no roles attached.

Change-Id: I25a059318450b7d2dd3c19f3653fc15367867693
Reviewed-on: https://review.monogon.dev/c/monogon/+/1380
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/kubernetes/reconciler/resources_rbac.go b/metropolis/node/kubernetes/reconciler/resources_rbac.go
index 0976ba5..4eab82e 100644
--- a/metropolis/node/kubernetes/reconciler/resources_rbac.go
+++ b/metropolis/node/kubernetes/reconciler/resources_rbac.go
@@ -29,6 +29,10 @@
 	clusterRoleBindingDefaultPSP             = builtinRBACName("default-psp-for-sa")
 	clusterRoleBindingAPIServerKubeletClient = builtinRBACName("apiserver-kubelet-client")
 	clusterRoleBindingOwnerAdmin             = builtinRBACName("owner-admin")
+	clusterRoleCSIProvisioner                = builtinRBACName("csi-provisioner")
+	clusterRoleBindingCSIProvisioners        = builtinRBACName("csi-provisioner")
+	clusterRoleNetServices                   = builtinRBACName("netservices")
+	clusterRoleBindingNetServices            = builtinRBACName("netservices")
 )
 
 type resourceClusterRoles struct {
@@ -75,6 +79,53 @@
 				},
 			},
 		},
+		clusterRoleCSIProvisioner: &rbac.ClusterRole{
+			ObjectMeta: meta.ObjectMeta{
+				Name:   clusterRoleCSIProvisioner,
+				Labels: builtinLabels(nil),
+				Annotations: map[string]string{
+					"kubernetes.io/description": "This role grants access to PersistentVolumes, PersistentVolumeClaims and StorageClassses, as used the the CSI provisioner running on nodes.",
+				},
+			},
+			Rules: []rbac.PolicyRule{
+				{
+					APIGroups: []string{""},
+					Resources: []string{"events"},
+					Verbs:     []string{"get", "list", "watch", "create", "update", "patch"},
+				},
+				{
+					APIGroups: []string{"storage.k8s.io"},
+					Resources: []string{"storageclasses"},
+					Verbs:     []string{"get", "list", "watch"},
+				},
+				{
+					APIGroups: []string{""},
+					Resources: []string{"persistentvolumes", "persistentvolumeclaims"},
+					Verbs:     []string{"*"},
+				},
+			},
+		},
+		clusterRoleNetServices: &rbac.ClusterRole{
+			ObjectMeta: meta.ObjectMeta{
+				Name:   clusterRoleNetServices,
+				Labels: builtinLabels(nil),
+				Annotations: map[string]string{
+					"kubernetes.io/description": "This role grants access to the minimum set of resources that are needed to run networking services for a node.",
+				},
+			},
+			Rules: []rbac.PolicyRule{
+				{
+					APIGroups: []string{"discovery.k8s.io"},
+					Resources: []string{"endpointslices"},
+					Verbs:     []string{"get", "list", "watch"},
+				},
+				{
+					APIGroups: []string{""},
+					Resources: []string{"services", "nodes", "namespaces"},
+					Verbs:     []string{"get", "list", "watch"},
+				},
+			},
+		},
 	}
 }
 
@@ -173,5 +224,47 @@
 				},
 			},
 		},
+		clusterRoleBindingCSIProvisioners: &rbac.ClusterRoleBinding{
+			ObjectMeta: meta.ObjectMeta{
+				Name:   clusterRoleBindingCSIProvisioners,
+				Labels: builtinLabels(nil),
+				Annotations: map[string]string{
+					"kubernetes.io/description": "This role binding grants CSI provisioners running on nodes access to the necessary resources.",
+				},
+			},
+			RoleRef: rbac.RoleRef{
+				APIGroup: rbac.GroupName,
+				Kind:     "ClusterRole",
+				Name:     clusterRoleCSIProvisioner,
+			},
+			Subjects: []rbac.Subject{
+				{
+					APIGroup: rbac.GroupName,
+					Kind:     "Group",
+					Name:     "metropolis:csi-provisioner",
+				},
+			},
+		},
+		clusterRoleBindingNetServices: &rbac.ClusterRoleBinding{
+			ObjectMeta: meta.ObjectMeta{
+				Name:   clusterRoleBindingNetServices,
+				Labels: builtinLabels(nil),
+				Annotations: map[string]string{
+					"kubernetes.io/description": "This role binding grants node network services access to necessary resources.",
+				},
+			},
+			RoleRef: rbac.RoleRef{
+				APIGroup: rbac.GroupName,
+				Kind:     "ClusterRole",
+				Name:     clusterRoleNetServices,
+			},
+			Subjects: []rbac.Subject{
+				{
+					APIGroup: rbac.GroupName,
+					Kind:     "Group",
+					Name:     "metropolis:netservices",
+				},
+			},
+		},
 	}
 }