A Kubernetes Service Account (KSA) can be used to provide least-privileged access to a pod for a cluster that has Role-based access control (RBAC) enabled. This is done by making the KSA the subject in an RBAC role.
But it can be challenging to discover and test whether the KSA has the correct set of API groups, resources, and verbs. In this article, I will show you how to create a KSA and then test whether it has an adequate level of permission for your desired operations.
Create Kubernetes Service Account (KSA)
The first step is to create the Kubernetes Service Account with ClusterRole and ClusterRoleBinding. Create the “my-ksa.yaml” file below.
# my-ksa.yaml --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: my-cluster-role-binding subjects: - kind: ServiceAccount name: my-ksa namespace: default roleRef: kind: ClusterRole name: my-cluster-role apiGroup: rbac.authorization.k8s.io --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: my-cluster-role rules: - apiGroups: [""] # intentionally missing configmaps resources: ["namespaces", "pods", "secrets", "services"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] # intentionally missing deployments resources: ["daemonsets", "replicasets", "statefulsets"] verbs: ["get", "list", "watch"] --- apiVersion: v1 kind: ServiceAccount metadata: name: my-ksa namespace: default
And then apply it.
kubectl apply -f my-ksa.yaml
This has created the “my-ksa” service account in the default namespace.
Test RBAC authorization
The first level of testing the KSA permissions is to use ‘auth can-i’.
# can I get pods, and secrets? should all be 'yes' $ kubectl auth can-i get pods --as=system:serviceaccount:default:my-ksa yes $ kubectl auth can-i get secrets --as=system:serviceaccount:default:my-ksa yes # should NOT be able to list configmaps $ kubectl auth can-i get cm -A --as=system:serviceaccount:default:my-ksa no # can I get daemonsets? should be 'yes' $ kubectl auth can-i get ds --as=system:serviceaccount:default:my-ksa yes # can I get deployments? should be 'no' $ kubectl auth can-i get deployment --as=system:serviceaccount:default:my-ksa no
Update RBAC Authorization
Now, modify the original file “my-ksa.yaml” to include “configmaps” in the resources list and remove “secrets”. Reapply and test again.
# make changes to my-ksa.yaml described above, then apply ClusterRole again with new permissions $ kubectl apply -f my-ksa.yaml # initially, configmap were not allowed. now there are $ kubectl auth can-i get cm -A --as=system:serviceaccount:default:my-ksa yes # initially, secrets were viewable. now they are not $ kubectl auth can-i get secrets --as=system:serviceaccount:default:my-ksa no
Create KUBECONFIG using service account for authentication
Instead of just using ‘can-i’ to test permissions, we will take it a step further by creating a KUBECONFIG where the KSA and its token are used to access the cluster.
ns=default KSA=my-ksa # get token and cert for service account TOKENNAME=$(kubectl -n $ns get serviceaccount/$KSA -o jsonpath='{.secrets[0].name}') TOKEN=$(kubectl -n $ns get secret $TOKENNAME -o jsonpath='{.data.token}' | base64 --decode) CA_CERT=$(kubectl -n $ns get secret $TOKENNAME -o jsonpath='{.data.ca\.crt}' | base64 --decode) # get cluster info to prepare for creating new KUBECONFIG the_cluster=$(kubectl config get-clusters | tail -n+2) kube_api=$(kubectl config view --output=jsonpath="{.clusters[].cluster.server}") kube_context=$(kubectl config current-context) # create new KUBECONFIG export KUBECONFIG=$(realpath $KSA.kubeconfig) kubectl config set-cluster $kube_context --server=$kube_api kubectl config set-credentials $KSA --token=$TOKEN kubectl config set-context $kube_context --user=$KSA --cluster=$the_cluster kubectl config set-cluster $the_cluster --embed-certs --certificate-authority <(echo "$CA_CERT") kubectl config use-context $kube_context
With this new KUBECONFIG, we can now test these operations directly using kubectl. Attempting to list secrets (which we have removed from the resource list) will fail with an error message.
# shows error showing why secrets are not accessible $ kubectl get secret -n default Error from server (Forbidden): secrets is forbidden: User "system:serviceaccount:default:my-ksa" cannot list resource "secrets" in API group "" in the namespace "default" # shows error showing why deployments are not accessible # because 'deployments' in 'apps' group $ kubectl get deployments Error from server (Forbidden): deployments.apps is forbidden: User "system:serviceaccount:default:my-ksa" cannot list resource "deployments" in API group "apps" in the namespace "default"
Error messages like this provide an easy way for you to find the exact API group and resource name that need to be added to the ClusterRole.
If you want the full list of API groups and resources, you can use the command below.
kubectl api-resources -o wide
REFERENCES
kubernetes.io, RBAC Authorization
ryanbaker.io, creating kubectl for KSA user and token