The story so far is that Alice has hired Ann and given her access as a reader. Now Bob wants the same for his team. Bob is also looking to up Alice in her game. He thinks of a way to make it easy for any tech lead in the org to create identical Roles which apply to different namespaces.
For example, both Bob and Chandan (another tech lead) have new-hires Bart and Charlie respectively. Bob wants both Bart and Charlie to have the same permissions as Ann without creating separate Roles. Keeping things DRY to avoid human error and ensure uniformity.
ClusterRole
A ClusterRole is a Role without a Namespace restriction. This is the reader role we made for Ann. Lets convert this to a ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: alices-team
name: reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
All you need to do is change the Kind and remove the namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
Lets create this
$ kubectl apply -f reader-clusterrole.yml
clusterrole.rbac.authorization.k8s.io/reader created
Lets see if its there
$ kubectl get ClusterRoles -n alices-team
NAME AGE
admin 15d
cluster-admin 15d
edit 15d
reader 3m44s
RoleBinding for a ClusterRole
lets delete the old RoleBinding we created.
$ kubectl delete RoleBindings anns-role -n alices-team
rolebinding.rbac.authorization.k8s.io "anns-role" deleted
Now Ann should not be able to view any pods in namespace alices-team
$ kubectl config use-context ann
Switched to context "ann".
$ kubectl get pods -n alices-team
Error from server (Forbidden): pods is forbidden: User "ann" cannot list resource "pods" in API group "" in the namespace "alices-team"
Create the RoleBinding
In the RoleBinding we need to specify the namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: anns-role
namespace: alices-team
subjects:
- kind: Group
name: alice # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: reader
apiGroup: rbac.authorization.k8s.io
Note the kind is ClusterRole. Also note that the namespace is specified as alices-team. Lets apply this and see if it works.
$ kubectl config use-context ann
Switched to context "ann".
$ kubectl get pods -n alices-team
NAME READY STATUS RESTARTS AGE
alice 1/1 Running 0 32s
$ kubectl get pods -n bobs-team
Error from server (Forbidden): pods is forbidden: User "ann" cannot list resource "pods" in API group "" in the namespace "bobs-team"
ClusterRoleBinding
What if we wanted Ann to have access across all namespaces ? In such a case we would need a ClusterRoleBinding. Just as a ClusterRole is a Role without a namespace, a ClusterRoleBinding is a RoleBinding without a namespace.
This is our present RoleBinding.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: anns-role
namespace: alices-team
subjects:
- kind: Group
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: reader
apiGroup: rbac.authorization.k8s.io
The ClusterRoleBinding would be
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: anns-role
subjects:
- kind: Group
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: reader
apiGroup: rbac.authorization.k8s.io
Note the missing namespace under metadata.
Lets delete the RoleBinding and apply the new ClusterRoleBinding.
$ kubectl delete rolebindings anns-role -n alices-team
rolebinding.rbac.authorization.k8s.io "anns-role" deleted
$ kubectl apply -f GroupClusterRoleBinding.yml
clusterrolebinding.rbac.authorization.k8s.io/anns-role created
$ kubectl config use-context ann
Switched to context "ann".
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
alices-team alice 1/1 Running 0 38m
bobs-team job1-847956d49f-spm28 1/1 Running 1 17h
default centos-pod 1/1 Running 8 12d
default junk-pod 1/1 Running 8 12d
default ubuntu-pod 1/1 Running 8 12d
kube-system coredns-6955765f44-7hjbw 1/1 Running 13 15d
kube-system coredns-6955765f44-j8tzv 1/1 Running 13 15d
kube-system etcd-m01 1/1 Running 13 15d
kube-system kube-apiserver-m01 1/1 Running 14 15d
kube-system kube-controller-manager-m01 1/1 Running 13 15d
kube-system kube-proxy-9d2sw 1/1 Running 13 15d
kube-system kube-scheduler-m01 1/1 Running 13 15d
kube-system storage-provisioner 1/1 Running 22 15d
Now Ann can read anything she ever wants to!
Learnings
ClusterRoles are Roles without a namespace restriction
ClusterRoleBindings are RoleBindings without a namespace restriction.
You can use a ClusterRole with a RoleBinding to create a single Role which can be used in different namespaces. This is useful when you need the same permissions in different namespaces.
DRY can avoid human error biting you later, not to mention reduce the number of chores you need to do!
Always think in groups. Groups allow you to convert O(n) chores to once-only tasks. As you scale thinking in Groups is key.
Conclusion
This brings us to the end of Role Based Access Control for Kubernetes. While you would not normally do these things by hand as we did, its important to understand that these things are happening in the background of any service provider.
Its also important to thing in Groups as much as possible and avoid dealing with Individuals in the group. Ideally, you should be able to put engineers into Groups and then the authentication system should just deal with Groups.
In the next post we will go back to our Pod creation and one of the things we need to decide is, who is allowed to deploy to the cluster ? Anyone ? Someone ? NoOne ?.