# GKE Node Auto-Upgrade Not Configured

> Node pools without auto-upgrade drift behind on Kubernetes patch releases and accumulate known CVEs. ZopNight rule RC-120 fires when the cluster-level auto_upgrade flag (aggregated by the discoverer across every node pool) is explicitly false; 1 pool with it off fails the whole cluster. Absent data abstains rather than over-flagging.

Source: https://zop.dev/integrations/gcp/recommendations/gke-node-auto-upgrade-not-configured
Updated: 2026-08-19

---

## Nodes that quietly age out of support

The failure mode here is gradual. A node pool opts out of auto-upgrade (usually during some long-forgotten incident when someone wanted to "control the timing"), and then nothing forces it forward. Twelve months later the nodes run a kubelet several minor versions behind a control plane that GKE has kept current, carrying every kernel, containerd, and Kubernetes CVE patched in between. Version skew eventually bites too: Kubernetes supports kubelets only within a bounded window of the API server, and pools that drift past it start failing upgrades in ways that are much harder to fix than the steady cadence would have been. Manual upgrading in theory prevents this; in practice the calendar reminder dies with the person who set it.

## An all-pools verdict on one flag

Detection is cluster-scoped by construction. The discoverer walks every node pool's `management.autoUpgrade` and stamps a single aggregate: `true` only when **every** pool has it on, `false` if any pool is off, and no value at all when there are no pools to observe. Rule RC-120 reads that aggregate from the metadata sink (tags mirror as fallback) and fires solely on the explicit `false`. A missing value abstains, because an unobserved cluster carries no evidence either way. One opted-out pool is thus enough to flag the cluster, and the finding will not tell you which pool it was. Enumerate to locate it:

```bash
gcloud container node-pools list --cluster my-cluster --location us-central1 \
  --format='table(name,management.autoUpgrade)'
```

## Re-enabling, and the grant it rides on

`gcloud container node-pools update my-pool --cluster my-cluster --location us-central1 --enable-autoupgrade` closes the gap per pool. In ZopNight's permission catalogue, node-pool changes like this are modelled as `container.clusters.update` under `roles/container.clusterAdmin`, the same grant that covers its node-pool scheduling writes.

## Making the timing objection obsolete

Teams disable auto-upgrade to avoid surprise disruption; GKE has since grown the tools that answer the concern without the drift. Pin pools to a release channel, set maintenance windows and exclusions so upgrades land only when you allow, and let surge upgrade settings bound how many nodes churn at once. That combination gives back the control that motivated the opt-out, with patches still arriving.
