Ensure Node Auto-Upgrade Is Enabled For GKE Nodes
More Info:
Enable node auto-upgrade so nodes stay current with the control plane version and receive security patches automatically. Outdated nodes may run vulnerable Kubernetes and OS versions.
Risk Level
Low
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all node pools and identify which require review
- Run on: any machine with
gcloudaccess.
gcloud container node-pools list \--cluster CLUSTER_NAME \--location LOCATION \--project PROJECT_ID- Decide which node pools should have auto-upgrade based on workload sensitivity, maintenance windows, and existing patching processes.
- Run on: any machine with
-
Gather auto-upgrade configuration for each node pool
- For each node pool name from step 1, run:
gcloud container node-pools describe NODE_POOL_NAME \--cluster CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--format json | jq '.management'- Capture
.management.autoUpgradeand.management.autoRepairfor documentation.
-
Assess whether auto-upgrade should be enabled
- For each node pool, review:
- Change-management and maintenance window requirements.
- Need for predictable vs. rapid security updates.
- Workload disruption tolerance and PodDisruptionBudget coverage.
- Decide per node pool: enable auto-upgrade, or keep it disabled with a documented manual upgrade process and schedule.
- For each node pool, review:
-
Enable auto-upgrade where appropriate
- For node pools where you’ve decided to enable it, run:
gcloud container node-pools update NODE_POOL_NAME \--cluster CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--enable-autoupgrade- Note: this changes future upgrade behavior; it does not immediately upgrade nodes but may schedule automatic upgrades according to Google’s policy.
-
Document exceptions where auto-upgrade remains disabled
- For any node pool where you choose not to enable auto-upgrade:
- Record the business/technical justification.
- Define and document an alternative, regular manual upgrade process (commands, cadence, responsible owner).
- For any node pool where you choose not to enable auto-upgrade:
-
Verify configuration after changes
- Re-run the audit command for all node pools:
gcloud container node-pools describe NODE_POOL_NAME \--cluster CLUSTER_NAME \--location LOCATION \--project PROJECT_ID \--format json | jq '.management'- Confirm
autoUpgradeistruefor node pools where it should be enabled, and that anyfalsevalues are intentional and documented.
Using kubectl
kubectl cannot enable node auto-upgrade because this setting is managed on the GKE control-plane side (Google Cloud Console / gcloud / IaC), not via Kubernetes API objects. To remediate this finding, follow the guidance in the Manual Steps section using the Google Cloud Console, gcloud CLI, or your IaC tooling.
Automation
#!/usr/bin/env bash
# Report GKE node auto-upgrade status for all node pools in all clusters in a project.
# Runs with: any machine that has gcloud, jq, and appropriate IAM permissions.
set -euo pipefail
PROJECT_ID="YOUR_PROJECT_ID_HERE"
if [[ "$PROJECT_ID" == "YOUR_PROJECT_ID_HERE" ]]; then
echo "ERROR: Set PROJECT_ID at the top of this script."
exit 1
fi
echo "Project: $PROJECT_ID"
echo
# List all clusters (regional and zonal)
gcloud container clusters list \
--project "$PROJECT_ID" \
--format='value(name,location)' |
while read -r CLUSTER LOCATION; do
if [[ -z "$CLUSTER" ]]; then
continue
fi
echo "Cluster: $CLUSTER (location: $LOCATION)"
# List all node pools for this cluster
gcloud container node-pools list \
--cluster "$CLUSTER" \
--location "$LOCATION" \
--project "$PROJECT_ID" \
--format='value(name)' |
while read -r POOL; do
if [[ -z "$POOL" ]]; then
continue
fi
# Describe management settings and extract autoUpgrade flag
MGMT_JSON=$(gcloud container node-pools describe "$POOL" \
--cluster "$CLUSTER" \
--location "$LOCATION" \
--project "$PROJECT_ID" \
--format=json | jq -r '.management')
AUTO_UPGRADE=$(printf '%s\n' "$MGMT_JSON" | jq -r '.autoUpgrade')
# Normalize missing field to "false"
if [[ "$AUTO_UPGRADE" != "true" ]]; then
AUTO_UPGRADE="false"
fi
# Mark non-compliant pools clearly
if [[ "$AUTO_UPGRADE" == "true" ]]; then
STATUS="OK"
else
STATUS="NON_COMPLIANT"
fi
echo " Node pool: $POOL"
echo " management: $MGMT_JSON"
echo " autoUpgrade: $AUTO_UPGRADE <-- $STATUS"
done
echo
done
How to interpret the output
- Each node pool shows:
management: {...}– raw management block from the API.autoUpgrade: true <-- OK– compliant with the benchmark.autoUpgrade: false <-- NON_COMPLIANT– needs review and likely remediation.
All node pools in a cluster should report autoUpgrade: true to align with CIS GKE 5.5.3.