Day 25/40 Days of K8s: Service Account in Kubernetes !! ☸️

πŸ’ What is a Service account in K8s?

Service accounts in Kubernetes (K8s) are a type of non-human users to authenticate with the Kubernetes API server similar to how user accounts are identities for human users.

Example: Prometheus use service accounts to collect metrics from the cluster, Jenkins use service accounts to deploy applications or manage resources in the cluster.

  • While Human users need certificates to authenticate with api-server but Service accounts use tokens.

  • Like human users, service accounts can be bound to roles (Role Binding) or cluster roles (Cluster Role Binding) to define their permissions.

  • Kubernetes automatically creates a default service account in each namespace. If you do not specify a ServiceAccount when you create a Pod, Kubernetes automatically assigns the ServiceAccount named default in that namespace.

  • You can list all ServiceAccount resources for current namespace with

      kubectl get serviceaccounts
    
  • Each namespace have dedicated service account, list ServiceAccount for all namespaces using

      kubectl get serviceaccount -A
    
  • To create and list a service account

      kubectl create sa name
      kubectl get sa
    

As you can see, we created a serviceaccount named vivi-sa and since we didn't specified any namespace while creating, it took default namespace. Also the default serviceaccount for default namespace was already there.

❇ Authentication

Manually create a long-lived API token for a ServiceAccount

  • If you want to obtain an API token for a ServiceAccount, you create a new Secret with a special annotation, kubernetes.io/service-account.name

  • Create a secret using this yaml

  •       apiVersion: v1
          kind: Secret
          metadata:
            name: vivi-secret
            annotations:
              kubernetes.io/service-account.name: vivi-sa
          type: kubernetes.io/service-account-token
    

    This will create a secret named vivi-secret of type api-token and assign the secret to serviceaccount named vivi-sa

Now, we have a token ready for serviceaccount named vivi-sa , make a curl API request to the Kubernetes API server using a service account token, and eventually we can add role and role binding for authorization.

curl -k \
-H "Authorization: Bearer <your-api-token>" \
-H "Content-Type: application/json" \
https://<your-k8s-api-server>:6443/api/v1/pods

Determine the URL of your Kubernetes API server.You can find it in ~/.kube/config

❇ Accessing External Docker Registries

Add ImagePullSecrets to a service account

  • Use case: To pull Docker images from a private registry, we create a Kubernetes secret that contains the credentials required for authentication.

  • We then reference this secret in either Pod or serviceaccount YAML using the imagePullSecrets field.

Create a Secret using the command

kubectl create secret docker-registry secret-name \
  --docker-username=<username> \
  --docker-password=<password> \
  --docker-email=<email> \
  --docker-server=<registry-server>

Add image pull secret to service account

We can edit the serviceaccount by adding lines for imagePullSecrets: and save it.

kubectl edit serviceaccount/vivi-sa
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2024-07-30T11:57:25Z"
  name: vivi-sa
  namespace: default
  uid: 1ff116ad-9c36-4f71-8460-7f9a27ab351c
imagePullSecrets:
  - name: myregistrykey

NOTE: Service account tokens are used for authenticating non-human users (like applications) to the Kubernetes API server.

When you create a service account in a namespace, Kubernetes automatically generates a default token associated with that service account which is tied to the lifecycle of the Service Account. This token can be mounted into Pods and used for authentication.
But, to create a persistent token for a Service Account that does not expire and can be used consistently, you can create a Secret manually and annotate with service account name.

imagePullSecrets for new Pods

Purpose: For authenticating with container registries, especially private ones, to allow Pods to pull images.

We can include the imagePullSecrets field directly in the Pod. Alternatively, we can attach imagePullSecrets to a service account. This means that every Pod that uses this service account will automatically use the specified image pull secrets for pulling images.

Let's create a new Pod in the current namespace default and using the vivi-sa ServiceAccount

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
spec:
  serviceAccountName: vivi-sa  
  containers:
  - name: nginx
    image: nginx

Now, The Pod named nginx, created with the service account vivi-sa, is automatically utilizing the secret named myregistrykey as its imagePullSecrets.

    • When the Pod is created, Kubernetes uses the specified imagePullSecrets to authenticate with the Docker registry and pull the image.

      * Simultaneously, the service account token is automatically mounted into the Pod, allowing the application to authenticate with the Kubernetes API.

Verify service account token by bashing into the container,

The token is mounted inside the Pod at the path /var/run/secrets/kubernetes.io/serviceaccount and is ready to authenticate with api-server.

❇ Role and RoleBinding to grant access(Authorization)

  • Verify if the serviceaccount can get the list of pods or not

      kubectl get pods --as vivi-sa
    

  • Let's create a Role and Rolebinding

      kubectl create role vivi-role \
       --verb=list,get,watch \
       --resource=pod 
    
      kubectl create rolebinding vivi-rb \
       --role=vivi-role \
       --user=vivi-sa
    

  • Verify to confirm that serviceaccount now have access to list the pods

❇ Common Questions

  1. Is the service account namespace-level?

    Yes, service accounts are scoped to the namespace level. Each namespace can have its own set of service accounts, including a default service account.

  2. How will the Prometheus Pod in a namespace gather metrics from all nodes if it is namespace-scoped?

    • While Prometheus runs in a specific namespace, it can be configured to scrape metrics from all nodes and other services running in the cluster, regardless of their namespaces.

    • Prometheus collects metrics from all nodes in a Kubernetes cluster by utilizing Node Exporters deployed as DaemonSets on each node. It uses service discovery, along with annotations, to automatically locate and scrape these metrics. The target Pods behind the services expose their metrics at the /metrics endpoint, and annotations are used to inform Prometheus which services or Pods should be scraped. This setup enables Prometheus to effectively monitor the entire cluster, regardless of the namespace in which it is deployed.

#Kubernetes #ServiceAccount #RBAC #Authorization #Role #RoleBinding #ClusterRole #ClusterRoleBinding #40DaysofKubernetes #CKASeries

0
Subscribe to my newsletter

Read articles from Gopi Vivek Manne directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Gopi Vivek Manne
Gopi Vivek Manne

I'm Gopi Vivek Manne, a passionate DevOps Cloud Engineer with a strong focus on AWS cloud migrations. I have expertise in a range of technologies, including AWS, Linux, Jenkins, Bitbucket, GitHub Actions, Terraform, Docker, Kubernetes, Ansible, SonarQube, JUnit, AppScan, Prometheus, Grafana, Zabbix, and container orchestration. I'm constantly learning and exploring new ways to optimize and automate workflows, and I enjoy sharing my experiences and knowledge with others in the tech community. Follow me for insights, tips, and best practices on all things DevOps and cloud engineering!