Token Basics
Every Kubernetes pod is associated with a service account. By default, this is the default service account in the pod's namespace. A JWT token for that service account is automatically mounted at /var/run/secrets/kubernetes.io/serviceaccount/token inside every container in the pod, unless the pod spec explicitly sets automountServiceAccountToken: false.
The token is a Kubernetes-signed JWT that authenticates the pod to the cluster's API server. Its claims include the service account name and namespace. The API server validates the token signature and applies the RBAC bindings for the service account. Every pod that does not disable auto-mounting is therefore pre-authenticated to the cluster API with whatever permissions its service account has β available to any code executing inside the container.
No secret required: Attacking a Kubernetes service account token requires no credential theft in the traditional sense. The token is already inside the container, at a predictable path, readable by any process in the container. "Theft" in this context means using the token from outside the pod's expected context β which requires first achieving code execution inside the pod.
RBAC Escalation Paths
The damage an attacker can do with a stolen service account token depends entirely on the RBAC bindings attached to that service account. In a poorly configured cluster, several common patterns create escalation paths:
- Wildcard cluster roles:
rules: [{apiGroups: ["*"], resources: ["*"], verbs: ["*"]}]β cluster admin via the service account. Any pod with this binding is a full cluster takeover if compromised. - Secrets read access: A service account with
getorlistonsecretsresources can read every secret in its namespace (or the entire cluster if the binding is a ClusterRoleBinding). Kubernetes Secrets store TLS certificates, database credentials, container registry credentials, and application API keys. - Create pods permission: A service account that can create pods can create a privileged pod with
hostPID: true,hostNetwork: true, andhostPathmounts β enabling container escape to the node. - RBAC create/update permission: A service account with permission to create or modify RBAC resources can grant itself or other service accounts any permission, including cluster admin.
Cloud Environment Pivot
In managed Kubernetes environments (EKS, GKE, AKE), the integration between Kubernetes service accounts and cloud IAM creates an additional escalation surface. Both AWS EKS Pod Identity and GCP Workload Identity allow a Kubernetes service account to be mapped to a cloud IAM role β granting pods running under that service account the ability to make authenticated calls to cloud APIs.
An attacker who steals a service account token with a cloud IAM binding can request cloud credentials directly from the cloud provider's metadata endpoint, using the Kubernetes token as proof of identity. The resulting cloud credentials grant the permissions of the mapped IAM role β which may include S3 bucket access, RDS database access, Secrets Manager reads, or broader IAM permissions depending on how the role was configured.
The cluster-to-cloud boundary is porous by design: EKS Pod Identity and GKE Workload Identity are intended to make cloud access from pods seamless. That seamlessness is also what makes a compromised pod's service account a direct path to cloud resources. The mapping between Kubernetes identities and cloud roles needs the same least-privilege review as any IAM configuration.
Audit Logging Gaps
Kubernetes audit logging is the primary mechanism for detecting service account token abuse. The audit log records every API call made to the cluster API server, including the identity (service account) and source IP. Reviewing audit logs for service account API calls from unexpected source IPs is the canonical detection for token theft and use outside the pod.
The problem is that audit logging is not enabled by default in all Kubernetes distributions, and where it is enabled, the verbosity level significantly affects what is captured. Many clusters run with a minimal audit policy that logs only authentication failures and high-privilege operations β missing the reconnaissance phase (list pods, list secrets, check permissions) that precedes an actual attack.
Detection Patterns
- API calls from service accounts made from external IP addresses: A service account for a pod should only make API calls from within the cluster's IP range. Any audit log entry showing a service account authenticated from an external IP is a strong signal of token theft and external use.
- Self-subject rules review calls: Attackers commonly call
selfsubjectrulesreviewsorselfsubjectaccessreviewsto discover what permissions they have. This is a reconnaissance signal β legitimate applications rarely need to enumerate their own permissions at runtime. - Secret list/get calls from pods that don't normally access secrets: If a pod's service account suddenly starts reading secrets, either the application changed behaviour or the token was stolen. Both are worth investigating.
- Privileged pod creation from a service account: Any pod creation request that includes
securityContext.privileged: true,hostPID,hostNetwork, orhostPathmounts from a service account that has not historically created pods should trigger immediate review.
Hardening Controls
- Disable auto-mounting for pods that don't need cluster API access: The vast majority of application pods do not need to call the Kubernetes API. Set
automountServiceAccountToken: falsein the pod spec or on the service account itself. This eliminates the token attack surface entirely for those workloads. - Create dedicated service accounts for each workload: Never share service accounts between workloads. Each deployment should have its own service account with the minimum permissions for that workload only. This limits blast radius β a compromised pod's token only grants that workload's permissions.
- Use Kubernetes token projection with short expiry: Projected service account tokens (enabled by default in Kubernetes 1.20+) are time-limited and audience-bound. Set
expirationSecondsto a short duration (e.g., 3600 seconds) so that a stolen token expires quickly. - Audit all RBAC bindings regularly: Review ClusterRoleBindings and RoleBindings quarterly. Remove any binding that grants secrets access, pod creation, or RBAC modification to service accounts that do not strictly require those permissions.
- Enable and review Kubernetes audit logs with a meaningful policy: Deploy an audit policy that captures at minimum: authentication events, secret access, pod creation, and RBAC changes. Ship audit logs to a SIEM and alert on the detection patterns above.
- Scope cloud IAM role bindings to specific service accounts: When using EKS Pod Identity or GKE Workload Identity, bind cloud IAM roles to specific service accounts in specific namespaces, not to broad service account patterns or all service accounts.
Service account token theft is not a novel attack technique β it has been documented since early Kubernetes adoption. It remains effective because the defaults (auto-mounting, shared service accounts, permissive RBAC) create the surface, and most organisations have not systematically addressed the defaults. The controls are known and straightforward to apply. The obstacle is operational discipline, not technical difficulty.