10.3. Service Accounts
A Kubernetes Service Account is an identity used by pods to interact with the Kubernetes API securely. It provides authentication for workloads running inside a cluster, enabling them to access resources such as secrets, config maps, or other API objects. By default, every pod is assigned a service account, but custom service accounts with specific permissions can be created using Role-Based Access Control (RBAC) to enforce security and least privilege principles.
Task 10.3.1: Create a Service Account
Create a file named sa.yaml
and define the ServiceAccount:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader
and apply this file using:
kubectl apply -f sa.yaml --namespace <namespace>
Task 10.3.2: Create a Role and a Rolebinding
In Kubernetes, Role-Based Access Control (RBAC) is used to manage permissions for users, applications, and system components.
- A Role defines a set of permissions (such as reading or modifying resources) within a specific namespace. It grants access to resources like pods, services, or config maps.
- A RoleBinding links a Role to a ServiceAccount, a user, or a group, effectively assigning the permissions defined in the Role to that entity.
In this task, we will create a Role that allows listing pods and bind it to our ServiceAccount so that it has the necessary permissions to query running pods.
Create a file named role.yaml
to define a Role with permissions to list Pods:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
Now create a rolebinding.yaml
file to bind the Role to the ServiceAccount (make sure that the namespace in subject
is correctly set to your namespace):
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-rolebinding
subjects:
- kind: ServiceAccount
name: pod-reader
namespace: <namespace>
roleRef:
kind: Role
name: pod-reader-role
apiGroup: rbac.authorization.k8s.io
and apply both files using:
kubectl apply -f role.yaml --namespace <namespace>
kubectl apply -f rolebinding.yaml --namespace <namespace>
Task 10.3.3: Create a Job That Lists Running Pods
And now finaly we start a Kubernetes Job thas lists all running pods. Create the job.yaml
file with the following content:
---
apiVersion: batch/v1
kind: Job
metadata:
name: list-pods-job
spec:
template:
spec:
serviceAccountName: pod-reader
containers:
- name: kubectl-container
image: bitnami/kubectl
command: ["kubectl", "get", "pods", "--field-selector=status.phase=Running"]
restartPolicy: Never
kubectl apply -f job.yaml --namespace <namespace>
Once the job runs, check the logs to see the list of running pods:
kubectl logs -l job-name=list-pods-job --namespace <namespace>
The job should list all running pods in your namespace.
Why is kubectl in the Job Using the Created Service Account?
In Kubernetes, when a Pod runs, it automatically assumes the identity of a ServiceAccount assigned to it. By default, Pods use the default ServiceAccount, which has minimal permissions. However, we explicitly assigned our pod-reader
ServiceAccount to the Job using:
serviceAccountName: pod-reader
How This Works:
- When a pod is created, Kubernetes automatically mounts a ServiceAccount token inside the pod at
/var/run/secrets/kubernetes.io/serviceaccount/token.
This token is a JWT (JSON Web Token) used for authenticating with the Kubernetes API. - The RoleBinding connects the
pod-reader
ServiceAccount to the Role that allows listing pods. When kubectl get pods runs inside the Job’s container, it authenticates using the pod-reader ServiceAccount token. - The
kubectl
command inside the Pod is executed with the permissions granted by the Role. Since we only gave “get” and “list” permissions on Pods, the job can list Pods but not modify or delete them. This ensures least privilege access, improving security by preventing unnecessary permissions from being granted.
When kubectl
runs inside a Pod, it follows Kubernetes in-cluster authentication process. Specifically, it:
- Checks for the
KUBERNETES_SERVICE_HOST
andKUBERNETES_SERVICE_PORT
environment variables, which are automatically set inside every Pod to point to the Kubernetes API server. - Looks for credentials in
~/.kube/config
(like when used locally). - If no kubeconfig is found, it falls back to in-cluster authentication, which means it:
- Reads the token from
/var/run/secrets/kubernetes.io/serviceaccount/token
- Uses the CA certificate at
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
to verify the API server - Identifies itself as the ServiceAccount assigned to the Pod
- Reads the token from