A deployment pipeline needs far less than cluster-admin, or even edit. BookNest's pipeline applies the manifests in k8s/, runs the migration Job, and waits on rollouts. It never needs Secrets (they are created separately, Secrets Management), never deletes a Deployment, never execs into a Pod, and never touches another namespace. Write down exactly that:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: booknest-deployer, labels: { app: booknest } }
rules:
- apiGroups: [apps]
resources: [deployments, statefulsets]
verbs: [get, list, watch, create, update, patch]
- apiGroups: ["", autoscaling, gateway.networking.k8s.io]
resources: [services, configmaps, horizontalpodautoscalers, gateways, httproutes]
verbs: [get, list, watch, create, update, patch]
- { apiGroups: [batch], resources: [jobs], verbs: [get, list, watch, create, delete] }
- { apiGroups: [apps], resources: [replicasets], verbs: [get, list, watch] }
- { apiGroups: [""], resources: [pods, pods/log, events], verbs: [get, list, watch] }A rule matches every combination of its groups and resources, so the second rule also names harmless pairs such as autoscaling/services, which do not exist; group resources this way only when the verbs are identical. The read-only rules on ReplicaSets and Pods are what kubectl 5,150 rollout status and kubectl logs job/... need. Deleting Jobs is allowed because a finished migration Job must be replaced, not updated. Anything else a release needs later is a deliberate one-line change in review, not a silent grant.