In K8s almost everytime Authorization happens via techniques like ABAC, RBAC, node permissions, and webhooks. We mostly use the RBAC instead of ABAC for convenience reason.
How ABAC works
First, let's discuss ABAC, which stands for Attribute Based Access Control. In ABAC we attach some set of rules to the newly created user and create a policy file out of that. After that we give this file to the API server, and then we restart the API server. This ABAC policy file takes a JSON format file as input, as the API-SERVER ABAC authorizer accepts only JSON format. As in this process we need to restart the API server every time we apply the file, we generally skip to RBAC. Now lets discuss about RBAC.
How RBAC is implemented
In RBAC we create a role and role-binding. In a role, we define a set of rules for the users or the groups, and we bind that role to the newly created user via a role-binding file. In this case there is no need to restart the API server, and the user will get the access to the cluster as much as we give in "role file". Now the Role and Role-Binding only give namespace-level resources access, but for cluster-level access, we need to create Cluster-Role and Cluster-Role-Binding files.
Sample ABAC Policy File
This file creates permissions for users alice, bob and admin and groups dev-team and ops-team in certain namespaces and for certain resources.
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"alice","namespace":"development","resource":"pods","readonly":true}}
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"group":"dev-team","namespace":"development","resource":"deployments","readonly":false}}
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"bob","resource":"pods","readonly":true}}
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"group":"ops-team","nonResourcePath":"/healthz","readonly":true}}
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"admin","namespace":"*","resource":"*","apiGroup":"*"}}Applying the ABAC Policy File and Restarting the API Server
Now, this policy file need to be copied to the control plane for example in this path /etc/kubernetes/abac-policy.jsonl and should be applied either using command, when you are manually starting the API server in manual K8s installations,
kube-apiserver \
--authorization-mode=ABAC \
--authorization-policy-file=/etc/kubernetes/abac-policy.jsonlor modifying the API Server manifest file in case of kubeadm server, as the kube-apiserver will be running as a static pod,
vi /etc/kubernetes/manifests/kube-apiserver.yamlafter adding this flags in the container spec.
spec:
containers:
- command:
- kube-apiserver
- --authorization-mode=Node,RBAC,ABAC
- --authorization-policy-file=/etc/kubernetes/abac-policy.jsonlThen we need to restart the kubelet so that it can restart all the static pods including kube-apiserver.
sudo systemctl restart kubeletSample Role File in RBAC
This file will create a role named pod-editor and user bind to this role can do this verbs "get", "list", "watch", "create", "update" and "patch".
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-editor
namespace: development
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "update", "patch"]Sample Role-Binding File
To tie the user alice with this role this role-binding file need to be applied, which specifies the user's name in subject spec and role name in roleRef spec and this whole thing will be development namespaced.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-editor-binding
namespace: development
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-editor
apiGroup: rbac.authorization.k8s.ioNow apply this with
kubectl apply role.yaml
kubectl apply role_binding.yamlSample ClusterRole file and Sample ClusterRoleBinding file
Here also the same thing but for whole the cluster and will not be namespaced.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-reader-binding
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.ioThese files are all created for example user Alice. Now you can check them using,
kubectl auth can-i delete pods --as=alice -n development
kubectl auth can-i create pods --as=alice -n development
kubectl auth can-i list nodes --as=aliceIf we need to give access to the groups instead of an individual user, we just need to specify the group name in the files. Now if user Alice is in a group named dev-team, then we can check using,
kubectl auth can-i create pods -n development --as=alice --as-group=dev-team
kubectl auth can-i delete pods -n development --as=alice --as-group=dev-team
kubectl auth can-i list nodes --as=alice --as-group=dev-teamOne more thing
is there a reason why ABAC policy files are written in JSON, but RBAC files can be written in YAML?
This happens because K8s treats RBAC as K8s objects, like pods and services, and it also gets stored in ETCD, but the ABAC policy file is enabled directly in the API server and gets loaded from a static file at startup; it is more about modifying the API server, and this also does not get stored in ETCD.