The B2B Podcast Index
Index
All categories
MarketingSalesSaaSFinanceHROpsLeadershipCustomer SuccessAI & DataProductStartups & FoundersRevOpsEngineering & DevTools
MethodologySubmit
Best of:MarketingSalesSaaSFinanceHROpsLeadershipCustomer SuccessAI & DataProductStartups & FoundersRevOpsEngineering & DevTools
An independent project byFame
SearchBest episodesGuestsInsightsMethodologySubmit a podcast
Index/Engineering & DevTools/DevOps Daily with Fexingo
DevOps Daily with Fexingo artwork

How Kubernetes ServiceAccount Token Expiration Breaks CI Workflows

DevOps Daily with Fexingo · 2026-07-30 · 9 min

0:00--:--

Key moments - from our scoring

Substance score

55 / 100

Five dimensions, 20 points each

Insight Density13 / 20
Originality9 / 20
Guest Caliber8 / 20
Specificity & Evidence14 / 20
Conversational Craft11 / 20

The shift to expiring ServiceAccount tokens in Kubernetes 1.24+ creates a hidden failure mode in CI/CD systems and applications: pods start with a valid token mounted as a projected volume, but if the workload runs longer than the TTL (typically one hour), subsequent API calls fail with 401 errors. The kubelet automatically rotates the token file on disk, but applications must actively re-read it - many older SDKs and tools like legacy Jenkins agents, GitLab runners, and even earlier ArgoCD versions don't handle this. Lucas and Luna walk through the mechanics of projected token volumes, the 'Bound Service Account Token Volume' pattern, sidecar-based token refresh strategies, and detection methods. The episode covers how to audit clusters for legacy token dependencies (checking kube-apiserver logs for 401s and inventorying pods using deprecated 'kubernetes.io/service-account' secrets), proper implementation patterns in client-go versus Python and Java SDKs, and why service meshes like Istio handle this differently. The core takeaway is that teams running workloads exceeding the token TTL must either upgrade their tooling, implement explicit token refresh logic, or use sidecar patterns - and that the migration from static tokens happened with minimal deprecation warning.

Key takeaways

  • →Kubernetes 1.24+ enforces one-hour-TTL tokens by default on projected volumes, causing long-running CI jobs and applications to fail with 401 errors when the token expires mid-operation.
  • →The kubelet rotates the token file automatically, but applications must re-read it; client-go handles this transparently, but Python and Java SDKs often require explicit file watchers or sidecar patterns.
  • →Audit existing clusters by checking kube-apiserver logs for 401 serviceaccount errors and inventorying pods that mount legacy 'kubernetes.io/service-account' secrets rather than projected volumes.
  • →Test cluster readiness by running a 90-minute workload to catch token expiration failures before they hit production, since failures are intermittent and often misattributed to networking or storage.
  • →The recommended fix is either explicit projected token volumes with configurable TTL, a sidecar that refreshes tokens via the TokenRequest API, or upgrading to SDK versions that handle token rotation automatically.

Topics in this episode

ci cd pipeline failure kuberneteskubernetes 1.24 token time to liveprojected service account token mountkubernetes token request apibound service account token volumeKubernetes 1.24+ ServiceAccount token expirationProjected token volumesclient-go InClusterConfigTokenRequest APIkube-apiserver 401 authentication logsArgoCD token refreshJenkins agents KubernetesGitLab runners ServiceAccountSPIFFE identity standardIstio sidecar proxy

Questions this episode answers

Why are my Kubernetes CI/CD pipelines failing with 401 errors after running for about an hour?

Kubernetes 1.24+ uses one-hour-TTL tokens by default; if your pods are using the legacy auto-mounted token and your application doesn't refresh it, the token expires mid-operation and subsequent API calls fail with 401 authentication errors.

How do I fix ServiceAccount token expiration in my cluster?

Use projected token volumes with explicit 'serviceAccountToken' entries in your pod spec that the kubelet rotates automatically, implement a sidecar that refreshes tokens via the TokenRequest API, or update to SDK versions like recent client-go that automatically re-read token files.

How can I detect if my cluster has pods vulnerable to token expiration?

