The Forbidden message named four things: verb, resource, API group, namespace. A Role is a list of rules made of exactly those, and a RoleBinding says who gets it.
A Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: citadel
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]Or on one line:
kubectl create role pod-reader --verb=get,list,watch --resource=pods,pods/log -n citadelapiGroups: [""] is the core group, where Pods, Services, ConfigMaps and Secrets live. Deployments are in apps, Jobs in batch; kubectl api-resources shows the group of everything. Verbs are the API's words: get one object, list many, watch for changes, create, update, patch, delete. A Role never names a person.
A RoleBinding
kubectl create rolebinding dev-reads-pods --role=pod-reader --user=dev -n citadelSubjects are users (--user), groups (--group) or ServiceAccounts (--serviceaccount=citadel:ci). A binding can list several subjects but points at one role.
The namespace boundary
Both objects live in a namespace, and the grant stays there. dev can now list pods in citadel and nowhere else:
kubectl auth can-i list pods --as dev -n citadel # yes
kubectl auth can-i list pods --as dev -n default # no
kubectl auth can-i get secrets --as dev -n citadel # no: not in the rulesReading what exists
kubectl get roles,rolebindings -n citadel
kubectl describe role pod-reader -n citadel
kubectl describe rolebinding dev-reads-pods -n citadeldescribe role prints the rules as a table; describe rolebinding prints the role and the subjects. Between them they answer "who can do what here" for one namespace.