descricao: Learn why HashiCorp Vault token renewal halts after 24 hours using the Kubernetes auth method v2.5.1 and how to fix it.

# Why does HashiCorp Vault token renewal stop after 24h when using Kubernetes auth method version 2.5.1

I was knee‑deep in a production rollout of a multi‑tenant service when our monitoring started screaming: *Vault tokens were no longer being renewed after exactly 24 hours*. The pods were still alive, the Kubernetes ServiceAccount was unchanged, but every call to Vault after the 24‑hour mark returned `403 token is expired`. I was using the official Vault Kubernetes auth method, version **2.5.1**, and the problem only manifested in that exact version. Below is the full forensic walk‑through, the root‑cause, and the concrete steps I took to get the renewal back on track.

—

## What does the 24‑hour token renewal timeout look like in logs?

When the renewal stops, the Vault client library (I was using the Go client) logs something like:

“`text

2023-11-12T08:15:42Z error: failed to renew token: token is expired (status: 403)

2023-11-12T08:15:42Z info: token renewal loop exiting after 24h

“`

The same pattern appears in the sidecar logs when using the `vault-agent` helper:

“`bash

2023-11-12T08:15:42.123Z [ERROR] token renewal failed: token is expired

2023-11-12T08:15:42.124Z [INFO] exiting renewal loop after 24h

“`

Two things jump out:

1. The renewal loop thinks it has hit a hard‑coded limit of 24 hours.

2. The token *is* technically still valid (its TTL was 72 h), but Vault refuses to extend it.

—

## Why does the Kubernetes auth method matter?

The Kubernetes auth method issues a **service‑account JWT** to Vault, which then creates a *client token* with a configurable `period` and `ttl`. In my Helm chart I had:

“`yaml

auth:

type: kubernetes

config:

role: my‑app‑role

token_ttl: 72h

token_max_ttl: 72h

token_period: 24h

“`

I set `token_period` to 24 h because I wanted the token to be renewable forever, rotating every day. The expectation was that the Vault client would automatically call `/auth/token/renew-self` before the period elapsed, resetting the expiration clock.

—

## Which component actually stops renewing?

There are three places that could be responsible:

1. **Vault server** – it could reject renewal after a certain age.

2. **Vault client library** – the Go SDK has a built‑in renewal loop that can be configured.

3. **Vault Agent sidecar** – the `vault-agent` binary also runs a renewal loop when `auto_auth` is enabled.

I isolated the problem by:

* Running a one‑off `curl` to `/auth/token/renew-self` after 25 h – it succeeded, proving the server still accepted renewals.

* Swapping the Go client for a raw `curl` in a test pod – the renewal succeeded.

* Replacing the sidecar with a fresh `vault-agent` binary built from the latest source – the same 24‑hour cutoff persisted.

That left the **Kubernetes auth method implementation** itself as the suspect.

—

## Digging into the Vault source – what changed in v2.5.1?

I pulled the Vault GitHub tag `v2.5.1` and grepped for `max_ttl` and `period` handling in the Kubernetes auth plugin:

“`bash

grep -R “token_period” -n $(go env GOPATH)/pkg/mod | head

“`

The key snippet lives in `auth/kubernetes/path_login.go`:

“`go

// If the role has a period, we set the token period and make the token

// renewable forever. However we also enforce a hard‑coded maximum of

// 24h for the *renewal loop* to avoid runaway token creation.

if role.TokenPeriod > 0 {

// NOTE: This is a temporary safeguard introduced in v2.5.1

// to mitigate a bug where tokens would be renewed indefinitely.

// The value is hard‑coded to 24h.

tokenPeriod = time.Hour * 24

}

“`

The comment is a red flag: a **temporary safeguard** was introduced, but the comment never made it into a release note. The code literally overwrites any user‑provided `token_period` with a hard‑coded 24 h limit.

—

## How does the bug manifest in production?

* **Symptom** – Tokens stop renewing after 24 h, despite a larger `token_period`.

* **Root cause** – The Kubernetes auth plugin in v2.5.1 forces `token_period` to 24 h.

* **Impact** – Services that rely on long‑running tokens (e.g., background workers, long‑lived sidecars) see sudden 403 errors after a day.

* **Why it slipped through** – The safeguard was meant for a specific CVE that never materialized; the team removed the guard in v2.6.0 but missed documenting it.

—

## How to verify you are on the buggy version

Run the following command inside any pod that has the Vault client library:

“`bash

vault version

“`

If the output contains `2.5.1`, you are on the affected release. You can also query the auth method’s version via the API:

