Kubernetes Service Accounts

Authentication and Authorization for Pod-based Applications

Featured image

Image reference link



Overview

Service Accounts in Kubernetes are a fundamental security mechanism that provides identity to processes running inside Pods. They enable controlled access to the Kubernetes API server, allowing applications to interact with cluster resources based on defined permissions.

Understanding Service Accounts is essential for implementing proper security practices and ensuring your applications have the appropriate level of access within the cluster.

graph LR A[Pod] --> B[Service Account] B --> C[Token] B --> D[RBAC Permissions] D --> E[Role/ClusterRole] D --> F[RoleBinding/ClusterRoleBinding] C --> G[API Server] F --> G



Service Account Core Concepts

What is a Service Account?

A Service Account is a Kubernetes resource that provides an identity for processes running in Pods. It enables applications to authenticate with the Kubernetes API server and perform authorized operations within the cluster.

k8s-service-account-component Image reference link

Service Accounts function as the identity mechanism for Pods, similar to how user accounts function for humans. When a Pod uses a Service Account, it receives credentials that allow it to interact with the Kubernetes API server according to the permissions assigned to that Service Account.

Service Account Lifecycle

sequenceDiagram participant U as User/System participant K as Kubernetes API participant C as Controller Manager participant P as Pod U->>K: Create ServiceAccount K->>C: ServiceAccount Created C->>K: Create Token (pre-1.24) or Mount ProjectedVolume (1.24+) U->>K: Create Pod with ServiceAccount K->>P: Assign ServiceAccount P->>K: Access API with Token

Pre-Kubernetes 1.24

In versions before Kubernetes 1.24, a Secret containing a service account token was automatically created when a ServiceAccount was created:

$ kubectl get serviceaccount -n somaz
NAME                                   SECRETS   AGE
default                                1         27d

$ kubectl get secret -n somaz
NAME                                               TYPE                                  DATA   AGE
default-token-7c6dm                                kubernetes.io/service-account-token   3      27d

Kubernetes 1.24 and Later

Starting with Kubernetes 1.24, long-lived service account tokens are no longer automatically created. Instead, tokens are obtained through the TokenRequest API and mounted as projected volumes with automatic rotation.

For backward compatibility or specific use cases, you can still manually create long-lived tokens:

apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  name: my-service-account-token
  annotations:
    kubernetes.io/service-account.name: my-service-account



Service Account Components

Key Elements of Service Accounts

Component Description Purpose
Token JSON Web Token (JWT) Authenticates API requests, contains encoded identity information
ca.crt Cluster CA certificate Verifies API server identity to prevent MITM attacks
Namespace Associated namespace Defines the scope of the service account permissions

1. Token

The token is a JSON Web Token (JWT) that authenticates requests to the Kubernetes API server on behalf of a service account.

Key characteristics:

Token location in a Pod:

/var/run/secrets/kubernetes.io/serviceaccount/token

2. ca.crt

The ca.crt file contains the certificate of the certificate authority (CA) for the Kubernetes cluster. It serves as a trust anchor for verifying the API server’s identity.

Key characteristics:

CA certificate location in a Pod:

/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

3. Namespace

The namespace element defines the default scope for the service account’s permissions when using Role and RoleBinding (as opposed to ClusterRole and ClusterRoleBinding).

Key characteristics:

Namespace location in a Pod:

/var/run/secrets/kubernetes.io/serviceaccount/namespace



Internal Architecture

Kubernetes Controllers for Service Accounts

Several controllers in Kubernetes manage the lifecycle and functionality of service accounts:

1. ServiceAccount Admission Controller

The ServiceAccount Admission Controller is part of the Kubernetes API server and performs the following functions:

2. ServiceAccount Token Controller

The ServiceAccount Token Controller is part of the kube-controller-manager and:

3. ServiceAccount Controller

The ServiceAccount Controller ensures:

4. Token Request Projection

In Kubernetes 1.24+, the token request projection system:



RBAC Integration with Service Accounts

Role-Based Access Control (RBAC)

Service accounts themselves don't provide permissions - they must be bound to Roles or ClusterRoles through RoleBindings or ClusterRoleBindings.

Understanding RBAC Components

graph TD A[Service Account] --> B[RoleBinding/ClusterRoleBinding] B --> C[Role/ClusterRole] C --> D[Rules] D --> E[API Groups] D --> F[Resources] D --> G[Verbs]
RBAC Component Purpose Scope
Role Defines permissions to resources Namespace-specific
ClusterRole Defines permissions to resources Cluster-wide
RoleBinding Binds service account to role Namespace-specific
ClusterRoleBinding Binds service account to cluster role Cluster-wide

Complete RBAC Example

# Service Account Definition
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring-agent
  namespace: monitoring
---
# Token Secret (K8s 1.24+)
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  name: monitoring-agent-token
  namespace: monitoring
  annotations:
    kubernetes.io/service-account.name: "monitoring-agent"
---
# Role Definition - Namespace Scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-metrics-reader
  namespace: monitoring
