
Kubernetes 1.34 loses upstream support on October 27, 2026. That date doesn't announce itself. Nobody gets a banner in their terminal. The clusters that are still on 1.34 after that day just keep running, quietly outside the window where anyone will ship them a security patch.
If you manage more than one or two clusters, you've probably lost track of which ones need an upgrade plan. The fix isn't a spreadsheet you remember to check. It's a script that checks for you, using the same kubernetes Python client you'd use to talk to the API server for anything else.
The support window, in one table
Kubernetes supports the three most recent minor releases at any time (the current one, plus the two before it), and each minor release gets roughly 14 months of patches from its GA date. That gives you a known end-of-life date per minor version, months in advance. The problem is remembering to look it up for every cluster you run.
The script
This connects to every context in your kubeconfig, reads the server version with the official VersionApi, and compares it against a table of EOL dates. Install the client first:
pip install kubernetesThen the audit script itself:
#!/usr/bin/env python3
"""Audit every cluster in your kubeconfig against the Kubernetes support window."""
import re
import sys
from datetime import date
from kubernetes import client, config
# Known upstream EOL dates (end of the ~14-month support window from GA).
# Source: the official Kubernetes release history.
# verify: confirm exact dates against kubernetes.io/releases before relying on this in CI
EOL_DATES = {
(1, 31): date(2025, 10, 28),
(1, 32): date(2026, 2, 28),
(1, 33): date(2026, 6, 28),
(1, 34): date(2026, 10, 27),
(1, 35): date(2027, 2, 28),
}
WARNING_WINDOW_DAYS = 60
def cluster_versions():
"""Yield (context_name, major, minor, git_version) for every context in kubeconfig."""
contexts, _ = config.list_kube_config_contexts()
for ctx in contexts:
name = ctx["name"]
api_client = config.new_client_from_config(context=name)
version_info = client.VersionApi(api_client).get_code()
match = re.match(r"v(\d+)\.(\d+)", version_info.git_version)
if not match:
continue
major, minor = int(match.group(1)), int(match.group(2))
yield name, major, minor, version_info.git_version
def audit():
today = date.today()
flagged = []
for name, major, minor, git_version in cluster_versions():
eol = EOL_DATES.get((major, minor))
if eol is None:
print(f"{name:30} {git_version:12} no EOL data for {major}.{minor} -- add it to EOL_DATES")
continue
days_left = (eol - today).days
if days_left < 0:
status = f"UNSUPPORTED since {eol} ({-days_left} days ago)"
flagged.append(name)
elif days_left <= WARNING_WINDOW_DAYS:
status = f"EOL in {days_left} days ({eol})"
flagged.append(name)
else:
status = f"supported until {eol}"
print(f"{name:30} {git_version:12} {status}")
return flagged
if __name__ == "__main__":
flagged = audit()
if flagged:
print(f"\n{len(flagged)} cluster(s) need a plan: {', '.join(flagged)}")
sys.exit(1)
sys.exit(0)Three things worth noticing in that code:
config.list_kube_config_contexts()reads every context in your kubeconfig, not just the current one. You get every cluster you have access to, in one pass, without switching contexts manually.config.new_client_from_config(context=name)builds a fresh API client scoped to that one context, so you're not stuck auditing whatever cluster happens to be "current" when the script runs.- The script exits with status
1if anything is flagged. That's not an accident — it's what lets you drop this straight into a CI job and have the pipeline fail loudly instead of a human needing to read logs.
What it looks like running
Here's the shape of the output against a few clusters (illustrative — run it against your own kubeconfig for real numbers):
prod-us-east-1 v1.33.4 supported until 2026-06-28
prod-eu-west-1 v1.34.1 EOL in 12 days (2026-10-27)
staging v1.31.9 UNSUPPORTED since 2025-10-28 (357 days ago)
3 cluster(s) need a plan: prod-us-east-1, prod-eu-west-1, stagingThat staging line is the one that should worry you more than the one counting down. A cluster that's already past EOL and nobody noticed is a cluster nobody's been watching for anything else either.
Wiring it into CI instead of your memory
Save the script as audit_k8s_eol.py in a repo you already have CI on, and add a scheduled job that runs it weekly:
name: kubernetes-eol-audit
on:
schedule:
- cron: "0 9 * * 1" # every Monday at 09:00 UTC
workflow_dispatch: {}
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install kubernetes
- run: python audit_k8s_eol.pyPoint KUBECONFIG at a config that has read access to the clusters you want tracked (a CI secret, not your laptop's kubeconfig), and the job fails the moment any cluster crosses into the warning window — not the day someone remembers to check a calendar.
Push this into your own repo and adjust EOL_DATES as new minor versions ship — it's a five-minute edit each time, which is a lot cheaper than finding out your cluster's been unsupported for a year.

Experienced DevOps Engineer proficient in Python, Docker, Kubernetes, CI/CD, and cloud technologies. Specialized in automating processes and building scalable infrastructure for seamless development and deployment.