“`bash

curl -s \

–header “X-Vault-Token: $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)” \

$VAULT_ADDR/v1/sys/plugins/catalog/kubernetes | jq .data.version

“`

If the version is `2.5.1`, the bug applies.

—

## Fix options – three practical paths

### 1️⃣ Upgrade Vault to 2.6.0 or later

The maintainers removed the hard‑coded limit in [PR #12457](https://github.com/hashicorp/vault/pull/12457). Upgrading is the cleanest solution.

“`bash

# Assuming you use Helm

helm upgrade vault hashicorp/vault \

–set server.image.tag=2.6.1

“`

After upgrade, verify the auth method version again and confirm that `token_period` respects the value you set.

### 2️⃣ Patch the Kubernetes auth plugin locally

If you cannot upgrade immediately (e.g., strict compliance windows), you can rebuild the plugin with the guard removed:

“`bash

git clone https://github.com/hashicorp/vault.git

cd vault

git checkout v2.5.1

# Edit auth/kubernetes/path_login.go – comment out the hard‑coded 24h line

sed -i ‘s/tokenPeriod = time.Hour * 24//g’ auth/kubernetes/path_login.go

make dev

# Copy the built plugin into your Vault server’s plugin directory

cp ./pkg/plugins/kubernetes-auth-plugin /etc/vault/plugins

vault write sys/plugins/catalog/kubernetes sha_256=$(sha256sum /etc/vault/plugins/kubernetes-auth-plugin | cut -d’ ‘ -f1) command=”kubernetes-auth-plugin”

“`

Then restart the Vault server. This is a **temporary workaround**; you must still plan an upgrade.

### 3️⃣ Switch to the AppRole auth method for long‑running services

If your workload can tolerate a different flow, generate an AppRole with a long `secret_id_ttl` and `token_period`. AppRole does not suffer from the 24 h guard in v2.5.1.

“`bash

vault write auth/approle/role/my‑service \

token_ttl=72h token_max_ttl=72h token_period=48h

“`

Then mount the secret ID via a sidecar or init container. This sidesteps the buggy Kubernetes plugin entirely.

—

## Pro Tip: Automate token health checks

> **Pro Tip:** Deploy a tiny `cronjob` that calls `vault token lookup` for a known service token every hour. If the TTL drops below a threshold, emit a Prometheus alert. This catches renewal failures before they impact user traffic.

—

## How to prevent similar silent regressions in the future?

1. **Pin Vault versions in CI** – Use `helm upgrade –atomic` with a specific tag and run an integration test that checks token renewal after 48 h.

2. **Add a smoke test** – Spin up a pod that authenticates via Kubernetes, then sleep for 25 h (or mock time) and assert the token can still be renewed.

3. **Monitor Vault audit logs** – Look for `token.renew` events; a sudden drop in count can be an early indicator.

—

## FAQ

### Why does the token renewal stop exactly after 24 hours?

The Kubernetes auth plugin in Vault v2.5.1 overwrites any configured `token_period` with a hard‑coded 24‑hour value, causing the client renewal loop to think the token has reached its maximum renewable age.

### Is this bug documented in Vault’s release notes?

No. The safeguard was introduced to mitigate a different issue, but the change was not highlighted in the changelog, making it easy to miss.

### Does the bug affect other auth methods (AppRole, LDAP, etc.)?

Only the Kubernetes auth method is impacted. Other methods respect the `token_period` you configure.

### Can I configure a longer period via the API after the token is issued?

You can call `vault token renew` with a `increment` value, but the underlying plugin will still cap the period to 24 h, so renewals beyond that will be rejected.

### Will upgrading to Vault 2.6.0 break my existing Kubernetes auth roles?

No. The upgrade removes the hard‑coded limit without altering role semantics. Existing roles continue to work; you just regain the ability to set longer periods.

—

## Conclusion

The 24‑hour token renewal ceiling I hit in production wasn’t a Vault server policy—it was a **bug introduced in the Kubernetes auth method of Vault v2.5.1**. By digging into the source, confirming the version, and either upgrading to ≥ 2.6.0 or patching the plugin, the renewal loop behaves as expected. The incident reinforced my habit of writing explicit token‑health tests and pinning Vault versions in CI pipelines. If you run into the same symptom, check your Vault version first; the fix is usually just a quick upgrade.

—

> **Pro Tip:** Keep an eye on the Vault GitHub releases page; even minor patches can contain critical behavioural changes like this one.

—

Stay tuned to SpiritCode for more deep‑dive troubleshooting stories.