DEV Community

Kevin Luu
Kevin Luu

Posted on • Originally published at releasehub.com

How to Create and Configure Your Kubernetes Service Account

cover image

How to Create and Configure Your Kubernetes Service Account

Accessing Kubernetes clusters has always been straightforward. You only need to download a kubeconfig file and place it in a specific place for your kubectl tool to read. This works well for human access, but there are use cases when you'd like some tools to access your Kubernetes API server. For example, your CI/CD pipeline somehow needs to authenticate to your cluster in order to deploy your applications there. For non-human access, Kubernetes offers what it calls service accounts. In this post, you'll learn what they are and how to use them.

What Are Kubernetes Service Accounts?

Let's start with the basics. In order to understand what a Kubernetes service account is, you first need to know how the authentication mechanism works.

When you access your Kubernetes cluster, you authenticate to the Kubernetes API as a human user via a user account. This is just an ordinary user account like in any other system. It distinguishes one user from another (however, by default, Kubernetes uses the same user account for all users).

Normally, you should connect your Kubernetes cluster to an external user management solution like Active Directory or LDAP. When you do that, users will authenticate to Kubernetes using their company email address. So, for each request to its API server, Kubernetes will be able to see who made the request. In most organizations, this will follow the typical firstname.lastname@company.com format.

This model works perfectly fine for human users. But what about non-human users? They can't authenticate using user accounts because they're not human. They won't have a firstname.lastname@company.com email address. Which brings us to the point of this post. For these use cases, instead of user accounts, Kubernetes offers service accounts. And again, as the name suggests, these are special accounts that are meant to be used by non-humans or services.

How To Create a Service Account

Now that you know the theory, let's get into the nuts and bolts. As with any other resource on Kubernetes, you can create a service account by using the kubectl create command. In the case of service accounts, it's as simple as specifying serviceaccount as the resource to be created, followed by its name.

$ kubectl create serviceaccount my-service-account
serviceaccount/my-service-account created
Enter fullscreen mode Exit fullscreen mode

That's it. You just created a new service account. But don't get too excited yet. This service account won't be very useful because, by default, it won't have any permissions associated with it. In other words, it won't be able to do anything. In order to change that, you can use the same Kubernetes RBAC mechanism as with user accounts. Therefore, you need to create a role binding for your new service account to an existing Kubernetes role or create a new custom role. Here's an example.

$ kubectl create rolebinding my-service-account-rolebinding \
   --clusterrole=view \
   --serviceaccount=default:my-service-account \
   --namespace=default
Enter fullscreen mode Exit fullscreen mode

rolebinding.rbac.authorization.k8s.io/my-service-account-rolebinding created
In the code above, I created a Kubernetes role binding that associates build in the "view" role with my new service account. By doing so, my service principal will now be able to contact the Kubernetes API and perform read-only operations. So, how do you actually use a service principal?

How to Use a Service Account

Using Kubernetes as a human user in most cases means downloading kubeconfig and interacting with the cluster using the kubectl command. And as we already established, service accounts are used by non-humans. You already know how to create a service account, so now it's time to discuss how non-humans actually use them.

First of all, what is non-human? In most cases, it just means pods on your cluster, be it your CI/CD agent that needs to be able to deploy other pods on the same cluster, a monitoring solution that needs to be able to get metrics from Kubernetes, or a security scanning tool that needs to get details about all pods on the cluster.

Assigning Service Accounts to Pods

These are just a few examples. The point is that anytime an application running in a pod on your cluster will need to get some information about other pods or the cluster itself, it will need a service account. You already know how to create a service account, but your pods won't magically start using it. Especially since you may have a few different service accounts with different permissions assigned to them.

Therefore, you need to somehow tell a pod which service account to use. The good news is that it's pretty simple. All it takes is one extra line in the spec section of your deployment YAML definition.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example-deployment-app
  template:
    metadata:
      labels:
        app: example-deployment-app
    spec:
      serviceAccountName: my-service-account
      containers:
        - name: busybox
          image: busybox
          command:
            - sleep
            - "3600"
Enter fullscreen mode Exit fullscreen mode

By specifying serviceAccountName in your deployment (or any other object that creates pods), you'll tell Kubernetes which service account to assign to the underlying pods. It's worth remembering that service accounts are assigned to pods themselves, not higher-level resources like deployments.

Why did we specify serviceAccountName in the deployment definition then? Simple. Because you normally don't create pods directly. You usually use these higher-level resources that create pods for you. And Kubernetes is smart enough and won't complain. It will just apply specified service accounts on the pods directly.

How to Validate If It Works

Now you know how to create and apply a service account to your pods. But how can you be sure that everything works and that your pod is, in fact, using a specified service account?

It's quite straightforward. You can get the details of the pod with kubectl get pod and pass the -o yaml parameter. One of the lines in the spec section of the output will tell you which service account the pod is using.

$ kubectl get pod nginx-deployment-c486548df-4spkw -oyaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-08-27T15:36:29Z"
  generateName: nginx-deployment-c486548df-
(...)
spec:
  containers:
  - image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    name: nginx
    (...)
  serviceAccount: my-service-account
  serviceAccountName: my-service-account
(...)
Enter fullscreen mode Exit fullscreen mode

Adjusting Permissions

OK, now you have a running pod with a custom service account attached to it that allows the application running in the pod to view resources on the cluster. What if you want to add read-write permissions You have two options. You can delete the existing role binding for your service account and create a new one, or you can start from scratch and create a separate service account altogether.

Let's look at the first option. For that, you first need to execute the kubectl delete rolebinding my-service-account-rolebinding command to delete the existing role binding. You need to do that because Kubernetes doesn't allow you to change role bindings.

Now you can create a new role binding, this time binding your service account to the edit role instead of view. Previously you did it with an inline kubectl command. This time I'll show you how to do it using the YAML file. The definition for role bindings looks like this:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-service-account-rolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: edit
subjects:
- kind: ServiceAccount
  name: my-service-account
  namespace: default
Enter fullscreen mode Exit fullscreen mode

Save the above snippet in a YAML file and apply it to the cluster just like with any other YAML definition using kubectl apply.

$ kubectl apply -f rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/my-service-account-rolebinding created
Enter fullscreen mode Exit fullscreen mode

And just like with any other Kubernetes resource, you can always list existing role bindings using the kubectl get command.

$ kubectl get rolebindings
NAME                             ROLE               AGE
my-service-account-rolebinding   ClusterRole/edit   34s
Enter fullscreen mode Exit fullscreen mode

Now, after restarting your pod, it will have read-write permissions.

Summary

As you can see, creating and configuring a service account is not that difficult. It is, however, a useful thing to know since most Kubernetes-based tools these days use service accounts. On top of that, it's a good security practice to have the least privileged service accounts for your pods. Misconfigured service accounts with too many permissions and no control over which pod gets which service principal could easily lead to an attacker taking control over your cluster.

If you want to learn more about Kubernetes, take a look at our other posts on our blog.

Top comments (0)