rules:
- apiGroups: [""]
  resources: ["pods", "pods/metrics"]
  verbs: ["get", "list"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["pods"]
  verbs: ["get", "list"]
---
# RoleBinding - Binds Service Account to Role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: monitoring-agent-metrics-reader
  namespace: monitoring
subjects:
- kind: ServiceAccount
  name: monitoring-agent
  namespace: monitoring
roleRef:
  kind: Role
  name: pod-metrics-reader
  apiGroup: rbac.authorization.k8s.io
---
# ClusterRole Definition - Cluster Scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-metrics-reader
rules:
- apiGroups: [""]
  resources: ["nodes", "nodes/metrics", "nodes/stats"]
  verbs: ["get", "list"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["nodes"]
  verbs: ["get", "list"]
---
# ClusterRoleBinding - Binds Service Account to ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-agent-node-metrics-reader
subjects:
- kind: ServiceAccount
  name: monitoring-agent
  namespace: monitoring
roleRef:
  kind: ClusterRole
  name: node-metrics-reader
  apiGroup: rbac.authorization.k8s.io



Practical Service Account Examples

Examining Service Account in a Pod

Let’s look at how a service account manifests inside a running Pod:

# Check which service account is used by a Pod
kubectl describe pod -n somaz somaz-db-d7d785ff4-mwgfm

Output:

Mounts:
  /etc/mysql/conf.d from config-volume (rw)
  /var/lib/mysql from mysql-persistent-storage-dev2 (rw)
  /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9dnzq (ro)

Examining the Service Account Tokens

# List files in the service account mount
kubectl exec -ti -n somaz somaz-db-d7d785ff4-mwgfm -- ls -l /var/run/secrets/kubernetes.io/serviceaccount/

total 0
lrwxrwxrwx 1 root root 13 Apr 12 10:00 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Apr 12 10:00 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Apr 12 10:00 token -> ..data/token

Creating and Binding Permissions

Below is an example of creating a Role and RoleBinding for a service account to access Pod information in a specific namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: somaz
rules:
  - apiGroups: [""] 
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: somaz 
subjects:
  - kind: ServiceAccount
    name: default
    namespace: somaz
roleRef:
  kind: Role 
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Testing API Access from a Pod

Once the permissions are set up, you can test the access from inside a Pod:

# Access the Pod
kubectl exec -ti -n somaz somaz-db-d7d785ff4-mwgfm -- bash

# Inside the Pod, access the Kubernetes API using the service account token
bash-4.4# cd /var/run/secrets/kubernetes.io/serviceaccount/
bash-4.4# TOKEN=$(cat token)
bash-4.4# curl -X GET https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/somaz/pods \
  --header "Authorization: Bearer $TOKEN" \
  --cacert ca.crt

API Access from Pod

The example above demonstrates how a Pod with the appropriate service account permissions can access the Kubernetes API server to retrieve information about other pods in the same namespace.



Common Questions and Best Practices

Frequently Asked Questions

What is $KUBERNETES_SERVICE_HOST?

$KUBERNETES_SERVICE_HOST is an environment variable automatically injected into all Pods. It contains the IP address of the Kubernetes API server, allowing Pods to communicate with it without hardcoding the address.

# Example:
echo $KUBERNETES_SERVICE_HOST
10.233.0.1

kubectl get service -n default
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.233.0.1   <none>        443/TCP   372d

Why are Pod and Cluster Token Values Different?

With Kubernetes 1.24+, tokens mounted in Pods are different from tokens stored in Secrets because:

  • Pod tokens are short-lived and automatically rotated
  • Pod tokens are audience-scoped and bound to the specific Pod
  • Pod tokens have a limited validity period (usually 1 hour by default)
  • Token rotation provides better security by limiting the impact of token compromise

This prevents long-term credential abuse if tokens are leaked.

Service Account Best Practices

Best Practice Description
Principle of Least Privilege Assign only the minimum necessary permissions to service accounts
Use Namespace-Scoped Roles Prefer Role/RoleBinding over ClusterRole/ClusterRoleBinding when possible
Custom Service Accounts Create dedicated service accounts for each application instead of using default
Disable automountServiceAccountToken Set automountServiceAccountToken: false for Pods that don't need API access
Audit Service Account Usage Regularly review service account permissions and bindings
Token Scope Limitation Use audience-restricted tokens with appropriate validity periods
Network Policies Restrict Pod network access to the API server when possible

Example: Custom Service Account with Limited Permissions

# Create a dedicated service account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-specific-account
  namespace: my-namespace
  annotations:
    kubernetes.io/description: "Service account for my application with limited permissions"
---
# Disable auto-mounting for pods that don't need it
apiVersion: v1
kind: Pod
metadata:
  name: no-api-access-pod
spec:
  serviceAccountName: default
  automountServiceAccountToken: false
  containers:
  - name: my-container
    image: nginx
---
# Create time-limited tokens when needed
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  name: time-limited-token
  annotations:
    kubernetes.io/service-account.name: "app-specific-account"
    kubernetes.io/service-account.expiration: "86400" # 24 hours in seconds



Advanced Service Account Topics

Service Account Impersonation

Kubernetes allows users with appropriate permissions to impersonate service accounts, which can be useful for debugging or testing permissions:

kubectl get pods --as=system:serviceaccount:namespace:serviceaccountname

External Identity Integration

Service accounts can be integrated with external identity providers:

  1. OIDC Integration: Through token exchange mechanisms
  2. Cloud Provider IAM: GCP Workload Identity, AWS IAM Roles for Service Accounts, Azure Pod Identity
  3. Vault Integration: HashiCorp Vault for dynamic secret generation

Service Accounts in CI/CD Pipelines

Best practices for using service accounts in CI/CD pipelines:

  1. Create dedicated service accounts for each pipeline with scoped permissions
  2. Rotate tokens regularly
  3. Store tokens securely in CI/CD secret management
  4. Audit pipeline service account usage



References