Skip to main content

Ensure Shielded GKE Nodes Are Enabled

More Info:

Enable Shielded GKE Nodes to provide verifiable node identity and integrity via secure boot and vTPM protections. This defends against boot-level and kernel-level tampering.

Risk Level

High

Address

Security

Compliance Standards

  • CIS GKE

Triage and Remediation

Remediation

Manual Steps
  1. On any machine with gcloud configured, list clusters and identify those to review:

    gcloud container clusters list --project YOUR_PROJECT_ID --format="table(name,location,shieldedNodes)"

    Note clusters where shieldedNodes is empty or False.

  2. For each cluster to review, gather detailed shielded nodes status and record the output for change review:

    gcloud container clusters describe CLUSTER_NAME \
    --location LOCATION \
    --project YOUR_PROJECT_ID \
    --format="json(shieldedNodes)"

    Confirm whether "enabled": true is present.

  3. With your security/operations stakeholders, decide whether Shielded GKE Nodes should be enforced for this cluster, considering: required node images, any dependency on custom bootloaders or kernel modules, and compatibility with secure boot/vTPM.

  4. If you decide to enable Shielded GKE Nodes, schedule a maintenance window and update the cluster:

    gcloud container clusters update CLUSTER_NAME \
    --location LOCATION \
    --project YOUR_PROJECT_ID \
    --enable-shielded-nodes

    Be aware that this changes how new and re-created nodes are provisioned and may trigger node recreations depending on your cluster configuration and subsequent operations (e.g., upgrades or node pool recreations).

  5. After the update completes, verify the setting is now enabled:

    gcloud container clusters describe CLUSTER_NAME \
    --location LOCATION \
    --project YOUR_PROJECT_ID \
    --format="json(shieldedNodes)"

    Confirm the result shows:

    {
    "enabled": true
    }
  6. Optionally, for each node pool, confirm that new nodes are being created as shielded nodes by inspecting instance details in the Google Cloud Console (Compute Engine → VM instances) and validating Shielded VM settings, or via CLI:

    gcloud compute instances describe INSTANCE_NAME \
    --zone ZONE \
    --project YOUR_PROJECT_ID \
    --format="json(shieldedInstanceConfig)"
Using kubectl

kubectl cannot enable Shielded GKE Nodes because this setting is part of the managed GKE control-plane/cluster configuration, changed only via the Google Cloud console, gcloud CLI, or IaC. Refer to the Manual Steps section for the exact gcloud command and configuration changes required.

Automation
#!/usr/bin/env bash
#
# Report Shielded GKE Nodes status for all clusters in one or more projects.
# Requirements:
# - gcloud
# - jq
#
# Usage examples:
# ./check_shielded_gke_nodes.sh # use current gcloud project
# GCP_PROJECTS="proj-a proj-b" ./check_shielded_gke_nodes.sh

set -euo pipefail

# Projects to check: space‑separated list in GCP_PROJECTS, or current gcloud project if unset
if [[ -n "${GCP_PROJECTS:-}" ]]; then
PROJECTS=${GCP_PROJECTS}
else
PROJECTS=$(gcloud config get-value project 2>/dev/null || true)
fi

if [[ -z "${PROJECTS}" ]]; then
echo "ERROR: No GCP project configured. Set GCP_PROJECTS or 'gcloud config set project ...'." >&2
exit 1
fi

echo "Checking Shielded GKE Nodes status..."
echo

for PROJECT in ${PROJECTS}; do
echo "=== Project: ${PROJECT} ==="
# List all clusters in all locations for the project
CLUSTERS_JSON=$(gcloud container clusters list \
--project "${PROJECT}" \
--format json 2>/dev/null || true)

if [[ "${CLUSTERS_JSON}" == "[]" || -z "${CLUSTERS_JSON}" ]]; then
echo " No clusters found."
echo
continue
fi

echo "${CLUSTERS_JSON}" | jq -r '.[] | [.name, .location] | @tsv' | while IFS=$'\t' read -r CLUSTER LOCATION; do
# Describe each cluster to get shieldedNodes status
DESC=$(gcloud container clusters describe "${CLUSTER}" \
--location "${LOCATION}" \
--project "${PROJECT}" \
--format json 2>/dev/null || true)

if [[ -z "${DESC}" ]]; then
echo " [ERROR] Failed to describe cluster ${CLUSTER} (${LOCATION})"
continue
fi

SHIELDED_ENABLED=$(echo "${DESC}" | jq -r '.shieldedNodes.enabled // "false"')
RELEASE_CHANNEL=$(echo "${DESC}" | jq -r '.releaseChannel.channel // "UNSPECIFIED"')

if [[ "${SHIELDED_ENABLED}" == "true" ]]; then
STATUS="OK"
else
STATUS="NON-COMPLIANT"
fi

printf " Cluster: %-30s Location: %-12s ShieldedNodes: %-5s ReleaseChannel: %s\n" \
"${CLUSTER}" "${LOCATION}" "${SHIELDED_ENABLED}" "${RELEASE_CHANNEL}"

if [[ "${STATUS}" == "NON-COMPLIANT" ]]; then
echo " -> REVIEW: Shielded GKE Nodes are DISABLED for this cluster."
fi
done
echo
done

Explanation of output indicating a problem:

  • For each cluster, look at the ShieldedNodes field in the printed line.

  • ShieldedNodes: true → compliant with the control.

  • ShieldedNodes: falseproblem; line is annotated with:

    -> REVIEW: Shielded GKE Nodes are DISABLED for this cluster.

Those clusters with ShieldedNodes: false are candidates for manual review and possible remediation using:

gcloud container clusters update <cluster_name> --location <location> --enable-shielded-nodes