Check kube-apiserver logs for 401 errors with 'serviceaccount' in the user field, and list pods that mount secrets of type 'kubernetes.io/service-account' - those are using the deprecated legacy token path.

Does the Python Kubernetes client automatically refresh tokens?

The 'load_incluster_config' helper reads the projected token but doesn't refresh automatically; you need to implement a file watcher or timer that reloads the config when the token file changes.

Why does ArgoCD fail to sync after a cluster upgrade to Kubernetes 1.24?

The ArgoCD Application controller's ServiceAccount token expires during long syncs in versions before 2.4; upgrading to 2.4+ or setting a longer TTL on a manually created ServiceAccount resolves this.

What our scoring noted

Our reviewer’s read on each dimension, with quotes from the episode.

Insight Density

13 / 20

For a 9-minute episode the content is impressively packed: SDK-specific rotation behaviour, the sidecar pattern, audit commands, and ArgoCD version-specific behaviour are all actionable. It loses points because the core K8s 1.24 token change is well-documented, and some segments rehash the same point (token expires, app breaks).

Most Go clients using client-go with the 'InClusterConfig' function do that automatically - but the Python and Java SDKs? Not always.
ArgoCD actually handles token refresh correctly since version 2.4, but older versions? You'd see sync stuck at 'OutOfSync' because the controller lost authentication.

Originality

9 / 20

The episode covers a real and specific problem but the content closely mirrors Kubernetes official docs and existing community blog posts; there is no contrarian angle or novel framework beyond the well-trodden 'upgrade broke your tokens' narrative. The one attempt at a fresh take - challenging whether the deprecation was too abrupt - is raised but dropped quickly.

Luna: Let me ask a controversial question: was this change too abrupt? The Kubernetes community removed the legacy token automount with only one minor version deprecation.
The security rationale is solid - stolen static tokens were a huge attack vector. But the migration path assumed that everyone would adopt the SDKs that refresh automatically.

Guest Caliber

8 / 20

There is no external guest; two co-hosts discuss the topic. They demonstrate solid hands-on knowledge and reference a real listener anecdote, but there is no verifiable seniority signal, no company affiliation, and no evidence of operating at scale beyond anecdote. Competent practitioner hosts, not notable caliber guests.

I spoke with a listener who runs a data processing job that takes about two hours. It kept failing mysteriously at the 55-minute mark. They blamed the network, the storage class, even the phase of the moon.
Lucas: That's a great point. ArgoCD actually handles token refresh correctly since version 2.4

Specificity & Evidence

14 / 20

Strong use of concrete specifics throughout: exact Kubernetes versions (1.24, 1.27), ArgoCD version (2.4), specific file paths, named functions (InClusterConfig, load_incluster_config), named tools (Jenkins, GitLab, Istio, Linkerd), and a real failure-time anecdote (55-minute mark). The only gap is no dollar-cost or scale metrics.

It kept failing mysteriously at the 55-minute mark.
check the kube-apiserver logs for 401 errors with 'serviceaccount' in the user field. Also, list all pods that mount a secret with 'kubernetes.io/service-account' - those are using the legacy path.

Conversational Craft

11 / 20

The hosts build on each other's points and systematically probe edge cases (external access, third-party meshes, operators), and Luna's 'controversial question' is a genuine attempt at pushback. However, the format is largely a structured setup-confirm loop rather than true interrogation; claims go unchallenged and the controversial question is resolved too quickly without real debate.

Luna: What about external access? Like, I'm running a CI job outside the cluster that uses kubectl with a token from a secret?
Luna: One more thing: what about third-party tools like Istio or Linkerd? Do they handle token refresh?

Conversation analysis

Computed from the transcript - who did the talking, and the words that came up most.

Most-used words

token38lucas17luna16kubernetes10cluster10serviceaccount8tokens7refresh7projected6volume6handle6client6code5bound5legacy5sidecar5

Episode notes

