> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Ensure The Gke Metadata Server Is Enabled

### More Info:

Running The Gke Metadata Server Prevents Workloads From Accessing Sensitive Instance Metadata And Facilitates Workload Identity

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List and review current cluster Workload Identity configuration**
           * **Machine:** Any machine with `gcloud` configured
           * **Command:**
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --location LOCATION \
               --format="json(workloadIdentityConfig,workloadPool)"
             ```
           * **Review:** Confirm whether `workloadIdentityConfig` / `workloadPool` is set to `PROJECT_ID.svc.id.goog`. If not set, enabling Workload Identity (and thus defaulting new node pools to use the GKE Metadata Server) is likely required.

        2. **Check each node pool’s metadata server configuration**
           * **Machine:** Any machine with `gcloud` configured
           * **Command:**
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --location LOCATION \
               --format json | jq '.nodePools[].config.workloadMetadataConfig'
             ```
           * **Review:** For each node pool, confirm `mode` is `GKE_METADATA_SERVER`. Any node pool with a different mode (e.g. `GCE_METADATA`, `UNSPECIFIED`, or null) does not have the GKE Metadata Server enabled.

        3. **Assess application impact and readiness for Workload Identity**
           * **Machine:** Any machine with `kubectl` and cluster access
           * **Commands (evidence gathering):**
             ```bash theme={null}
             kubectl get serviceaccounts -A
             kubectl get pods -A -o wide
             kubectl get iamserviceaccounts --project=PROJECT_ID 2>/dev/null || true
             ```
           * **Review:**
             * Identify workloads that currently rely on node service account credentials or direct instance metadata access.
             * Determine which workloads will need to be updated to use GCP IAM via Workload Identity (e.g., binding Kubernetes ServiceAccounts to GCP service accounts).

        4. **Decide and plan enabling Workload Identity and GKE Metadata Server**
           * If the cluster is not using Workload Identity, plan a change window to:
             * Enable Workload Identity at cluster level.
             * Migrate affected workloads to use Kubernetes ServiceAccounts mapped to GCP Service Accounts.
           * If Workload Identity is already enabled but some node pools are not using `GKE_METADATA_SERVER`, plan to update those node pools, considering any workloads tightly coupled to legacy metadata access patterns.

        5. **Enable Workload Identity at the cluster level (if not already enabled)**
           * **Machine:** Any machine with `gcloud` configured
           * **Command:**
             ```bash theme={null}
             gcloud container clusters update CLUSTER_NAME \
               --location LOCATION \
               --identity-namespace=PROJECT_ID.svc.id.goog
             ```
           * **Impact:** Control-plane configuration change; does not automatically alter existing node pools, but new node pools will default to `--workload-metadata-from-node=GKE_METADATA_SERVER`.

        6. **Enable GKE Metadata Server on existing node pools and verify**
           * **Machine:** Any machine with `gcloud` configured
           * **Command (per node pool):**
             ```bash theme={null}
             gcloud container node-pools update NODE_POOL_NAME \
               --cluster=CLUSTER_NAME \
               --location=LOCATION \
               --workload-metadata-from-node=GKE_METADATA_SERVER
             ```
           * **Verification:**
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --location LOCATION \
               --format json | jq '.nodePools[].config.workloadMetadataConfig'
             ```
             Confirm all node pools now report `"mode": "GKE_METADATA_SERVER"`.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot enable the GKE Metadata Server or configure Workload Identity, because these settings are managed at the GKE control-plane and node pool level via gcloud/console/IaC, not through Kubernetes API objects. To remediate this finding, follow the guidance in the Manual Steps section using the Google Cloud Console or gcloud commands.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report GKE Metadata Server / Workload Identity status for all clusters in a project.
        # Runs from: any machine with gcloud, jq, and appropriate IAM permissions.

        set -euo pipefail

        PROJECT_ID="$(gcloud config get-value project 2>/dev/null)"

        if [[ -z "${PROJECT_ID}" || "${PROJECT_ID}" == "(unset)" ]]; then
          echo "ERROR: gcloud project is not set. Run: gcloud config set project YOUR_PROJECT_ID" >&2
          exit 1
        fi

        echo "Project: ${PROJECT_ID}"
        echo

        # List all clusters (both zonal and regional)
        mapfile -t CLUSTERS < <(gcloud container clusters list \
          --project "${PROJECT_ID}" \
          --format='value(name,location)' 2>/dev/null)

        if [[ "${#CLUSTERS[@]}" -eq 0 ]]; then
          echo "No GKE clusters found in project ${PROJECT_ID}."
          exit 0
        fi

        printf "%-30s %-20s %-25s %-35s %-15s\n" \
          "CLUSTER" "LOCATION" "NODE_POOL" "WORKLOAD_METADATA_MODE" "ISSUE?"
        printf "%0.s-" {1..130}; echo

        for ENTRY in "${CLUSTERS[@]}"; do
          CLUSTER_NAME="$(awk '{print $1}' <<< "${ENTRY}")"
          LOCATION="$(awk '{print $2}' <<< "${ENTRY}")"

          # Describe cluster nodePools and workloadMetadataConfig
          DESC_JSON="$(gcloud container clusters describe "${CLUSTER_NAME}" \
            --location "${LOCATION}" \
            --project "${PROJECT_ID}" \
            --format=json 2>/dev/null || true)"

          if [[ -z "${DESC_JSON}" ]]; then
            printf "%-30s %-20s %-25s %-35s %-15s\n" \
              "${CLUSTER_NAME}" "${LOCATION}" "-" "DESCRIBE_FAILED" "REVIEW"
            continue
          fi

          # Get identity namespace for the cluster (Workload Identity enabled if non-empty)
          ID_NS="$(jq -r '.workloadIdentityConfig.identityNamespace // empty' <<< "${DESC_JSON}")"
          if [[ -z "${ID_NS}" ]]; then
            CLUSTER_WI="DISABLED"
          else
            CLUSTER_WI="ENABLED (${ID_NS})"
          fi

          # Iterate node pools
          NP_COUNT="$(jq '.nodePools | length' <<< "${DESC_JSON}")"
          if [[ "${NP_COUNT}" -eq 0 ]]; then
            printf "%-30s %-20s %-25s %-35s %-15s\n" \
              "${CLUSTER_NAME}" "${LOCATION}" "-" "NO_NODE_POOLS" "REVIEW"
            continue
          fi

          for ((i=0; i<NP_COUNT; i++)); do
            NP_NAME="$(jq -r ".nodePools[${i}].name" <<< "${DESC_JSON}")"
            MODE="$(jq -r ".nodePools[${i}].config.workloadMetadataConfig.mode // \"UNSPECIFIED\"" <<< "${DESC_JSON}")"

            # Normalize and flag issues:
            # EXPECTED secure setting: GKE_METADATA or GKE_METADATA_SERVER (legacy name).
            # Problematic / needs review:
            #   - MODE == "GCE_METADATA" (pods can query full instance metadata)
            #   - MODE == "UNSPECIFIED" (older clusters / unclear behavior)
            #   - Cluster workload identity disabled but node pool uses GKE_METADATA(_SERVER)
            ISSUE="OK"

            case "${MODE}" in
              "GKE_METADATA"|"GKE_METADATA_SERVER")
                # Good from metadata-server perspective, but cluster WI disabled is a config mismatch
                if [[ "${CLUSTER_WI}" == "DISABLED" ]]; then
                  ISSUE="REVIEW_WI"
                fi
                ;;
              "GCE_METADATA")
                ISSUE="PROBLEM"
                ;;
              "UNSPECIFIED")
                ISSUE="REVIEW"
                ;;
              *)
                ISSUE="REVIEW"
                ;;
            esac

            printf "%-30s %-20s %-25s %-35s %-15s\n" \
              "${CLUSTER_NAME}" "${LOCATION}" "${NP_NAME}" "${MODE} / WI:${CLUSTER_WI}" "${ISSUE}"
          done
        done

        cat <<'EOF'

        Interpretation:

        - WORKLOAD_METADATA_MODE = GCE_METADATA  (ISSUE=PROBLEM)
            -> Workloads access the full Compute Engine metadata server from the node.
               This is *not* using the GKE Metadata Server and should be remediated.

        - WORKLOAD_METADATA_MODE = UNSPECIFIED or any unexpected value (ISSUE=REVIEW)
            -> Older / unclear configuration. Manually inspect the cluster and node pool
               settings in the GCP Console or with:
                  gcloud container clusters describe CLUSTER --location LOCATION --format=json

        - WORKLOAD_METADATA_MODE = GKE_METADATA or GKE_METADATA_SERVER AND WI enabled (ISSUE=OK)
            -> Desired state: GKE Metadata Server is used and Workload Identity is configured.

        - WORKLOAD_METADATA_MODE = GKE_METADATA or GKE_METADATA_SERVER AND WI disabled (ISSUE=REVIEW_WI)
            -> Node pools use GKE Metadata Server, but the cluster identity namespace is not set.
               Review whether Workload Identity should be enabled for this cluster.

        Use this report to decide where to apply:
          - Cluster-level Workload Identity: 
              gcloud container clusters update CLUSTER_NAME \
                --location=LOCATION \
                --identity-namespace=PROJECT_ID.svc.id.goog

          - Node pool-level metadata mode:
              gcloud container node-pools update NODE_POOL_NAME \
                --cluster=CLUSTER_NAME \
                --location=LOCATION \
                --workload-metadata-from-node=GKE_METADATA_SERVER

        These commands are *not* executed by this script; they require manual review
        and explicit action per cluster and node pool.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://cloud.google.com/kubernetes-engine/docs/how-to/protecting-cluster-metadata#concealment](https://cloud.google.com/kubernetes-engine/docs/how-to/protecting-cluster-metadata#concealment)
