Skip to the content
Fabian Lee : Software EngineerFabian Lee : Software Engineer
Cloud Operations and Development
  • Monitoring
  • Logging
  • Containers
  • Python

Kubernetes: testing RBAC authorization of a Kubernetes Service Account

May 23, 2022
Categories: Kubernetes

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

mankier.com reference, kubectl auth can-i

kubernetes.io, api groups for 1.20

Categories: Kubernetes Tags: access, account, auth, authorization, can-i, control, KSA, kubernetes, RBAC, role, role-based

Post navigation

← Kubernetes: retrieving services and pods network CIDR block from cluster
GCP: running a container on a GKE cluster using Workload Identity →
© 2025 Fabian Lee : Software Engineer