In this episode of DevOps Daily, Lucas and Luna explore a growing pain in Kubernetes clusters upgraded to version 1.24 and later: default ServiceAccount token expiration. They walk through the surprising moment a listener's CI pipeline stopped deploying, trace the root cause to a one-hour token time-to-live, and explain how to migrate to projected volume mounts with sidecar refresh. With practical before-and-after YAML and a warning about legacy SDKs that still assume permanent tokens, this is a timely survival guide for anyone running modern Kubernetes. Also, Lucas ties in a broader theme of deprecation velocity in cloud-native, and Luna pushes back on whether the change was disruptive by design. #Kubernetes #DevOps #ServiceAccount #TokenExpiration #CI-CD #CloudNative #Kubernetes124 #Security #Kubelet #ProjectedVolume #Technology #PodIdentity #Automation #SRE #FexingoBusiness #BusinessPodcast #DevOpsDaily #Deprecation Keep every episode free: buymeacoffee.com/fexingo

Full transcript

9 min

Transcribed and scored by The B2B Podcast Index.

Lucas: So you push a code change, your CI pipeline kicks off, it tries to deploy to your Kubernetes cluster - and it just sits there. The pod never comes up. No obvious error in the YAML. No memory or CPU limit hit.

What happened? Luna: I've seen that movie. The team spends an hour checking RBAC, then the namespace, then the image pull secret. But it's something more fundamental.

Lucas: Exactly. This is Episode 141 of DevOps Daily, and we're talking about the quietest breaking change in recent Kubernetes history: ServiceAccount token expiration. If you've upgraded your cluster to Kubernetes 1.24 or later - and by now, July 2026, most production clusters are at 1.

27 or higher - you've already got time-bound tokens by default. And if your CI/CD system or application relied on a long-lived token mounted automatically, it's probably broken. Luna: Let me guess - the default token time to live is one hour? And nobody told the developers?

Lucas: You nailed it. Starting in Kubernetes 1.24, the legacy auto-generated tokens with no expiry were disabled. The new default is a token with a one-hour TTL, and it's bound to the pod's lifetime.

But here's the catch: the token is mounted into the pod as a projected volume, but many SDKs and tools weren't built to handle token rotation. They grab the token at startup and never refresh. Luna: So the pipeline starts, pulls the token, and runs for maybe 45 minutes. Then the next API call hits the cluster and gets a 401.

The token expired while the pod was still alive. Lucas: That's exactly the pattern. I spoke with a listener who runs a data processing job that takes about two hours. It kept failing mysteriously at the 55-minute mark.

They blamed the network, the storage class, even the phase of the moon. The actual fix was switching to an explicitly created ServiceAccount that uses a projected mount with a sidecar that refreshes the token. Luna: Right, because the token itself is refreshed on disk by the kubelet. But the application has to actually re-read the file.

Most Go clients using client-go with the 'InClusterConfig' function do that automatically - but the Python and Java SDKs? Not always. Lucas: Let's break down the anatomy of the fix. The recommended approach is the 'Bound Service Account Token Volume' - you explicitly project a token with a desired expiration and a target audience.

Here's the YAML you'd add to a pod spec: volume with 'projected' sources, and inside that, a 'serviceAccountToken' entry. That mounts a token that the kubelet rotates before expiry. Luna: And you can set the 'expirationSeconds' down to as low as 10 minutes, or up to a day. But the key is that the file on disk changes, and your app must watch for that.

Some libraries like 'client-go' handle it; others you need to implement a file watcher. Lucas: Yeah. And then there's the sidecar pattern. You run a container that pulls the token via the TokenRequest API and dumps it to a shared volume, restarting your primary process or signaling it when the token refreshes.

It's heavier, but gives you control. Luna: Before we go deeper, quick honest thing - a handful of listeners chip in monthly through buy me a coffee dot com slash fexingo, and that's literally what funds making episodes like this. If today's tech conversation gave you something usable, that's where you can keep it ad-free. We don't run sponsors, so it's listener-supported.

Okay, back to tokens. Lucas: So the biggest trap is the legacy token automount. Before 1.24, every pod got a token in '/var/run/secrets/kubernetes.

io/serviceaccount' that never expired. Many CI runners, like Jenkins agents or GitLab runners, still rely on that. If you're on a newer cluster, you either need to create a ServiceAccount with 'automountServiceAccountToken: false' and handle it differently, or use the projected volume approach. Luna: But there's also the issue of controllers and operators that were written before the change.

