Skip to main content

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​

Manual Steps
  1. List all node pools and identify which require review

    • Run on: any machine with gcloud access.
    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.
  2. 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.autoUpgrade and .management.autoRepair for documentation.
  3. 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.
  4. 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.
  5. 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).
  6. 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 autoUpgrade is true for node pools where it should be enabled, and that any false values 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.