diff --git a/extra-manifests/toolshed-deployer-rbac.yaml b/extra-manifests/toolshed-deployer-rbac.yaml new file mode 100644 index 0000000..870a2d9 --- /dev/null +++ b/extra-manifests/toolshed-deployer-rbac.yaml @@ -0,0 +1,59 @@ +# Cluster write access for toolshed's deployer, and only deployer. +# +# Lives here rather than in toolshed's own Helm chart because these are +# cluster-scoped, and toolshed's Application runs in the `webapp` project, +# whose clusterResourceWhitelist deliberately allows only Namespace. Widening +# that project to permit ClusterRole and ClusterRoleBinding would let *any* +# Application in it — every demo app — create cluster-wide RBAC, which is a +# privilege-escalation surface in the project that holds ordinary apps. The +# narrow fix is to put the two cluster-scoped objects where platform-level +# cluster resources already live. +# +# The ServiceAccount they bind to is namespaced, so it stays in toolshed's +# chart alongside the Deployment that uses it. If that ever moves, this +# binding's subject has to move with it. +# +# Scoped to the resource kinds toolshed creates for an app. Not cluster-admin +# and not a wildcard: this is the one credential in the system whose +# compromise means the cluster, so what it can do should fit on one screen. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: toolshed-deployer + labels: + app.kubernetes.io/part-of: toolshed +rules: + # Namespaces are cluster-scoped, and one is created per app. + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "watch", "create", "delete"] + # Everything an app needs inside its own namespace. + - apiGroups: [""] + resources: ["services", "resourcequotas"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # Read-only. Pods are listed to report why a rollout failed, never changed. + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # The policy that stops one app reaching another. + - apiGroups: ["networking.k8s.io"] + resources: ["networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: toolshed-deployer + labels: + app.kubernetes.io/part-of: toolshed +subjects: + - kind: ServiceAccount + name: toolshed-deployer + namespace: toolshed +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: toolshed-deployer