I've seen ArgoCD sync fail because the Application controller's service account token expired mid-sync. Lucas: That's a great point. ArgoCD actually handles token refresh correctly since version 2.4, but older versions?

You'd see sync stuck at 'OutOfSync' because the controller lost authentication. The fix is to upgrade the controller or explicitly set a bound token with a longer TTL, which is allowed if you create the ServiceAccount manually. Luna: What about external access? Like, I'm running a CI job outside the cluster that uses kubectl with a token from a secret?

Lucas: That's a separate path. Secrets that hold tokens are themselves deprecated but not removed. If you manually create a Secret of type 'kubernetes.io/service account token', it will have a token that doesn't expire - but that's officially deprecated.

The better approach is to use the TokenRequest API from outside to get a time-bound token, or use a kubeconfig with a client certificate. Luna: So the overall message is: if your cluster was upgraded to 1.24 or later, and you haven't proactively updated your CI/CD or your in-cluster applications to handle token rotation, you're sitting on a time bomb. Lucas: Exactly.

And the worst part is that failures are intermittent - only when the token expires during a long-running operation. So teams often blame the network or the cloud provider. Let's talk about how to audit your cluster for this. You can check the kube-apiserver logs for 401 errors with 'serviceaccount' in the user field.

Also, list all pods that mount a secret with 'kubernetes.io/service-account' - those are using the legacy path. Luna: And for new code, what's the best practice? I'm thinking: use the client-go library with 'InClusterConfig', and if you're writing Python, use the 'kubernetes' client with token refresh logic or a sidecar.

Lucas: Right. The Python client has a helper called 'load_incluster_config' that reads the token from the projected volume, but it doesn't refresh automatically - you need to reload on a timer. Some teams wrap it with a file watcher that calls 'load_incluster_config' again when the token file changes. Luna: One more thing: what about third-party tools like Istio or Linkerd?

Do they handle token refresh? Lucas: Service meshes are actually a good example. Istio's sidecar proxy has its own identity using the SPIFFE standard, so it doesn't rely on Kubernetes ServiceAccount tokens for control plane auth. But the application itself still uses the projected token for its own calls.

So the sidecar might be fine, but your app code needs to handle it. Luna: Let me ask a controversial question: was this change too abrupt? The Kubernetes community removed the legacy token automount with only one minor version deprecation. A lot of teams got burned.

Lucas: I think it's a valid criticism. The security rationale is solid - stolen static tokens were a huge attack vector. But the migration path assumed that everyone would adopt the SDKs that refresh automatically. In practice, many internal tools and old containers were caught off guard.

The kubelet does rotate the token on disk, but if the code doesn't re-read it, it doesn't help. Luna: So the lesson: after any major upgrade, test your longest-running workloads. And make sure your CI pipelines run for at least an hour and ten minutes to catch token expiration. Lucas: That's a solid testing heuristic.

Also, use the ' - token-ttl' flag when you create a ServiceAccount to set a longer TTL if appropriate - but be careful, because longer-lived tokens are more dangerous if leaked. Luna: Alright, so recap: check your cluster version, audit your pods for legacy token mounts, update your CI runners, and implement token refresh in your code. That's the episode. Lucas: One final thought: if you haven't yet, test your cluster with a workload that runs for 90 minutes with minimal logging.

See if it still authenticates. That's the cheapest way to find out if you have this issue. Luna: Good advice. Thanks, Lucas.

Lucas: Thanks, Luna. We'll catch you next time on DevOps Daily.

More from DevOps Daily with Fexingo

All episodes →
  • How Kubernetes StatefulSet PVC Resizing Causes Node Disk Failures94 / 100
  • How Kubernetes Topology Spread Constraints Create Scheduling Hotspots95 / 100
  • How Kubernetes CRD Versioning Breaks Controller Upgrades90 / 100
  • How Kubernetes Audit Logging Causes etcd Performance Degradation91 / 100
  • How Kubernetes Volume Snapshots Cause Storage Backend Data Corruption85 / 100
Explore the best B2B Engineering & DevTools podcasts →
All DevOps Daily with Fexingo episodes →