CKA Study notes - Service Accounts in Kubernetes Pods - 2024 edition

Continuing with my Certified Kubernetes Administrator exam preparations I'm now going to take a look at ServiceAccounts.

This is an updated version of a similar post I created around three years ago. Things have changed since then so a new post was called for

Service Accounts provides an distinct identity in a Kubernetes cluster. A Service Account can be used by Pods and other system components to access and communicate through the API scheduler. Service accounts is also a way for external services to authenticate to the cluster.

Service Accounts are namespaced meaning that they are created in and bound to a Kubernetes namespace. Every namespace has a default service account.

Note #1: I'm using documentation for version 1.28 in my references below as this is the version used in the current (jan 2024) CKA exam. Please check the version applicable to your usecase and/or environment

Note #2: This is a post covering my study notes preparing for the CKA exam and reflects my understanding of the topic, and what I have focused on during my preparations.

Service account in Pods

Kubernetes documentation

One of the use cases for a service account is to give a Pod a specific access to specific resources, for instance a secret.

Let's first check the default service account in our default namespace

1kubectl get serviceaccounts
2kubectl describe serviceaccounts default

Default Service account

The default service account in the default namespace has nothing configured.

When a Pod gets scheduled it's getting a ServiceAccount assigned. If you're not specifying anything the default Service account in the namespace is used. Let's take a look

1kubectl get pod -o=custom-columns='Name:.metadata.name','ServiceAccount:.spec.serviceAccount'

ServiceAccounts for Pods in default namespace

In our default namespace there's several Pods running, all of them are using the default service account.

Let's take a look at one of the other namespaces in the cluster

1kubectl get ns
2kubectl get serviceaccounts -n calico-system
3kubectl get pod -o=custom-columns='Name:.metadata.name','ServiceAccount:.spec.serviceAccount' -n calico-system

Calico system namespace pods

In the calico-system namespace we can see that some of the Pods specific service accounts assigned whereas some are using the default service account.

For information about the installation of Calico in this cluster, please refer to this post

Service Accounts are used with the built-in Kubernetes role-based access control (RBAC) to grant (and thereby restrict) permissions in the Cluster. This is done by creating a Role and bind a Service Account to this role. More on that in an upcoming post.

Create service account

Now let's try to create our own ServiceAccount and use this in a Pod

1kubectl create serviceaccount my-first-sa
2kubectl get serviceaccount

Create service account

Now to assign this to a new Pod we'll create a Pod manifest and apply this in our cluster

1apiVersion: v1
2kind: Pod
3metadata:
4  name: sa-pod-demo
5spec:
6  containers:
7  - name: sa-pod
8    image: nginx
9  serviceAccount: my-first-sa
1kubectl apply -f sa-pod-demo-1.yaml
2kubectl get pod -o=custom-columns='Name:.metadata.name','ServiceAccount:.spec.serviceAccount'
3kubectl describe pod sa-pod-demo

Create pod with service account

As we can see our new Pod is now assigned with my-first-sa as the Service Account. Note that at this point this service account doesn't do anything to or from.

Service account with secret

Now we'll see how to put the service account to use, but first we'll try to deploy a Pod based on a custom Nginx image from a private Docker Hub repository, note that we are using the Service Account we previously created.

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx-test
 5  labels:
 6    app: nginx-test
 7spec:
 8  containers:
 9  - name: web-test
10    image: rumart/web-test:0.0.1
11  serviceAccount: my-first-sa
1kubectl apply -f nginx-rumart.yaml
2kubectl get pod

Deploy Pod with image from private repository

As we can see the status of the Pod isn't Running as the others, this time we have an ErrImagePull status.

If we dig a little deeper we can see the reason why

1kubectl describe pod nginx-test

Pod details

So the Kubernetes node fails to pull the container image from Docker Hub because they are missing access

To fix this let's create an imagePullSecret and add this to our Service Account.

I already have a Docker credential on my client machine which will be used to create the imagePullSecret. For more information about this take a look at the official Kubernetes documentation

1ls ~/.docker
2kubectl create secret generic rudi-docker --from-file=.dockerconfigjson=~/.docker/config.json --type=kubernetes.io/dockerconfigjson
3kubectl get secret

Create imagePullSecret

Next step is to add this secret to the Service Account

Add imagePullSecret to ServiceAccount

Kubernetes documentation reference

1kubectl patch serviceaccount my-first-sa -p '{"imagePullSecrets": [{"name": "rudi-docker"}]}'
2kubectl get sa my-first-sa -o yaml

Service Account has the imagePullSecret added

Redeploy Pod

Now, let's verify that this works by re-applying our Pod specification that uses the custom image. First we'll have to delete the existing, failing, pod

1kubectl delete -f nginx-rumart.yaml
2kubectl apply -f nginx-rumart.yaml
3kubectl get pod

Recreate Pod

Let's verify that our Pod is using our Service Account and that we are running the correct image

1kubectl describe pod nginx-test

Verify Pod status

Summary

There's a lot more to service accounts, pod security and role based access control (RBAC). Please refer to the Kubernetes documentation for more information

Thanks for reading, and please reach out if you have any questions or comments

This page was modified on January 14, 2024: cka sa post