Kubernetes 1.34 reaches upstream end of life on 27 October 2026. After that date, the Kubernetes project stops cutting 1.34 patch releases, so a vulnerability found in November gets fixed in 1.35 and later, not in the version you run. Whether that matters to you this month depends on who builds your Kubernetes. EKS, AKS and GKE all keep supporting 1.34 into 2027. A cluster built with kubeadm or from upstream binaries doesn't get that extra time.
This guide is for platform teams running 1.34 anywhere. It covers what upstream end of life means, the dates each major managed provider publishes, the September security fixes that a 1.34 cluster should already have, what can break on the way to 1.35, and a script that checks a cluster's control plane and nodes.
The short answer
Upstream Kubernetes 1.34 reaches end of life on 27 October 2026, after two months in maintenance mode. The latest 1.34 patch is 1.34.12, tagged on 23 September 2026, and it fixes three CVEs published in August and September. On managed services, 1.34 stays supported for longer: EKS standard support ends on 2 December 2026, AKS lists end of life in November 2026, and GKE ends standard support on 25 January 2027, with paid or opt-in extended support on all three. If you run upstream Kubernetes yourself, plan the move to 1.35 now. Before upgrading, check for cgroup v1 nodes and the removed kubelet flag --pod-infra-container-image, both of which stop a 1.35 kubelet from starting.
What upstream end of life means
Each Kubernetes minor version gets about 12 months of regular patches, then two months of maintenance mode, then end of life. The project's patch release policy says maintenance releases in those two months only cover CVE fixes, dependency issues such as base image updates, and critical core bugs. At the end of the two months the branch "will be considered EOL", and cherry picks to it are closed soon after.
For 1.34, the dates in the project's release schedule are:
| Milestone | Date |
|---|---|
| Maintenance mode began | 27 August 2026 |
| Latest patch, 1.34.12 | 23 September 2026 (scheduled for 15 September) |
| Next listed patch, 1.34.13 | scheduled for 13 October, not tagged as of 16 October |
| End of life | 27 October 2026 |
So 1.34 may get one more patch before the end. After it, nothing.
The other supported branches end later: 1.35 on 28 February 2027, 1.36 on 28 June 2027, and 1.37 on 28 October 2027.
What managed providers do instead
Managed services build and patch their own Kubernetes, so their dates are what count for a managed cluster. Each publishes a calendar. On 16 October 2026 they said:
| Provider | End of standard support for 1.34 | Longer option |
|---|---|---|
| Amazon EKS | 2 December 2026 | Extended support until 2 December 2027, at an additional cost per cluster hour |
| Azure AKS | November 2026 (AKS reads this as the last day of the month) | Long-term support, opt-in, until November 2027 |
| Google GKE | 25 January 2027 | Extended support until 25 November 2027 |
Three details matter for planning.
EKS turns extended support on by default. A 1.34 cluster that isn't upgraded by 2 December moves into extended support and starts billing for it. If the cluster is still on 1.34 when extended support ends, EKS upgrades it automatically.
AKS separates end of life from forced upgrades. Its table lists "platform support" for 1.34 until 1.38 is generally available, and a platform-initiated upgrade for clusters still on 1.34, planned for June 2027. Microsoft calls that month a planning estimate. Long-term support isn't automatic. You have to enable it.
GKE dates depend on the release channel. The 25 January 2027 date is the end of standard support. Clusters on the Extended channel keep 1.34 until 25 November 2027.
The table comes from each provider's documentation, and all three revise their calendars. Check the live page before you commit to a date.
The September fixes a 1.34 cluster should have
Three Kubernetes CVEs published in August and September are fixed in 1.34.12, and in 1.35.9, 1.36.5 and 1.37.1 where those lines are affected. All three come from the official Kubernetes CVE feed.
| CVE | Component | What it allows | CVSS 3.1 |
|---|---|---|---|
| CVE-2026-2270 | kube-controller-manager | A user who can write StatefulSets and ControllerRevisions in one namespace can make the StatefulSet controller create a pod in another namespace | 5.9 |
| CVE-2026-76654 | kubelet on Windows nodes | A subPath symlink pointing at a network share makes the kubelet authenticate to it, exposing the node account's NetNTLMv2 hash | 5.8 |
| CVE-2026-19444 | kubectl on Windows | A malicious tar in a container can write files anywhere the user can when they run kubectl cp from it | 6.5 |
None of them is critical. CVE-2026-2270 is the one most clusters should care about, because it turns namespace-scoped write access into a pod in a namespace the user doesn't control. The advisory notes that the garbage collector deletes such a pod immediately unless the attacker can give it a valid owner reference, which requires the UID of an existing StatefulSet in the victim's namespace.
Credit goes to ImanOracle for CVE-2026-2270, to the Kubernetes Third-Party Security Audit subproject, OSTIF and Shielder for CVE-2026-76654, and to Moriel Harush for CVE-2026-19444.
On a managed service, the provider ships these fixes in its own builds, so check its security bulletins rather than the upstream patch number.
What can break on the way to 1.35
Control planes move one minor version at a time, so 1.35 is the next step from 1.34 in every case. The 1.35 changelog has an "Urgent Upgrade Notes" section, and its items are the ones to check first:
- cgroup v1 nodes. In 1.35 the kubelet's
failCgroupV1setting defaults to true, so a 1.35 kubelet won't start on a cgroup v1 host. kubeadm's preflight check now fails instead of warning. You can override both, but the changelog marks cgroup v1 as deprecated. Moving those nodes to a cgroup v2 OS image is the durable fix. - The
--pod-infra-container-imageflag is gone. A kubelet that still passes it fails to start. On kubeadm clusters, checkextraArgsin the kubelet configuration, because kubeadm won't remove it for you. - StorageVersionMigration v1alpha1 is removed. Delete any v1alpha1 resources before upgrading. 1.35 adds v1beta1.
- kube-proxy's
ipvsmode is deprecated. It still works in 1.35, but the project recommendsnftables. Plan that migration rather than doing it during the upgrade.
Nodes don't have to move in the same step as the control plane. The version skew policy allows a kubelet up to three minor versions older than the API server, but never newer. A 1.31 node pool under a 1.34 control plane is already at that limit, and upgrading the control plane to 1.35 puts it out of policy.
Check your cluster
This script reads the output of two read-only kubectl commands and reports, for the control plane and each node, the upstream end-of-life status, whether the version predates the September fixes, and whether node versions are within skew. --refresh downloads the current dates from the Kubernetes website instead of using the table in the script. It uses only the Python standard library.
#!/usr/bin/env python3
"""Check a cluster's Kubernetes versions against upstream end-of-life dates.
Usage:
kubectl version -o json > version.json
kubectl get nodes -o json > nodes.json
python3 k8s_eol_check.py version.json nodes.json [--today YYYY-MM-DD] [--refresh]
Reads the two files only. --refresh downloads the current schedule from
kubernetes/website instead of using the table below (checked 16 Oct 2026).
"""
import argparse, datetime as dt, json, re, sys, urllib.request
# Upstream end of life per minor, from kubernetes/website data/releases.
EOL = {"1.31": "2025-11-11", "1.32": "2026-02-28", "1.33": "2026-06-28",
"1.34": "2026-10-27", "1.35": "2027-02-28", "1.36": "2027-06-28",
"1.37": "2027-10-28"}
# First patch that fixes the September 2026 kubelet and controller CVEs
# (CVE-2026-76654, CVE-2026-2270), per Kubernetes' official CVE feed.
SEPT_FIX = {"1.34": 12, "1.35": 9, "1.36": 5, "1.37": 1}
WARN_DAYS = 60
def refresh():
base = "https://raw.githubusercontent.com/kubernetes/website/main/data/releases/"
table = {}
for name in ("schedule.yaml", "eol.yaml"):
text = urllib.request.urlopen(base + name, timeout=20).read().decode()
# Each branch block holds an endOfLifeDate and a quoted release "1.N".
for block in re.split(r"\n- ", text):
eol = re.search(r'endOfLifeDate: "(\d{4}-\d{2}-\d{2})"', block)
rel = re.search(r'\n release: "(1\.\d+)"', "\n" + block) or \
re.search(r'^release: "(1\.\d+)"', block, re.M)
if eol and rel:
table[rel.group(1)] = eol.group(1)
return table
def parse(v):
m = re.match(r"v?(\d+)\.(\d+)\.(\d+)", v or "")
return (f"{m.group(1)}.{m.group(2)}", int(m.group(3))) if m else (None, None)
def status(minor, patch, today, kind, windows=False):
out = []
eol = EOL.get(minor)
if eol is None:
out.append("FAIL unknown or already past every listed EOL")
else:
days = (dt.date.fromisoformat(eol) - today).days
if days < 0:
out.append(f"FAIL upstream EOL was {eol}, no more upstream patches")
elif days <= WARN_DAYS:
out.append(f"WARN upstream EOL {eol}, in {days} days")
else:
out.append(f"ok upstream EOL {eol}")
fix = SEPT_FIX.get(minor)
# CVE-2026-76654 affects kubelet on Windows nodes only.
if fix is not None and patch < fix and (kind != "kubelet" or windows):
cve = "CVE-2026-76654" if kind == "kubelet" else "CVE-2026-2270"
out.append(f"FAIL below {minor}.{fix}, missing the fix for {cve}")
return out
def main():
ap = argparse.ArgumentParser()
ap.add_argument("version"); ap.add_argument("nodes")
ap.add_argument("--today"); ap.add_argument("--refresh", action="store_true")
a = ap.parse_args()
if a.refresh:
EOL.update(refresh())
today = dt.date.fromisoformat(a.today) if a.today else dt.date.today()
bad = False
server = json.load(open(a.version))["serverVersion"]["gitVersion"]
smin, spatch = parse(server)
print(f"control plane {server}")
for line in status(smin, spatch, today, "controller"):
print(" " + line); bad |= line.startswith("FAIL")
print(" note: managed control planes (EKS, AKS, GKE) follow the provider's dates, not upstream's")
sm = int(smin.split(".")[1])
for n in json.load(open(a.nodes))["items"]:
info = n["status"]["nodeInfo"]
kv = info["kubeletVersion"]; kmin, kpatch = parse(kv)
win = info.get("operatingSystem") == "windows"
print(f"node {n['metadata']['name']}: kubelet {kv}, {info.get('containerRuntimeVersion')}, {info.get('osImage')}")
lines = status(kmin, kpatch, today, "kubelet", win)
km = int(kmin.split(".")[1])
if km > sm:
lines.append("FAIL kubelet newer than the API server")
elif sm - km > 3:
lines.append(f"FAIL kubelet is {sm - km} minors behind the API server (max 3)")
elif sm - km == 3:
lines.append("WARN kubelet is 3 minors behind; the next control plane upgrade breaks skew")
for line in lines:
print(" " + line); bad |= line.startswith("FAIL")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())
We ran it against two synthetic clusters built from kubectl's output format, with the date set to 16 October. The first has a 1.34.10 control plane, a current node pool, an old 1.31 pool and a Windows node:
$ python3 k8s_eol_check.py version.json nodes.json --today 2026-10-16
control plane v1.34.10
WARN upstream EOL 2026-10-27, in 11 days
FAIL below 1.34.12, missing the fix for CVE-2026-2270
note: managed control planes (EKS, AKS, GKE) follow the provider's dates, not upstream's
node pool-a-1: kubelet v1.34.10, containerd://2.1.4, Ubuntu 24.04.3 LTS
WARN upstream EOL 2026-10-27, in 11 days
node pool-old-1: kubelet v1.31.9, containerd://1.7.27, Ubuntu 22.04.5 LTS
FAIL upstream EOL was 2025-11-11, no more upstream patches
WARN kubelet is 3 minors behind; the next control plane upgrade breaks skew
node win-1: kubelet v1.34.10, containerd://2.1.4, Windows Server 2022 Datacenter
WARN upstream EOL 2026-10-27, in 11 days
FAIL below 1.34.12, missing the fix for CVE-2026-76654
$ echo $?
1
The second is the same cluster after an upgrade to 1.35.9:
$ python3 k8s_eol_check.py version2.json nodes2.json --today 2026-10-16
control plane v1.35.9
ok upstream EOL 2027-02-28
note: managed control planes (EKS, AKS, GKE) follow the provider's dates, not upstream's
node pool-a-1: kubelet v1.35.9, containerd://2.1.4, Ubuntu 24.04.3 LTS
ok upstream EOL 2027-02-28
node win-1: kubelet v1.35.9, containerd://2.1.4, Windows Server 2022 Datacenter
ok upstream EOL 2027-02-28
$ echo $?
0
Two limits. kubectl version reports the API server's version, so the CVE-2026-2270 check assumes the controller manager matches it, which holds on managed control planes and on most kubeadm clusters. And on EKS, AKS or GKE, the upstream end-of-life line is a reminder, not the deadline. Use the provider's table above.
What to do
- Find every 1.34 cluster, including the ones in test accounts. Run the script on each one, and match managed clusters against the provider's calendar.
- On upstream or kubeadm clusters, get to 1.34.12 now for the September fixes, then plan 1.35 before 27 October or soon after.
- On managed clusters, write the provider's date down and decide whether you'll upgrade or pay for extended support. On EKS, deciding nothing means extended support from 2 December.
- Clear the 1.35 blockers first: cgroup v1 nodes, the removed kubelet flag and any StorageVersionMigration v1alpha1 objects.
- Fix node skew before the control plane moves, so no node pool falls more than three minors behind.
Our guide to managing end-of-life software dependencies covers the same problem one level down, in the libraries your workloads run.
The fair view
End of life upstream isn't an emergency for most clusters. Managed providers keep 1.34 supported for months, the September CVEs are medium severity, and a cluster patched to 1.34.12 has every fix the official CVE feed lists for core Kubernetes components this year. Upgrading in a hurry to beat a date has its own risks, and the 1.35 changes to cgroups and kubelet flags are exactly the kind that break a rushed upgrade.
The case for moving anyway is about the next vulnerability, not the last one. After 27 October, a self-managed 1.34 cluster has no upstream fix path for anything new, and a managed one is on a calendar that ends with either an automatic upgrade or a bill. The four-month release cycle means 1.35 reaches the same point in February. Teams that make minor upgrades routine spend less on each one.