GKE clusters with node auto-upgrade off in at least one pool
What does ZopNight detect here?
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.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-120 |
| Category | compliance |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | gke_autoupgrade.go |
Where it applies
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:
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.