13 min to read
Kubernetes Service Accounts
Authentication and Authorization for Pod-based Applications

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.
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.
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
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:
- Signed with the private key of the Kubernetes API server
- Can be verified using the corresponding public key
- Contains claims about the service account identity
- Used in HTTP Authorization header when making API requests
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:
- Used to validate the API server’s TLS certificate
- Prevents man-in-the-middle attacks
- Establishes secure TLS connection to the API server
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:
- Stored as plain text in the mounted volume
- Indicates which namespace the service account belongs to
- Used by client libraries to determine the default namespace
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:
- Assigns the default service account to pods that don’t specify a service account
- Ensures pods have a valid service account
- Modifies the pod spec to include volume mounts for service account tokens
2. ServiceAccount Token Controller
The ServiceAccount Token Controller is part of the kube-controller-manager and:
- Manages token generation for service accounts
- Creates and deletes token secrets when service accounts are created or deleted
- Removes tokens for deleted service accounts
- Adds tokens for new service accounts
3. ServiceAccount Controller
The ServiceAccount Controller ensures:
- Every namespace has a default service account
- Manages the lifecycle of service accounts
- Synchronizes service account resources with the cluster state
4. Token Request Projection
In Kubernetes 1.24+, the token request projection system:
- Generates short-lived tokens bound to specific pods
- Automatically rotates tokens before expiration
- Invalidates tokens when pods are deleted
- Provides tokens through the projected volume mechanism
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
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:
- OIDC Integration: Through token exchange mechanisms
- Cloud Provider IAM: GCP Workload Identity, AWS IAM Roles for Service Accounts, Azure Pod Identity
- Vault Integration: HashiCorp Vault for dynamic secret generation
Service Accounts in CI/CD Pipelines
Best practices for using service accounts in CI/CD pipelines:
- Create dedicated service accounts for each pipeline with scoped permissions
- Rotate tokens regularly
- Store tokens securely in CI/CD secret management
- Audit pipeline service account usage
Comments