> ## 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:

Enable the GKE Metadata Server so workloads use Workload Identity and legacy metadata endpoints are not exposed to pods. Legacy metadata endpoints can leak node service-account credentials.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify clusters and capture current Workload Identity / metadata settings**
           * Run on any machine with `gcloud` access:
             ```bash theme={null}
             gcloud config set project <PROJECT_ID>

             gcloud container clusters list \
               --format="table(name,location,workloadIdentityConfig.workloadPool)"

             # For a specific cluster:
             gcloud container clusters describe <CLUSTER_NAME> \
               --location <LOCATION> \
               --format="json(workloadIdentityConfig,nodePools.config.workloadMetadataConfig)" \
               | jq .
             ```
           * Note whether `workloadIdentityConfig.workloadPool` is set and whether each `nodePools[].config.workloadMetadataConfig.mode` is `GKE_METADATA_SERVER`.

        2. **Decide on cluster-level Workload Identity configuration**
           * If `workloadIdentityConfig.workloadPool` is **unset or empty**, decide whether this cluster should use Workload Identity (recommended for production/security‑sensitive clusters).
           * If yes, enable Workload Identity for the cluster (no node pools are changed yet):
             ```bash theme={null}
             gcloud container clusters update <CLUSTER_NAME> \
               --location <LOCATION> \
               --identity-namespace=<PROJECT_ID>.svc.id.goog
             ```
           * Record the decision and any clusters intentionally left without Workload Identity (e.g., legacy/test).

        3. **Review each node pool’s metadata mode and plan changes**
           * For each cluster where Workload Identity is (or will be) enabled, list node pools and their metadata mode:
             ```bash theme={null}
             gcloud container node-pools list \
               --cluster <CLUSTER_NAME> \
               --location <LOCATION> \
               --format="table(name,config.workloadMetadataConfig.mode)"
             ```
           * Identify node pools where `mode` is **not** `GKE_METADATA_SERVER` (e.g. `GCE_METADATA`).
           * For each such pool, confirm with workload owners whether any workloads still rely on node service account metadata access; plan remediation (migrating to Workload Identity) before flipping the setting.

        4. **Enable GKE Metadata Server on selected node pools**
           * When you are ready to cut over a node pool, run:
             ```bash theme={null}
             gcloud container node-pools update <NODE_POOL_NAME> \
               --cluster=<CLUSTER_NAME> \
               --location=<LOCATION> \
               --workload-metadata-from-node=GKE_METADATA_SERVER
             ```
           * Repeat for each node pool you decided to protect with the metadata server.
           * Be aware this can trigger node recreation/rolling updates depending on configuration and may affect workloads that used legacy metadata endpoints.

        5. **Adjust workloads to use Workload Identity (if needed)**
           * For workloads that previously used node service account credentials, identify required Google Cloud IAM permissions and bind them to Kubernetes service accounts using Workload Identity.
           * Evidence collection:
             ```bash theme={null}
             # Find service accounts in a namespace
             kubectl get sa -n <NAMESPACE>

             # Show annotations on a service account (to confirm Workload Identity binding)
             kubectl get sa <KSA_NAME> -n <NAMESPACE> -o yaml | grep -A2 'iam.gke.io/gcp-service-account'
             ```
           * Update manifests/IaC so pods mount and use the correct Kubernetes service accounts with the proper `iam.gke.io/gcp-service-account` annotation (per your internal standards and Google’s documentation).

        6. **Verify remediation and document exceptions**
           * Re-run the audit for each cluster:
             ```bash theme={null}
             gcloud container clusters describe <CLUSTER_NAME> \
               --location <LOCATION> \
               --format json | jq '.nodePools[].config.workloadMetadataConfig'
             ```
           * Confirm that for all intended node pools, `mode` is `GKE_METADATA_SERVER`.
           * Document any clusters/node pools where GKE Metadata Server is intentionally not enabled, including owners, justification, and a review date.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot enable the GKE Metadata Server or configure Workload Identity, because this setting is managed at the GKE control-plane/node-pool level via Google Cloud (gcloud CLI, Console, or IaC), not via Kubernetes API objects. Use the cloud provider configuration steps described in the Manual Steps section to remediate this finding.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Check GKE Metadata Server / Workload Identity status for all clusters in a project
        # Requirements:
        #   - gcloud, jq installed
        #   - Authenticated to GCP with permissions to list/describe clusters

        set -euo pipefail

        PROJECT_ID="$(gcloud config get-value project 2>/dev/null || true)"
        if [[ -z "${PROJECT_ID}" ]]; then
          echo "ERROR: No active GCP project is set in gcloud."
          echo "Run: gcloud config set project YOUR_PROJECT_ID"
          exit 1
        fi

        echo "Using project: ${PROJECT_ID}"
        echo

        # List all clusters (regional and zonal) in the project
        clusters_json="$(gcloud container clusters list --project "${PROJECT_ID}" --format=json)"

        if [[ "${clusters_json}" == "[]" ]]; then
          echo "No GKE clusters found in project ${PROJECT_ID}."
          exit 0
        fi

        echo "Cluster Workload Identity / GKE Metadata Server status:"
        echo "---------------------------------------------------------------------"

        # Iterate over clusters
        echo "${clusters_json}" | jq -r '.[] | [.name, .location] | @tsv' | while IFS=$'\t' read -r CLUSTER_NAME LOCATION; do
          echo
          echo "Cluster: ${CLUSTER_NAME}"
          echo "Location: ${LOCATION}"

          # Describe cluster (control-plane level Workload Identity setting)
          desc="$(gcloud container clusters describe "${CLUSTER_NAME}" \
                    --location "${LOCATION}" \
                    --project "${PROJECT_ID}" \
                    --format=json)"

          # Cluster-level Workload Identity identityNamespace
          identity_ns="$(echo "${desc}" | jq -r '.workloadIdentityConfig.identityNamespace // "NONE"')"

          if [[ "${identity_ns}" == "NONE" ]]; then
            echo "  Workload Identity: DISABLED (identityNamespace is not set)"
          else
            echo "  Workload Identity: ENABLED"
            echo "    identityNamespace: ${identity_ns}"
          fi

          echo "  Node pools:"
          echo "    NAME | WORKLOAD METADATA MODE | STATUS"

          # For each node pool, show workloadMetadataConfig.mode
          echo "${desc}" | jq -r '
            .nodePools[] |
            [
              .name,
              (.config.workloadMetadataConfig.mode // "UNSET"),
              .status
            ] | @tsv' | while IFS=$'\t' read -r NP_NAME MODE STATUS; do
              echo "    ${NP_NAME} | ${MODE} | ${STATUS}"
            done

          cat <<'EOF'

          Interpretation (what indicates a problem):
            - If "Workload Identity: DISABLED", the cluster is not using Workload Identity.
            - For node pools:
                * MODE == "GCE_METADATA" or "UNSET"  => LEGACY METADATA ENDPOINT IN USE (PROBLEM).
                * MODE == "GKE_METADATA_SERVER"     => GKE Metadata Server enabled (DESIRED).
            - To fully align with CIS 5.4.1:
                * identityNamespace SHOULD be set (Workload Identity enabled).
                * ALL node pools SHOULD have mode "GKE_METADATA_SERVER".
        EOF

        done
        ```

        **How to run (any machine with gcloud access):**

        1. Ensure `gcloud` and `jq` are installed and authenticated.
        2. Set your project:\
           `gcloud config set project YOUR_PROJECT_ID`
        3. Save the script as `check_gke_metadata_server.sh`, make it executable:\
           `chmod +x check_gke_metadata_server.sh`
        4. Run:\
           `./check_gke_metadata_server.sh`

        **Output indicating a problem:**

        * Line: `Workload Identity: DISABLED (identityNamespace is not set)`\
          → Cluster not configured for Workload Identity.
        * Any node pool line where `WORKLOAD METADATA MODE` is `GCE_METADATA` or `UNSET`\
          → That node pool is not using the GKE Metadata Server and still exposes the legacy metadata endpoint.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
