Service Accounts in Kubernetes: Giving Your Workloads a Secure Identity
Learn what a service account is, how pods prove who they are to the cluster, how tokens are issued and rotated, how permissions are granted, and how to keep this powerful feature safe with least privilege and careful design.
Imagine a large office building where different visitors need access. People who work there carry a personal badge. But the building also has machines: delivery robots, cleaning drones, and automatic door controllers. These machines need to enter certain rooms to do their jobs, but they are not people, and they cannot carry a personal badge. So the building issues each kind of machine its own machine badge, which lists exactly which rooms it may enter. In Kubernetes, the programs running inside pods are those machines, and a service account is their badge. Understanding how it works, and how to keep it safe, is essential for anyone who runs software on a cluster.
1Why Workloads Need an Identity
Programs inside a cluster often need to talk to the cluster itself.
Most applications running in Kubernetes never need to speak to the cluster’s control system. A web server just answers requests, and a database just stores data. But some programs must. A monitoring tool needs to discover which pods exist so it can collect their metrics. An ingress controller needs to watch for new routes. A deployment tool needs to create and update resources. A program that manages certificates needs to write secrets. All of these programs talk to the Kubernetes API, the cluster’s central control interface.
The API does not simply let anyone in. Every request must answer two questions: who is asking, and are they allowed to do this? The first question is called authentication, and the second is authorisation. For a human administrator, authentication might use a company login. But a program inside a pod is not a human, and it needs a different way to prove who it is. That way is the service account.
Think of a hotel. Guests have room keys that open only their own rooms. Staff have cards that open service corridors. A cleaning robot needs a card too, but a robot card should open only the rooms it needs to clean, and nothing else. A service account is the robot’s card: it identifies the machine, and the permissions attached to it say which doors it may open.
What can go wrong without a clear identity
If every program in a cluster shared one identity with wide permissions, then a single compromised application could read secrets, delete workloads, or take over the whole cluster. A careful identity system gives each workload its own badge and only the permissions it truly needs, so that a break-in to one application stays small.
This guide assumes you know what a pod and a namespace are, but every new term is explained when it first appears. Security is a theme throughout, because service accounts sit right where convenience and risk meet.
2Users and Service Accounts: Two Kinds of Identity
Kubernetes treats people and programs differently.
Kubernetes distinguishes between two kinds of identities that can call its API. The first is a normal user, meaning a human such as an engineer or an administrator. Kubernetes has no object called a user. It does not store users at all. Instead, it trusts an outside system, such as a company login service or a certificate authority, to say who a person is.
The second kind is the service account, which represents a program. Unlike users, service accounts are real Kubernetes objects. They are created, listed, and deleted through the API, and they belong to a namespace. Because they are managed inside the cluster, they can be created automatically and in large numbers, one for each application, without involving any outside system.
| Aspect | Normal User | Service Account |
|---|---|---|
| Represents | A human, such as an engineer | A program running in a pod, or an automated tool |
| Stored as a Kubernetes object | No | Yes |
| Scope | Cluster-wide identity managed outside the cluster | Belongs to one namespace |
| How it proves identity | Certificates, company login tokens, or similar | A signed token issued by the cluster |
| Created by | An external identity system | Anyone allowed to create the object, or automatically |
| Typical lifetime | Tied to a person’s employment or session | Tied to the workload that uses it |
Employees are identified by the company’s personnel department, which is an outside system as far as a building’s door controllers are concerned. Machines, on the other hand, are registered directly in the building’s own equipment list. The building can add a new robot to that list in seconds without asking personnel.
Service accounts are not meant for people. Using a service account token as a personal login makes it hard to know who did what, and long-lived tokens shared among people are a common source of security incidents. People should use their own individual identities.
3What Exactly Is a ServiceAccount?
A small, namespaced object that names an identity for workloads.
A ServiceAccount is one of the simplest objects in Kubernetes. On its own, it is little more than a name inside a namespace, together with a few optional settings. Its power comes from the connections around it: pods can be told to run as a service account, the cluster issues tokens on its behalf, and permission rules can be attached to it.
Every namespace automatically contains a service account named default. When you create a pod without specifying which service account to use, the pod runs as the default one in its namespace. This is convenient, but it is also a hidden source of risk, because many pods end up sharing one identity that nobody chose deliberately.
The identity
A unique name within a namespace. Together with the namespace, it forms the identity that the API recognises.
The tokens
Signed credentials that the cluster issues so that a program can prove it is this service account.
The permissions
Rules, defined elsewhere, that say what this identity may do. A new service account has almost none.
The options
Settings such as whether tokens are automatically mounted into pods, and which image pull credentials pods inherit.
flowchart TD
NS[Namespace] --> SA1[ServiceAccount: default
created automatically]
NS --> SA2[ServiceAccount: web-app]
NS --> SA3[ServiceAccount: metrics-reader]
SA2 --> P1[Pod running the web app]
SA3 --> P2[Pod running the metrics tool]
SA1 --> P3[Pods with no service account chosen]
A service account is like a job title on a badge: “cleaning robot,” “delivery robot,” or “door controller.” The title alone opens no doors. What matters is the list of doors that the building’s security office attaches to that title.
Treat the default service account as a fallback, not a choice. Give each application its own named service account, so that permissions, audit records, and troubleshooting all point at something specific.
4How the API Sees a Service Account
Every request carries a name and a set of groups.
When a program uses a service account token to call the API, the API server turns the token into a username and a list of groups. The username follows a fixed pattern that includes the words “system”, “serviceaccount”, the namespace, and the service account name, joined together. This full name is what appears in permission rules and in audit records, so it is worth understanding.
| Item | What It Looks Like in Words | Why It Matters |
|---|---|---|
| Username | The reserved service account prefix, then the namespace, then the service account name | Used when granting permissions to this exact identity and when reading audit logs |
| Group for all service accounts | A reserved group containing every service account in the cluster | Rules on this group affect every workload identity |
| Group for one namespace | A reserved group containing every service account in that namespace | Rules on this group affect all workloads in the namespace |
| Authenticated group | A group containing every successfully identified caller | Baseline permissions given to anyone who is recognised |
A badge reader does not only see “cleaning robot.” It sees “robot number seven from the fourth floor,” and it also knows the robot belongs to the group “all robots” and the group “fourth-floor devices.” Security rules can then be written for one robot, for the fourth-floor devices, or for all robots.
Why groups deserve caution
Permission rules that mention a group apply to every member. A rule that grants a broad permission to the group of all service accounts silently gives that permission to every workload in the cluster, including ones created in the future. Such rules are convenient and dangerous, and reviewers should treat them with suspicion.
Granting permissions to a whole group of service accounts to solve one application’s problem. The permission then applies to everything, and it is easy to forget that it exists.
5Proving Identity: Tokens and How a Pod Gets One
A token is a signed statement from the cluster saying “this program is that service account.”
A service account token is a compact, signed piece of text that the cluster issues. It states which service account it belongs to, which namespace it is in, which audience it is meant for, and when it expires. The cluster signs it with a private key, so that anyone with the matching public key, notably the API server, can check that it is genuine and unaltered.
When a pod starts, the kubelet asks the API server for a token for the pod’s service account, and places it as a file inside the container. The program reads the file and sends the token with every API request. The API server checks the signature, the expiry, and the audience, and then knows exactly who is calling.
sequenceDiagram
participant K as Kubelet
participant API as API Server
participant P as Pod and application
K->>API: Request a token for this pod's service account
API-->>K: Signed token with expiry
K->>P: Place token as a file in the container
P->>API: Request with the token attached
API->>API: Check signature, expiry, audience, and pod
API-->>P: Identity accepted, authorisation checked next
A pod is created with a service account
The pod either names a service account or gets the default one from its namespace.
The kubelet requests a token
The node agent asks the API server to issue a token that is tied to this pod and this service account.
The token is mounted as a file
The token appears at a standard location inside every container of the pod, together with the cluster’s certificate authority and the namespace name.
The application reads and uses it
Client libraries find the token automatically and attach it to API requests as a bearer credential.
The kubelet refreshes it before it expires
The token is renewed automatically, and the file is updated in place, so long-running programs continue to work.
The token is a visitor pass printed by reception and handed to the robot as it enters the building. The pass carries a stamp that guards can verify, states who the robot is, and expires at a stated time. Reception reprints it before it expires so the robot keeps working.
6Projected Tokens Versus Legacy Tokens
Modern tokens are short-lived and bound to the pod; older tokens lived forever.
In early versions of Kubernetes, each service account automatically received a long-lived token stored in a Secret. That token never expired, was not tied to any pod, and could be copied and used from anywhere for as long as the service account existed. If a token leaked, the leak had no end date. This design was convenient but weak.
Modern clusters use projected tokens instead. A projected token is requested for a specific pod, has a limited lifetime, and is valid for a specific audience. It becomes invalid when the pod is deleted. The kubelet renews it automatically before it expires. In current versions, the cluster no longer creates the old long-lived secret tokens automatically. They can still be created by hand, but that is discouraged.
| Aspect | Legacy Secret Token | Projected Token |
|---|---|---|
| Lifetime | Does not expire | Limited, by default about an hour, and renewed automatically |
| Bound to a pod | No | Yes, invalid once the pod is gone |
| Audience | Not specific | Specific to an intended recipient |
| Stored as a Secret object | Yes, readable by anyone who can read secrets | No, delivered directly to the pod’s file system |
| Damage if leaked | Unlimited in time | Limited to the remaining lifetime and to the pod’s existence |
| Created automatically today | No, in current versions | Yes, for every pod that mounts a token |
flowchart LR
subgraph Legacy tokens
L1[Token stored in a Secret] --> L2[No expiry]
L2 --> L3[Works from anywhere]
L3 --> L4[Leak lasts until the service account is deleted]
end
subgraph Projected tokens
P1[Token delivered to the pod file system] --> P2[Expires and is renewed]
P2 --> P3[Bound to the pod and an audience]
P3 --> P4[Leak is limited in time and scope]
end
A legacy token is a master key cut once and never replaced, which works forever for anyone holding a copy. A projected token is a hotel key card that stops working at check-out time, opens only your room, and is cancelled when you leave.
Clusters that were created many versions ago may still contain old long-lived token secrets. Review and remove any that are not needed. Newer versions can help find and clean up those that are unused, but the review is still your responsibility.
7Inside a Token and How It Is Checked
A few claims in the token decide whether the API server accepts it.
A service account token is a signed structure with several statements, called claims. The API server reads these claims and checks each one before it trusts the caller. Knowing what they are makes it clear why a token stops working in certain situations.
Issuer
Who created the token. The API server accepts only tokens from its configured issuer, so tokens from other clusters are rejected.
Subject
The identity: the namespace and service account name. This becomes the username used for permission checks.
Audience
Who the token is meant for. A token for one audience is rejected by another, which limits where a stolen token can be used.
Expiry
When the token stops being valid. Expired tokens are rejected, which is why old tokens are safer than never-ending ones.
Bound object
The pod the token was issued for. If that pod no longer exists, the token is rejected, even if it has not expired.
flowchart TD
T[Token arrives at the API server] --> S{Signature valid?}
S -->|No| X[Rejected]
S -->|Yes| E{Expired?}
E -->|Yes| X
E -->|No| A{Audience accepted?}
A -->|No| X
A -->|Yes| B{Bound pod and service account still exist?}
B -->|No| X
B -->|Yes| OK[Identity established, authorisation next]
A guard checking a visitor pass looks for an official stamp, the expiry time, whether the pass is meant for this building, and whether the named host is still in the building. Failing any check means no entry.
Passing these checks only proves who the caller is. What the caller may do is decided in a second, separate step using permission rules. A perfectly valid token with no permissions can do almost nothing.
8Where the Token Lives and How Applications Use It
A standard location and a standard convention make it work with little effort.
Inside every container that mounts it, the token appears in a fixed directory. Next to the token file are two other files: the certificate authority the program should trust when talking to the API server, and a file containing the pod’s namespace. Together, they give a program everything it needs to talk to the API securely.
| File | Contents | Purpose |
|---|---|---|
| Token file | The signed service account token | Proves the program’s identity on each request |
| Certificate authority file | The cluster’s trusted certificate authority | Lets the program verify that it is really talking to the cluster’s API server |
| Namespace file | The name of the pod’s namespace | Tells the program where it lives, so it can work in its own namespace |
In-cluster configuration
The standard Kubernetes client libraries have a built-in mode, often called in-cluster configuration, which looks in this standard location, finds the token and certificate, and discovers the API server’s address from environment variables that Kubernetes sets in every container. A program using such a library needs no configuration at all to talk to its own cluster.
Because tokens expire and are renewed, a program that reads the token file once at start-up and never again will start to fail after the token expires, typically after about an hour. Modern client libraries re-read the file regularly. Older or hand-written clients may not, and they fail mysteriously long after they started.
sequenceDiagram
participant A as Application
participant F as Token file
participant K as Kubelet
participant API as API Server
A->>F: Read token
A->>API: Request with token
API-->>A: Success
Note over K,F: Token nears expiry, kubelet writes a fresh token
K->>F: Replace token
A->>F: Re-read token before next requests
A->>API: Request with the fresh token
API-->>A: Success
A robot that photographs its visitor pass on its first day and keeps showing the photo will be turned away when the pass expires, even though reception issued a new one. A sensible robot looks at the actual pass each time it enters.
9Granting Permissions with RBAC
A service account can do nothing until someone gives it permissions.
Role-based access control, usually shortened to RBAC, is the system that decides what an identity may do. It is built from four kinds of objects. A role lists permissions within one namespace, such as reading pods. A cluster role lists permissions that can apply cluster-wide, or can be reused in many namespaces. A role binding connects a role to one or more identities inside a namespace. A cluster role binding connects a cluster role to identities across the whole cluster.
Role
A list of allowed actions on certain resources, valid only inside one namespace.
ClusterRole
A list of allowed actions that can cover cluster-wide resources, or be reused across namespaces.
RoleBinding
Attaches a role or cluster role to identities, but only within one namespace.
ClusterRoleBinding
Attaches a cluster role to identities everywhere in the cluster. It is the most powerful and most dangerous binding.
flowchart LR
SA[ServiceAccount
metrics-reader in namespace shop] --> RB[RoleBinding in namespace shop]
R[Role: can read pods in namespace shop] --> RB
RB --> G[Permission granted:
read pods in shop only]
| Goal | Suitable Combination | Reach |
|---|---|---|
| Let an app read pods in its own namespace | Role plus RoleBinding | One namespace |
| Reuse one set of permissions in several namespaces | ClusterRole plus a RoleBinding in each namespace | Each chosen namespace only |
| Let a controller watch nodes, which are cluster-wide | ClusterRole plus ClusterRoleBinding | Whole cluster |
A role is a list of rooms, such as “kitchen and storeroom.” A binding is the security office writing the robot’s name next to that list. The robot then opens exactly those rooms. A cluster-wide binding is like a master key list that opens the same rooms on every floor.
Giving a service account the highest-level administrator role because “it was easier.” A compromise of that single application then gives an attacker control of the whole cluster. Always start from no permissions and add only what the application demonstrably needs.
10The Default Service Account and Its Risks
A shared identity that nobody chose is a quiet source of trouble.
Every namespace has a service account called default, and every pod that does not name another one runs as it. In a fresh cluster, the default service account has no meaningful permissions, so the arrangement looks harmless. The danger appears over time. Someone needs a quick fix, grants a permission to the default service account, and from that moment every pod in the namespace that relies on it silently inherits that permission, including pods created later by other teams for unrelated purposes.
flowchart TD
A[Someone grants a permission to the default service account] --> B[All pods using the default inherit it]
B --> C[New unrelated pods appear in the namespace]
C --> D[They inherit the permission too]
D --> E[A compromised pod can now use that permission]
Why teams use the default
- It exists already, so nothing needs to be created
- It works out of the box for programs that never call the API
- It requires no extra configuration in pod definitions
Why it is risky
- Permissions granted to it apply to every pod that uses it
- It hides which workload actually needs which permission
- Audit records cannot tell workloads apart
- It mounts a token into pods that never needed one
Imagine a single shared visitor badge kept at reception for anyone who forgets theirs. If somebody once added kitchen access to it to help a plumber, every future visitor who picks it up can enter the kitchen. A badge for each visitor, with its own list of rooms, avoids the problem.
Leave the default service account without any permissions, and, for workloads that do not need the API, switch off token mounting. Give every application that does need the API its own named service account.
11Creating and Assigning Service Accounts
The workflow is simple: create the identity, grant permissions, and tell the pod to use it.
Create the service account
Make a named service account in the namespace where the application will run. Choose a name that describes the application.
Define the permissions needed
List exactly what the application must do with the API: which resources, which actions, in which namespaces. Write a role that contains only that.
Bind the role to the service account
Create a binding that connects the role to the service account, using a namespaced binding wherever possible.
Set the service account in the pod template
Name the service account in the workload definition, so every pod created from it runs with that identity.
Test the permissions
Ask the cluster whether the identity may perform the actions it should, and, just as importantly, whether it is denied actions it should not have.
Same namespace only
A pod can use only a service account from its own namespace. It cannot borrow one from another namespace.
Fixed after creation
A pod’s service account cannot be changed once the pod exists. To change it, update the workload template so that new pods replace the old ones.
Must exist first
If a pod names a service account that does not exist, the pod is refused. Create the identity before the workload that uses it.
Bindings can cross namespaces
A permission rule may name a service account from any namespace, as long as the namespace is stated in the binding.
Cluster tools let you test permissions by asking, on behalf of a given service account, whether an action would be allowed. Use this to confirm both what works and what is properly forbidden before an application reaches production.
12Switching Off Automatic Token Mounting
If an application never talks to the API, it should not carry a key to it.
By default, Kubernetes mounts a token into every pod, whether or not the application ever uses it. For the large majority of applications, which serve web pages or process data and never call the Kubernetes API, this token is unnecessary. But it is still there, sitting in the file system. If an attacker takes control of the application, for example through a vulnerability, the token is an extra weapon lying within reach.
The setting that controls this is called automounting. It can be switched off on the service account, so that no pod using it receives a token, or on the individual pod, which overrides the service account setting. Applications that truly need the API can turn it back on for themselves.
| Where Set | Effect | When To Use |
|---|---|---|
| On the service account | No pod using this service account gets a token, unless the pod says otherwise | For service accounts that belong to applications that never call the API |
| On the pod | This pod does or does not get a token, overriding the service account setting | For exceptions, in either direction |
| On the default service account of a namespace | Every pod that falls back to the default has no token | As a namespace-wide safety net |
flowchart TD
A[Pod is created] --> B{Pod setting for automount present?}
B -->|Yes| C[Follow the pod setting]
B -->|No| D{Service account setting present?}
D -->|Yes| E[Follow the service account setting]
D -->|No| F[Default behaviour: mount a token]
A cleaner who only sweeps the lobby does not need a key to the server room. Handing everyone a full key ring by default, just in case, is convenient until one of them loses it.
Removing a token that is not needed is one of the cheapest and most effective security improvements available. It costs nothing, and it removes an attack path completely.
13Image Pull Secrets on a Service Account
A service account can also carry credentials for downloading container images.
Container images often live in private registries that require a login. Kubernetes stores such registry credentials in a special kind of secret, called an image pull secret. Normally, each pod lists the secrets it needs. That is easy to forget, and repeating it in every workload is tedious.
A service account can list image pull secrets, and every pod that runs as that service account automatically receives them. This is a convenient way to give a whole application, or a whole namespace if you use the default service account, access to a private registry without changing each workload definition.
sequenceDiagram
participant U as User
participant SA as ServiceAccount with pull secret listed
participant API as API Server
participant K as Kubelet
participant R as Private registry
U->>API: Create pod using the service account
API->>API: Add the service account's pull secrets to the pod
K->>R: Pull image using the credentials
R-->>K: Image delivered
K->>K: Start the container
Advantages
- Workload definitions stay clean and short
- One place to update registry credentials for an application
- Fewer failed pods caused by forgotten pull secrets
Points to watch
- Every pod using the service account can pull from that registry
- Registry credentials should be narrowly scoped and read-only
- Putting them on the default account shares them with every workload
Attaching powerful registry credentials, such as ones that can push images, to a widely used service account. Use pull-only credentials for pulling, and keep push credentials in the build system only.
14Tokens for Other Audiences and External Systems
A pod’s identity can be recognised beyond the cluster, without long-lived passwords.
Service account tokens are not only useful for the Kubernetes API. Because they are signed, time-limited, and carry an audience, they can prove a pod’s identity to other systems. A pod can request a projected token intended for a specific audience, such as a secrets manager or a cloud provider. The external system checks the signature against the cluster’s published public keys, and then trusts the identity in the token.
sequenceDiagram
participant P as Pod
participant K as Kubelet
participant X as External system such as a cloud or secrets manager
participant D as Cluster issuer keys, published for verification
K->>P: Mount token with audience for the external system
P->>X: Present token and ask for access
X->>D: Fetch public keys and verify signature
D-->>X: Keys
X->>X: Check issuer, subject, audience, expiry
X-->>P: Short-lived credentials for the external service
Cloud workload identity
Major cloud providers let a service account be mapped to a cloud identity, so a pod can call cloud services without stored access keys.
Secrets managers
External secret stores can trust a pod’s token, and hand it secrets according to the service account’s name and namespace.
Service-to-service identity
Identity frameworks and meshes can use the token to establish who a workload is, and then issue their own certificates.
Custom internal services
Your own services can verify tokens for their audience, so that only genuine workloads from your cluster may call them.
A robot from one building visits a partner company. The reception there does not know the robot, but it trusts the first building’s stamp. It checks the stamp, sees the robot’s name and purpose, and hands over a temporary pass for its own premises. No permanent key needs to be sent across town.
Cloud access keys stored in secrets are long-lived and easy to leak. Exchanging a short-lived, audience-bound token for cloud credentials removes the stored secret altogether and ties access to the identity and lifetime of the pod.
15Using Service Accounts from Outside the Cluster
Automation systems often need cluster access, and they need to get it safely.
Build pipelines and deployment tools frequently live outside the cluster, and yet they need to call its API. It is tempting to create a service account, generate a token that never expires, and paste it into the pipeline’s secret store. This works, and it is one of the most common ways clusters get compromised, because that token is a permanent key that can be copied and used from anywhere.
| Approach | How It Works | Risk | Better When |
|---|---|---|---|
| Long-lived token stored in a secret | A never-expiring token copied to the outside system | High: a leak has no end date | Avoid, except where nothing else is possible |
| Short-lived token requested on demand | The tool asks the cluster for a token that lasts minutes or hours | Low: a leak expires quickly | Scripts and jobs that can request a token when they run |
| Federated identity from the pipeline provider | The pipeline presents its own signed identity, and the cluster trusts it | Low: no stored secret at all | Modern pipelines that support identity federation |
| Agent running inside the cluster | A controller in the cluster pulls changes from a repository | Low: no inbound credentials needed | GitOps style delivery |
flowchart TD
A[Pipeline needs to deploy] --> B{Can it use federated identity?}
B -->|Yes| C[Use it: no stored secret]
B -->|No| D{Can it request a short-lived token?}
D -->|Yes| E[Request a token with a short lifetime for each run]
D -->|No| F{Can deployment be pulled from inside the cluster?}
F -->|Yes| G[Use an in-cluster delivery agent]
F -->|No| H[Last resort: long-lived token, tightly scoped and rotated]
Handing a contractor a permanent key to the building is easy and risky. Issuing a day pass each morning, or letting a trusted resident let them in, is a little more work and much safer, because a lost day pass is worthless tomorrow.
Whatever the method, give the automation’s service account only the permissions it needs, in only the namespaces it deploys to. A deployment tool rarely needs to read secrets or manage permissions across the whole cluster.
16Common Use Cases for Service Accounts
Who actually needs a service account with permissions?
Monitoring and metrics collectors
Tools that discover pods and services in order to scrape their metrics need read access to those objects. A read-only role bound to a dedicated service account is the standard approach.
Ingress and gateway controllers
They watch Services, Endpoints, and Ingress objects to configure routing. They need read access to these and sometimes write access to update status.
Operators and custom controllers
Programs that manage other objects, such as databases or certificates, need permissions to create, update, and delete exactly those objects, and to watch for changes.
Continuous delivery agents
Tools that apply manifests need permissions to create and update workloads in the namespaces they manage, and nowhere else.
Autoscalers and cluster maintenance tools
Components that resize workloads or nodes need targeted permissions over the objects they scale, and nothing more.
Applications that read their own configuration
Some applications read a configuration map or a secret from the API at start-up. A role that allows reading only those named objects is enough.
Workloads that use cloud services
Applications that store files in cloud storage or call managed services use their service account as the identity to obtain cloud access without stored keys.
For any new workload, ask: does this program need to call the Kubernetes API at all? If not, give it a dedicated service account with no permissions and no token. If yes, write down exactly which calls it makes.
17Privilege Escalation: How Small Permissions Become Big Ones
Some permissions look modest but effectively hand over much more.
Not all permissions are equal. Some seem small, yet they allow a holder to obtain far greater powers. Understanding these escalation paths is central to service account security, because an attacker who takes over one pod usually starts with the modest permissions of its service account and then looks for a way up.
| Permission | Why It Is More Powerful Than It Looks | Safer Approach |
|---|---|---|
| Create pods in a namespace | The holder can start a pod that runs as any service account in that namespace, and thereby obtain that account’s permissions | Restrict who can create pods, and keep powerful service accounts out of shared namespaces |
| Read secrets | Secrets may hold tokens, passwords, and keys for other systems | Grant reading only of specific named secrets, when unavoidable |
| Create tokens for service accounts | The holder can mint credentials for any service account they may name, including more powerful ones | Reserve this permission for trusted administrators and specific accounts |
| Modify roles and bindings | The holder can grant themselves or others any permission | Limit strictly, and use the built-in safeguards that prevent granting more than you hold |
| Impersonate other identities | The holder can act as any identity they may impersonate | Grant only for named identities and only where essential |
| Run commands inside pods | The holder can enter any pod and read its token and data | Restrict, especially in namespaces with sensitive workloads |
flowchart TD
A[Attacker compromises a low-privilege pod] --> B[Reads its service account token]
B --> C{Can the account create pods in the namespace?}
C -->|Yes| D[Starts a new pod using a more powerful service account]
D --> E[Gains that account's permissions]
C -->|No| F{Can it read secrets or create tokens?}
F -->|Yes| G[Obtains credentials of other identities]
G --> E
F -->|No| H[Damage stays limited]
Permission to order new staff badges sounds harmless, but the person who can order a badge for the head of security has effectively got the head of security’s access. Some permissions are keys to making other keys.
Because being able to create pods equals being able to use any service account in that namespace, place highly privileged service accounts in namespaces where only trusted administrators can create workloads, and never in shared, general-purpose namespaces.
18Hardening Service Accounts with Least Privilege
A set of habits that keep the identity system small, clear, and safe.
One service account per workload
Give every application its own identity, so that permissions and audit records point to a single, specific thing.
Start with nothing and add narrowly
Begin with no permissions. Add only the exact resources and actions needed, preferably in one namespace, and name the specific objects where possible.
Turn off tokens for workloads that do not call the API
Disable automatic mounting, so that a compromise of such a workload does not also yield an API credential.
Avoid cluster-wide bindings
Use namespaced bindings wherever possible, and treat every cluster-wide binding as an exception that needs a written reason.
Prefer short-lived, bound tokens
Use projected tokens, request short lifetimes for outside use, and remove old long-lived secret tokens.
Review regularly
Periodically list which identities hold which permissions, remove unused ones, and check for dangerous combinations.
Admission policies
Automated rules can block pods that use the default service account, or that request cluster administrator bindings, before they are ever created.
Network policies
Restrict which pods can reach the API server at all, so that a stolen token is harder to use from an unexpected place.
Pod hardening
Run containers with reduced privileges and read-only file systems, so that a compromise cannot easily reach the token or other secrets.
Namespace separation
Keep sensitive workloads and powerful identities in separate namespaces with restricted access to create pods.
No single measure is enough. Combine narrow permissions, short-lived tokens, disabled mounting, network restrictions, and admission rules, so that a failure in one layer is caught by another.
19Auditing and Monitoring Service Accounts
If you cannot see what an identity does, you cannot tell when it goes wrong.
Every request to the API can be recorded in the audit log, together with the identity that made it. For service accounts, the recorded username is the full name that includes the namespace and the account name. This is why one service account per workload matters so much: when the log shows an unexpected action, the name points to the exact application, and you can investigate the right place immediately.
Denied requests
Repeated denials from a service account often mean a misconfigured application, or an attacker trying things their identity is not allowed to do.
Unusual actions
A service account that suddenly reads secrets, creates pods, or lists other namespaces, when it never did before, deserves immediate attention.
Token creation events
Requests that mint tokens for service accounts are rare in a healthy cluster. Alert when they come from unexpected callers.
Permission changes
Creation or change of roles and bindings, especially cluster-wide ones, should be logged, reviewed, and alerted on.
Requests from unexpected places
A service account token used from outside the cluster network, or from a pod that should not be using it, suggests theft.
flowchart TD
A[API request with service account token] --> L[Audit log entry:
identity, action, resource, result]
L --> S[Log collection and search]
S --> R1[Alert: many denied requests]
S --> R2[Alert: secrets read by unexpected account]
S --> R3[Alert: new cluster-wide binding created]
S --> R4[Alert: token minted for a privileged account]
R1 --> I[Investigate the workload behind the name]
R2 --> I
R3 --> I
R4 --> I
A building’s door log records which badge opened which door and when. If the cleaning robot’s badge suddenly opens the vault at three in the morning, the log shows it clearly, and security can react. With one shared badge for every machine, the log would tell them nothing.
Besides live alerts, periodically list every service account, every binding that mentions one, and every pod that uses each. Unused accounts and forgotten powerful bindings are best found in a scheduled review, not in an incident.
20Troubleshooting Service Account Problems
Most problems are either a missing permission, a missing token, or an expired one.
When an application cannot talk to the API, the error message usually tells you which of the three groups of problem you face. A forbidden error means the identity was recognised but not permitted. An unauthorised error means the identity was not recognised at all, often because of a missing, expired, or invalid token. A refused pod creation points to a missing service account. Reading the exact message carefully saves a lot of guessing.
Read the error message
Forbidden messages name the identity, the action, and the resource. That is exactly the information needed to write the missing permission.
Confirm which service account the pod uses
Look at the running pod, not only the workload template. Confirm the account name, and check it is the one you expected.
Ask the cluster whether the action is allowed
Test the exact action on behalf of that service account. A denial confirms a permission problem; an approval points to another cause.
Check the bindings
Verify that a binding exists, that it names the right service account and namespace, and that it points to the intended role.
Check the token inside the pod
Confirm that a token file exists. If automounting is switched off, no token is present, and the program cannot authenticate.
Consider token refresh
If the application works for a while and then fails, it may not be re-reading the token file after renewal.
| Symptom | Likely Cause | What To Do |
|---|---|---|
| Forbidden error naming the service account | Missing or too narrow permission | Add the specific permission through a role and binding |
| Forbidden although a binding exists | Binding names the wrong namespace, account, or role | Check names and namespaces in the binding carefully |
| Unauthorised error | No token, expired token, or token for a different cluster | Check mounting, expiry, and issuer |
| Pod is refused because the service account is not found | Account does not exist in the pod’s namespace | Create it first, or correct the name |
| Application fails about an hour after start | Client reads the token only once | Update the client library, or make it re-read the file |
| No token file in the container | Automounting is disabled | Enable it on the pod, or use a projected token explicitly |
| External system rejects the token | Wrong audience, or issuer not trusted | Request a token for the right audience and configure trust |
| Image pull fails despite a pull secret on the account | Pod uses a different service account, or the secret is in another namespace | Confirm the account and that the secret is in the same namespace |
A forbidden message is a gift: it states the identity, verb, and resource. Copy those three pieces into your permission rule, and resist the temptation to solve it by granting broad rights.
21Performance and Scale Considerations
Identity is cheap, but token handling and permission checks add up in large clusters.
Service accounts themselves are tiny objects, and having thousands of them is not a problem. The costs come from the activity around them. Every pod that mounts a token causes the kubelet to request one and to renew it periodically. Every API request triggers a permission check. Clusters with many pods, and applications that call the API very frequently, generate a lot of both.
Advantages
- Creating identities is cheap and fully automatable
- Token signing and checking is fast
- Tokens are renewed by the kubelet without application effort
- Narrow permissions reduce blast radius without any performance cost
Disadvantages / Trade-offs
- Many pods with tokens create steady token requests and renewals
- Chatty applications that poll the API add load to the API server
- Very large numbers of bindings make permission review harder
- Wide watches by many identities increase API server work
Do not mount tokens needlessly
Every mounted token means renewals. Removing tokens from pods that do not use them lowers both risk and load.
Prefer watches over polling
Applications that must track changes should use the API’s watch mechanism instead of repeatedly listing everything.
Keep permissions understandable
Reuse a small set of well-named roles rather than thousands of one-off rules, so that reviews remain possible.
Cache in the application
Programs that read the same configuration repeatedly should cache it and refresh occasionally, instead of asking the API on every request.
22Design Patterns for Service Accounts
Reliable arrangements used in well-run clusters.
Pattern: One identity per workload, named after it
Every application gets a service account named for its purpose. Permissions, audit records, and cloud identity mappings then line up one-to-one with real software.
Pattern: Namespaced roles with minimal verbs
Write roles that list only the specific resources and actions needed, prefer read-only verbs, and name individual objects when a program uses only a few.
Pattern: No token unless needed
Disable automounting by default, and enable it explicitly only for workloads that call the API. Make tokenless the normal state.
Pattern: Workload identity for cloud access
Map service accounts to cloud identities so pods obtain short-lived cloud credentials, and no cloud access keys are stored in the cluster.
Pattern: Policy as guardrail
Use admission policies to refuse pods that use the default account, to forbid cluster administrator bindings for workloads, and to require explicit automount settings.
Pattern: Templates for new applications
Provide a standard package that creates the service account, a minimal role, and the binding together, so teams start from a safe baseline instead of improvising.
flowchart TD
A[New application] --> B[Create dedicated service account]
B --> C{Needs Kubernetes API?}
C -->|No| D[Disable token mounting, no permissions]
C -->|Yes| E[Write minimal namespaced role]
E --> F[Bind role to the service account]
F --> G{Needs cloud or external access?}
G -->|Yes| H[Map to workload identity with narrow scope]
G -->|No| I[Done]
D --> I
H --> I
23Anti-patterns to Avoid
Habits that create quiet, serious risk.
Problem
Granting cluster administrator rights to a workload’s service account.
Why It’s Harmful
Any compromise of that application gives an attacker complete control of the cluster.
Correct Approach
Write a narrow role for exactly what the application does, and bind it in the smallest scope possible.
Problem
Adding permissions to the default service account.
Why It’s Harmful
Every pod that falls back to it, now and in the future, inherits the permissions without anyone deciding so.
Correct Approach
Create a dedicated service account for the workload that needs the permission, and leave the default account empty.
Problem
Storing long-lived service account tokens in pipelines or on laptops.
Why It’s Harmful
The tokens never expire, are easy to copy, and are often found in repositories and logs, giving permanent access to anyone who finds them.
Correct Approach
Use short-lived tokens, federated identity, or an in-cluster delivery agent instead of stored permanent keys.
Problem
Sharing one service account among many unrelated applications.
Why It’s Harmful
Permissions accumulate for the union of all needs, and audit records cannot say which application acted.
Correct Approach
Give each application its own identity with only its own permissions.
Problem
Leaving tokens mounted in pods that never call the API.
Why It’s Harmful
A compromise of the application also yields an API credential that was never needed.
Correct Approach
Disable automatic mounting for these workloads, and enable it only where required.
Problem
Using service accounts as shared human logins.
Why It’s Harmful
Actions cannot be traced to a person, and a departing employee keeps access through the shared token.
Correct Approach
Give people their own individual identities, and keep service accounts for programs.
Problem
Placing powerful service accounts in shared namespaces where many people can create pods.
Why It’s Harmful
Anyone who can create a pod there can run it as the powerful account and take its permissions.
Correct Approach
Keep powerful identities in locked-down namespaces where only trusted administrators can create workloads.
24Best Practices and Common Mistakes
A short checklist for safe use of service accounts.
Best Practices
- Create one named service account for each workload
- Leave the default service account without permissions
- Disable token mounting where the API is not used
- Write minimal, namespaced roles and avoid cluster-wide bindings
- Prefer short-lived, audience-bound projected tokens
- Use workload identity instead of stored cloud keys
- Audit permissions and activity on a regular schedule
Common Mistakes
- Confusing authentication with authorisation
- Granting groups of service accounts broad permissions
- Assuming that a pod’s service account can be changed while it runs
- Forgetting that clients must re-read rotated tokens
- Leaving old long-lived token secrets in the cluster
- Ignoring how pod creation rights lead to privilege escalation
For every service account, imagine that an attacker has stolen its token. Then read the permissions attached to it. If the result frightens you, the permissions are too broad. This simple exercise finds most problems early.
25Real-World Scenarios
How teams handle service accounts in daily operations.
A retailer limiting a breach
A vulnerability let an attacker take over a web application pod at a retailer. Because the application had its own service account with no permissions and no mounted token, the attacker could not reach the cluster API, and the incident stayed inside one pod. A neighbouring team, which had used the default account with administrator rights, was fixed within a day after the review that followed.
A startup removing stored cloud keys
A startup kept cloud access keys in cluster secrets, and rotated them rarely. They switched to workload identity: each application’s service account maps to a narrow cloud role, and pods receive short-lived credentials. The stored keys were deleted, and a leaked secret no longer meant a leaked cloud account.
A bank tightening its pipelines
A bank found a never-expiring service account token in its build system’s settings. The team replaced it with federated identity so that each pipeline run receives a short-lived credential, and the old token was revoked by deleting the secret and rotating the signing configuration for legacy tokens.
A platform team providing safe templates
A platform team offers application teams a standard package that creates a service account, a narrow role, and a binding, with token mounting off by default. An admission policy rejects pods that use the default account. New applications start secure without every team needing to be an expert.
An operations team fixing an hourly failure
An internal tool worked perfectly for an hour and then failed with unauthorised errors. The cause was an old client that read its token once at start-up. Upgrading the library, so that it re-reads the token file, removed the failures entirely.
26Frequently Asked Questions
A namespaced object that represents the identity of a program running in a pod, or of an automated tool. The cluster issues tokens for it, and permission rules decide what it may do.
Users represent humans and are managed outside the cluster. Service accounts represent programs, are real Kubernetes objects, and belong to a namespace.
Each namespace has one, and pods that name no other account run as it. It has no meaningful permissions by default, and permissions should not be added to it.
The kubelet requests a token from the API server for the pod’s service account and mounts it as a file in the container. The kubelet renews it before it expires.
Projected tokens, used by default in current versions, are time-limited and bound to the pod. Old-style secret tokens did not expire, and should be removed where possible.
Create a role that lists the allowed actions, and a binding that attaches the role to the service account. Use namespaced roles and bindings wherever possible.
No. Applications that never call the Kubernetes API should have automatic mounting disabled, which removes an unnecessary credential from the pod.
No. A pod can only use a service account from its own namespace, although permission bindings can refer to service accounts in other namespaces.
No. It is fixed at creation. Change the workload template so that new pods, which replace the old ones, use the new account.
Prefer federated identity or short-lived tokens requested on demand, or an in-cluster delivery agent. Avoid storing never-expiring tokens.
It probably reads the token file once and never again. Tokens are renewed, so clients must re-read the file. Use a current client library.
Through workload identity: the cluster’s token, signed and audience-bound, is exchanged with the cloud provider for short-lived cloud credentials, according to a mapping you configure.
27Summary and Key Takeaways
A service account is the identity of a program inside a Kubernetes cluster. It is a small namespaced object that the cluster uses to issue signed tokens, which pods present to the API server to prove who they are. What the identity is then allowed to do is decided separately, through roles and bindings. Modern clusters issue short-lived, pod-bound, audience-specific tokens that the kubelet renews automatically, replacing the never-expiring secret tokens of the past.
Because service accounts sit where convenience meets risk, the most important habits are simple: give each workload its own identity, start with no permissions, add only what is needed in the smallest scope, switch off tokens that are not used, prefer short-lived credentials over stored ones, and watch what identities actually do. Remember the escalation paths, especially that the right to create pods in a namespace is the right to use every identity in it. With these habits, service accounts give your workloads a safe, clear, and auditable identity.
Key Takeaways
- A service account is a workload’s identity — a namespaced object that lets programs authenticate to the API, distinct from human users managed outside the cluster.
- Tokens are short-lived and bound — projected tokens expire, are tied to a pod and an audience, and are renewed by the kubelet, so clients must re-read the token file.
- Authentication is not authorisation — a valid token only proves identity; roles and bindings decide what the identity can do, and a new account has almost nothing.
- Avoid the default account and shared accounts — dedicated accounts per workload keep permissions narrow and audit records meaningful.
- Do not mount tokens you do not need — disabling automatic mounting for workloads that never call the API removes a free weapon from attackers.
- Watch the escalation paths — creating pods, reading secrets, minting tokens, and editing permissions can each lead to far greater access than they seem to grant.
- Prefer short-lived, federated credentials — use workload identity and on-demand tokens instead of stored keys and permanent tokens, and audit activity regularly.