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

# Consider GKE Sandbox For Running Untrusted Workloads

### More Info:

Use GKE Sandbox (gVisor) to isolate untrusted workloads from the host kernel, reducing the impact of container escapes. This adds a strong isolation boundary for risky workloads.

### 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. **Identify untrusted / risky workloads and namespaces**
           * On any machine with `kubectl` access, list namespaces and deployments to find workloads that run untrusted code, multi-tenant apps, user-supplied images, or high-risk services:
             ```bash theme={null}
             kubectl get ns
             kubectl get deploy --all-namespaces -o wide
             ```
           * Document which namespaces/workloads should be isolated with GKE Sandbox.

        2. **Check current Sandbox (gVisor) configuration on all node pools**
           * On any machine with `gcloud` access, list node pools for the cluster:
             ```bash theme={null}
             gcloud container node-pools list \
               --cluster CLUSTER_NAME \
               --location LOCATION \
               --project PROJECT_ID
             ```
           * For each node pool, inspect sandbox configuration:
             ```bash theme={null}
             gcloud container node-pools describe NODE_POOL_NAME \
               --cluster CLUSTER_NAME \
               --location LOCATION \
               --project PROJECT_ID \
               --format json | jq '.config.sandboxConfig'
             ```
           * `type: "GVISOR"` indicates the node pool is configured for GKE Sandbox.

        3. **Decide whether to introduce or expand GKE Sandbox**
           * If no node pool has `"type": "GVISOR"` and you have identified untrusted workloads, decide to create at least one dedicated GKE Sandbox node pool.
           * If some node pools use GKE Sandbox, decide whether to migrate additional untrusted workloads to those or to new sandboxed pools.
           * Consider operational impacts: performance overhead, supported OS/image (`cos_containerd`), and compatibility of privileged / hostPath workloads (these generally cannot use gVisor).

        4. **Create a GKE Sandbox node pool (if needed)**
           * On any machine with `gcloud` access, create a new sandboxed node pool following the benchmark remediation:
             ```bash theme={null}
             gcloud container node-pools create NODE_POOL_NAME \
               --location LOCATION \
               --cluster CLUSTER_NAME \
               --project PROJECT_ID \
               --image-type=cos_containerd \
               --sandbox="type=gvisor"
             ```
           * Optionally, add labels/taints to target only untrusted workloads, for example:
             ```bash theme={null}
             gcloud container node-pools create NODE_POOL_NAME \
               --location LOCATION \
               --cluster CLUSTER_NAME \
               --project PROJECT_ID \
               --image-type=cos_containerd \
               --sandbox="type=gvisor" \
               --node-labels=workload=isolation-untrusted \
               --node-taints=workload=isolation-untrusted:NoSchedule
             ```

        5. **Schedule untrusted workloads onto GKE Sandbox nodes**
           * On any machine with `kubectl` access, update the Pod/Deployment specs of untrusted workloads to use node selectors and/or tolerations matching the sandbox node pool, for example:
             ```yaml theme={null}
             spec:
               nodeSelector:
                 workload: isolation-untrusted
               tolerations:
               - key: "workload"
                 operator: "Equal"
                 value: "isolation-untrusted"
                 effect: "NoSchedule"
             ```
           * Apply updated manifests:
             ```bash theme={null}
             kubectl apply -f UPDATED_MANIFEST.yaml
             ```
           * Ensure no privileged or incompatible workloads are targeted to gVisor nodes.

        6. **Verify GKE Sandbox is enabled and in use**
           * Re-run the audit for the sandbox node pool(s):
             ```bash theme={null}
             gcloud container node-pools describe NODE_POOL_NAME \
               --cluster CLUSTER_NAME \
               --location LOCATION \
               --project PROJECT_ID \
               --format json | jq '.config.sandboxConfig'
             ```
           * On any machine with `kubectl` access, confirm untrusted Pods are running on nodes from the sandbox pool:
             ```bash theme={null}
             kubectl get pods -A -o wide | grep NODE_POOL_NAME
             ```
           * Optionally, list nodes and confirm labels/taints are correctly set:
             ```bash theme={null}
             kubectl get nodes --show-labels
             kubectl describe node NODE_NAME | grep -i taints -A2
             ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot enable GKE Sandbox, because this setting is configured at the managed control-plane / node pool level via the Google Cloud Console, gcloud CLI, or IaC, not through Kubernetes API objects. Refer to the Manual Steps section for how to create or update node pools with GKE Sandbox (gVisor) enabled.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Report GKE Sandbox (gVisor) status for all node pools in all clusters in a project.
        # REQUIREMENTS:
        #   - gcloud CLI authenticated and configured
        #   - jq installed
        #
        # USAGE:
        #   PROJECT_ID="my-project" ./check_gke_sandbox.sh
        #

        set -euo pipefail

        PROJECT_ID="${PROJECT_ID:-}"

        if [[ -z "${PROJECT_ID}" ]]; then
          echo "ERROR: Set PROJECT_ID environment variable." >&2
          exit 1
        fi

        echo "Project: ${PROJECT_ID}"
        echo "Time:    $(date -Iseconds)"
        echo

        # List all clusters (both zonal and regional)
        clusters_json="$(gcloud container clusters list \
          --project "${PROJECT_ID}" \
          --format='json(name,location,endpoint,resourceLabels,loggingService,monitoringService)')"

        if [[ "$(echo "${clusters_json}" | jq 'length')" -eq 0 ]]; then
          echo "No GKE clusters found in project ${PROJECT_ID}."
          exit 0
        fi

        echo "${clusters_json}" | jq -r '.[] | @base64' | while read -r cluster_b64; do
          _jq() { echo "${cluster_b64}" | base64 --decode | jq -r "${1}"; }

          CLUSTER_NAME="$(_jq '.name')"
          LOCATION="$(_jq '.location')"

          echo "================================================================================"
          echo "Cluster: ${CLUSTER_NAME}"
          echo "Location: ${LOCATION}"
          echo

          # List node pools for this cluster
          node_pools_json="$(gcloud container node-pools list \
            --cluster "${CLUSTER_NAME}" \
            --location "${LOCATION}" \
            --project "${PROJECT_ID}" \
            --format='json(name,config.imageType,config.sandboxConfig)')"

          if [[ "$(echo "${node_pools_json}" | jq 'length')" -eq 0 ]]; then
            echo "  No node pools found."
            echo
            continue
          fi

          echo "  Node pools:"
          echo "${node_pools_json}" | jq -r '.[] | @base64' | while read -r np_b64; do
            _npjq() { echo "${np_b64}" | base64 --decode | jq -r "${1}"; }

            NP_NAME="$(_npjq '.name')"
            IMAGE_TYPE="$(_npjq '.config.imageType // "UNKNOWN"')"
            SANDBOX_TYPE="$(_npjq '.config.sandboxConfig.type // "NONE"')"

            # Simple classification
            if [[ "${SANDBOX_TYPE}" == "GVISOR" ]]; then
              STATUS="SANDBOX_ENABLED"
            else
              STATUS="SANDBOX_DISABLED"
            fi

            echo "    - nodePool: ${NP_NAME}"
            echo "        imageType:   ${IMAGE_TYPE}"
            echo "        sandboxType: ${SANDBOX_TYPE}"
            echo "        status:      ${STATUS}"
          done

          echo
        done

        cat <<'EOF'

        INTERPRETING RESULTS
        --------------------
        For each node pool:

        - sandboxType == "GVISOR" and status == "SANDBOX_ENABLED"
            => GKE Sandbox (gVisor) is enabled for that node pool.

        - sandboxType == "NONE" or sandboxType is empty and status == "SANDBOX_DISABLED"
            => GKE Sandbox is NOT enabled for that node pool.

        WHAT INDICATES A PROBLEM
        ------------------------
        - If you have workloads that are untrusted, multi-tenant, or high-risk and they
          are scheduled on node pools where:
            - sandboxType is "NONE" (or absent), i.e., SANDBOX_DISABLED, and
            - imageType is NOT explicitly using sandbox (no gVisor),
          then this is a potential finding against CIS GKE 5.10.3.

        Next steps must be decided manually:
        - Identify which workloads are untrusted/risky.
        - Ensure those workloads are scheduled onto node pools with sandboxType "GVISOR".
        - Consider creating dedicated gVisor-enabled node pools and using node selectors
          / taints / tolerations to isolate untrusted workloads onto them.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
