Creating A Kubernetes Service Account To Run Pods
Tags: kubernetes, devops, docker, git
Published: 2022-08-03 10:47:02

When you create any type of resource in Kubernetes, whether it’s a standard Pod, or a higher level controller that manages Pods like a Deployment or DaemonSet, the resource is deployed with a service account inside of Kubernetes.

Understanding what that service account does, and more importantly, the implications of using a service account to create Pods is crucial for any successful production deployment.

In this blog post, you’re going to learn about service accounts in Kubernetes.

## What’s A Service Account?

A service account is how workloads in Kubernetes run. It contains RBAC permissions that give it the ability to deploy resources to a Kubernetes cluster. Service accounts are used to connect to the Kubernetes API server.

Service accounts can also give you the ability to connect to other services, for example, workloads running in GCP that a Kubernetes cluster may need access to. For example, a service account that can act as an IAM service account inside of GCP using Workload Identity.

## Why Create A Service Account?

By default, when you create a Pod, the default Kubernetes service account is used.

Let’s say you have a Pod running, you can run the following command and see the `spec.ServiceAccountName` field.

```jsx
kubectl get pods -o yaml
```

Since there’s already a service account being used, you may be asking yourself *why do I need to manually create a service account if it already exists?* of which there’s one big reason - security.

The biggest reason is from a security perspective. If you’re using the same service account over and over again and that service account gets compromised, all of your applications are in big trouble. If a malicious entity obtains access to the default service account that’s deploying every workload inside of Kubernetes, that means it’ll ultimately have access to every Pod that’s running in the cluster. It’ll also allow any compromised Pod to run API calls against the cluster.

Another reason, although not as important as the security piece, is the cleanliness of the environment. Think about it like this - imagine every Sysadmin used the same email account for every single service that the infrastructure department uses or a developer generating and using the same API key for authentication across all applications. Not only is it a bad security practice, but it’s not a good practice in general.

## Creating A Service Account

Now that you know why you want to use a different service account other than the Kubernetes default, let’s learn how to set it up.

For the purposes of this blog post, you’ll create a service account that’s tied to a specific namespace.

First, you’ll need to create a namespace. The example below shows a namespace called `levantest` that you can create.

Save the Kubernetes Manifest namespace code below as `namespace.yaml`

```jsx
apiVersion: v1
kind: Namespace
metadata:
  name: levantest
```

Create the namespace:

```jsx
kubectl apply -f namespace.yaml
```

Next, you need to create the service account and give it certain permissions. You’ll need to create:

- The service account
- A Role for the service account
- A RoleBinding to bind the Role so you can use it on the service account

The below YAML creates a service account called `app1serviceaccount`, gives it permissions to `create`, `get`, `watch`, and `list`, and binds it to the `levantest` namespace.

Save the Kubernetes Manifest below and call it `serviceaccount.yaml`

```jsx
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app1serviceaccount
  namespace: levantest
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: levantest
  name: pod-creator
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create", "get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-creator
  namespace: levantest
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-creator
subjects:
- kind: ServiceAccount
  name: app1serviceaccount
  namespace: levantest
```

Run the following command to create the resource:

```jsx
kubectl apply -f serviceaccount.yaml
```

You should see an output similar to the screenshot below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iq27ddd1d7mdva3j2pb1.png) 

Next, let’s use the service account to create a Pod.

## Using A Service Account

Now it’s time to create a Pod with the service account that you created.

The Kubernetes Manifest below creates a Pod resource that deploys a Pod running Nginx with no high-level controller (Deployment, DaemonSet, etc.) and utilizes the newly created service account.

Save the Kubernetes Manifest as `pod.yaml`

```jsx
apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: levantest
spec:
  containers:
  - image: nginx:latest
    name: nginxpod
  serviceAccountName: app1serviceaccount
```

 Run the following command to deploy the Pod.

```jsx
kubectl apply -f pod.yaml
```

Once running, you can see the output of the Pod to confirm it’s using the appropriate service account.

```jsx
kubectl get pods -n namespace_name -o yaml
```

You should see an output similar to the screenshot below, which under `spec` will show the service account.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6io7vu86qze8mnw6yl1m.png) 

Congrats! You have successfully created and used a new service account for Pod deployments.