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

# Minimize Access To Create Pods

### More Info:

The ability to create pods can be abused to run arbitrary workloads and escalate privileges. Restrict create access on pod objects to trusted subjects only.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List all Roles/ClusterRoles that can create pods
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get roles,clusterroles -A -o json | jq '
             [.items[] |
               select(
                 .rules[]? |
                 (.resources[]? == "pods" and .verbs[]? == "create")
               )
             ] | .[].metadata | {kind: .ownerReferences[0].kind, name: .name, namespace: .namespace}'
           ```
           Review each listed Role/ClusterRole to determine which subjects (users/groups/serviceaccounts) really need to create pods.

        2. Inspect a specific ClusterRole’s permissions
           * Run on: any machine with kubectl access\
             Replace CLUSTERROLE\_NAME with the actual name:
           ```bash theme={null}
           kubectl get clusterrole CLUSTERROLE_NAME -o yaml
           ```
           Identify rules where `resources` includes `pods` and `verbs` includes `create`.

        3. Remove `create` on pods from a ClusterRole that should not have it
           * Run on: any machine with kubectl access\
             Edit the ClusterRole:
           ```bash theme={null}
           kubectl edit clusterrole CLUSTERROLE_NAME
           ```
           In each `rules` entry that has `resources: ["pods", ...]` (or includes `pods`), remove `create` from the `verbs` list (keep other verbs like `get`, `list`, `watch` if still required), then save and exit.

        4. Adjust namespace-scoped Roles similarly
           * Run on: any machine with kubectl access\
             For each namespace where Roles were identified:
           ```bash theme={null}
           kubectl get role ROLE_NAME -n NAMESPACE -o yaml
           kubectl edit role ROLE_NAME -n NAMESPACE
           ```
           In `rules`, remove `create` from `verbs` wherever `resources` includes `pods`. Save when done.

        5. Re-verify there are no unintended subjects that still require pod creation
           * Run on: any machine with kubectl access\
             For any remaining Roles/ClusterRoles that must retain `pods` `create` access (e.g., system components or trusted CI/CD), document the justification and ensure their RoleBindings/ClusterRoleBindings are scoped only to the required subjects:
           ```bash theme={null}
           kubectl get rolebinding,clusterrolebinding -A -o yaml | grep -E "name: CLUSTERROLE_NAME|subjects:"
           ```
           Tighten bindings as needed (edit or delete) so only trusted subjects retain this access.

        6. Verification
           * Run on: any machine with kubectl access
           ```bash theme={null}
           access=$(kubectl get roles,clusterroles -N kube-system -A -o json | jq '
             [.items[] |
               select(
                 .rules[]? |
                 (.resources[]? == "pods" and .verbs[]? == "create")
               )
             ] | length')

           if [ "$access" -gt 0 ]; then
             echo "pods_create_access"
           else
             echo "no_pods_create_access_or_only_approved_remaining"
           fi
           ```
           Confirm that any remaining `pods` `create` permissions correspond only to explicitly approved, trusted Roles/ClusterRoles.
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with kubectl access:

        1. Identify Roles/ClusterRoles that can create pods

        ```bash theme={null}
        kubectl get roles,clusterroles -A -o json | jq -r '
          .items[]
          | select(
              .rules[]? |
              (.resources[]? == "pods" and .verbs[]? == "create")
            )
          | "\(.kind)/\(.metadata.name) [ns=\(.metadata.namespace // "cluster-scope")]"
        '
        ```

        2. For each offending Role/ClusterRole, fetch its manifest

        * Namespaced Role (replace NAMESPACE and ROLE\_NAME):

        ```bash theme={null}
        kubectl get role ROLE_NAME -n NAMESPACE -o yaml > role-ROLE_NAME.yaml
        ```

        * ClusterRole (replace CLUSTERROLE\_NAME):

        ```bash theme={null}
        kubectl get clusterrole CLUSTERROLE_NAME -o yaml > clusterrole-CLUSTERROLE_NAME.yaml
        ```

        3. Edit the manifest(s) locally to remove `create` from any rule that grants it on `pods`.

        Example before:

        ```yaml theme={null}
        rules:
          - apiGroups: [""]
            resources: ["pods"]
            verbs: ["get", "list", "watch", "create"]
        ```

        Example after (remove `create`):

        ```yaml theme={null}
        rules:
          - apiGroups: [""]
            resources: ["pods"]
            verbs: ["get", "list", "watch"]
        ```

        If a rule is only for `create` on `pods`, delete that rule block entirely.

        4. Apply the updated manifest(s)

        ```bash theme={null}
        kubectl apply -f role-ROLE_NAME.yaml
        kubectl apply -f clusterrole-CLUSTERROLE_NAME.yaml
        ```

        (Repeat for each edited file.)

        5. Re-run the verification

        ```bash theme={null}
        access=$(kubectl get roles,clusterroles -N -o json | jq '
          [.items[] |
            select(
              .rules[]? |
              (.resources[]? == "pods" and .verbs[]? == "create")
            )
          ] | length')

        if [ "$access" -gt 0 ]; then
          echo "pods_create_access"
        else
          echo "no_pods_create_access"
        fi
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # Minimize access to create pods on Roles and ClusterRoles
        # Runs on: any machine with kubectl access and current-context pointing to target cluster

        # REQUIREMENTS:
        # - kubectl installed and configured
        # - jq installed

        echo "[+] Discovering Roles/ClusterRoles with 'create' on pods..."

        tmpdir="$(mktemp -d)"
        trap 'rm -rf "${tmpdir}"' EXIT

        # Get all roles and clusterroles in JSON
        kubectl get roles,clusterroles -A -o json > "${tmpdir}/all-roles.json"

        # Extract all affected Role/ClusterRole names and kinds
        jq -r '
          .items[]
          | select(.rules[]? | (.resources[]? == "pods" and .verbs[]? == "create"))
          | [.kind, .metadata.name, (.metadata.namespace // "")] | @tsv
        ' "${tmpdir}/all-roles.json" > "${tmpdir}/affected.tsv" || true

        if [ ! -s "${tmpdir}/affected.tsv" ]; then
          echo "[+] No Roles or ClusterRoles grant create on pods. Nothing to change."
        else
          echo "[+] The following objects grant create on pods:"
          column -t "${tmpdir}/affected.tsv"

          echo
          echo "[!] This script will REMOVE the 'create' verb from any rule that includes 'pods'."
          echo "    It does NOT modify RoleBindings/ClusterRoleBindings, nor does it change"
          echo "    rules granting other verbs on pods."
          echo

          while IFS=$'\t' read -r kind name namespace; do
            ns_arg=()
            if [ -n "${namespace}" ] && [ "${kind}" = "Role" ]; then
              ns_arg=(--namespace "${namespace}")
            fi

            echo "[+] Processing ${kind}/${name}${namespace:+ in namespace ${namespace}}"

            # Fetch current YAML
            kubectl get "${kind}" "${name}" "${ns_arg[@]}" -o yaml > "${tmpdir}/${kind}_${namespace}_${name}.yaml"

            # Use yq if available for safer YAML manipulation; otherwise use jq+yaml round-trip through kubectl
            if command -v yq >/dev/null 2>&1; then
              # Remove 'create' verb from any rule on 'pods'
              yq '
                (.rules // [])
                |= map(
                  if (.resources // [] | any(. == "pods")) and (.verbs // [] | any(. == "create")) then
                    .verbs |= map(select(. != "create"))
                  else
                    .
                  end
                )
              ' "${tmpdir}/${kind}_${namespace}_${name}.yaml" > "${tmpdir}/${kind}_${namespace}_${name}.patched.yaml"
            else
              # Fallback: convert to JSON, edit with jq, apply as YAML via kubectl.
              # This will preserve semantics but may reorder fields.
              kubectl get "${kind}" "${name}" "${ns_arg[@]}" -o json \
                | jq '
                    .rules |=
                      ( . // [] | map(
                          if (.resources // [] | any(. == "pods")) and (.verbs // [] | any(. == "create")) then
                            .verbs |= map(select(. != "create"))
                          else
                            .
                          end
                        )
                      )
                  ' > "${tmpdir}/${kind}_${namespace}_${name}.patched.json"
              # Convert back to YAML via kubectl apply -f - directly from JSON
            fi

            # Apply the patched object
            if command -v yq >/dev/null 2>&1; then
              kubectl apply -f "${tmpdir}/${kind}_${namespace}_${name}.patched.yaml"
            else
              kubectl apply -f "${tmpdir}/${kind}_${namespace}_${name}.patched.json"
            fi

          done < "${tmpdir}/affected.tsv"
        fi

        echo
        echo "[+] Verifying that no Roles or ClusterRoles grant 'create' on pods..."

        access=$(kubectl get roles,clusterroles -A -o json | jq '
          [.items[] |
            select(
              .rules[]? |
              (.resources[]? == "pods" and .verbs[]? == "create")
            )
          ] | length')

        if [ "${access}" -gt 0 ]; then
          echo "[-] Verification FAILED: ${access} Role(s)/ClusterRole(s) still grant 'create' on pods."
          echo "    Inspect with:"
          echo "    kubectl get roles,clusterroles -A -o json | jq -r \"
              .items[]
              | select(.rules[]? | (.resources[]? == \\\"pods\\\" and .verbs[]? == \\\"create\\\"))
              | {kind, name: .metadata.name, namespace: .metadata.namespace}
            \""
          exit 1
        else
          echo "[+] Verification PASSED: no Roles or ClusterRoles grant 'create' on pods."
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
