> ## 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 privileged workloads and escalate access. Limit pod-create rights to the minimum required.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List who can create pods and through which roles**
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get clusterrole,role -A -o yaml | grep -nE '^(kind: (ClusterRole|Role)|  name:|  apiGroups:|  resources:|  verbs:)' 
           ```
           Then more precisely:
           ```bash theme={null}
           kubectl get clusterrole,role -A -o yaml \
             | awk '/^kind: /{k=$2} /^  name: /{n=$2} /resources:/{r=""} /- pods/{r="pods"} /verbs:/{if(r=="pods"){print k,n;}}' \
             | sort -u
           ```

        2. **Inspect a specific role/clusterrole that grants pod create**
           * Run on: any machine with kubectl access\
             Replace `<KIND>` with `role` or `clusterrole`, `<NAME>` with the name from step 1, and `<NAMESPACE>` for Roles (omit for ClusterRoles):
           ```bash theme={null}
           # For a Role
           kubectl get role <NAME> -n <NAMESPACE> -o yaml

           # For a ClusterRole
           kubectl get clusterrole <NAME> -o yaml
           ```

        3. **Decide whether each “create pods” permission is truly required** (manual review)
           * For each role/clusterrole from step 1:
             * Identify what workload or team uses it by checking its rolebindings:
               ```bash theme={null}
               kubectl get rolebinding -A --field-selector=roleRef.kind=Role,roleRef.name=<NAME>
               kubectl get clusterrolebinding -A --field-selector=roleRef.kind=ClusterRole,roleRef.name=<NAME>
               ```
             * Confirm whether those subjects actually need to create pods. If not clearly required (for example, they only need to read or list pods), plan to remove the `create` verb for `pods` from that role.

        4. **Edit the role/clusterrole to remove pod create rights**
           * Run on: any machine with kubectl access
           * For each role/clusterrole where `create` on `pods` is not strictly needed:
           ```bash theme={null}
           # Edit a Role
           kubectl edit role <NAME> -n <NAMESPACE>

           # Edit a ClusterRole
           kubectl edit clusterrole <NAME>
           ```
           In the editor, locate any `rules` entry where `resources` includes `pods` and `verbs` includes `create`, and remove `create` from that list (or remove the whole rule if it only existed for pod creation). Save and exit.

        5. **If authorization is managed via manifests/IaC, update the source files**
           * Run on: any machine with access to your Git/IaC repo
           * Locate the YAML defining the same `Role`/`ClusterRole` objects (matching names from step 4) and remove `create` from `verbs` for `pods` there as well, then apply:
           ```bash theme={null}
           kubectl apply -f <path-to-updated-rbac-manifests>.yaml
           ```

        6. **Verify that unauthenticated users cannot create pods cluster-wide**
           * Run on: any machine with kubectl access
           ```bash theme={null}
           echo "canCreatePodsAsSystemAuthenticated: $(kubectl auth can-i create pods --all-namespaces --as=system:authenticated)"
           ```
           Ensure the output is:\
           `canCreatePodsAsSystemAuthenticated: no`
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) List all Roles/ClusterRoles that can create pods
        # Run on: any machine with kubectl access

        kubectl get clusterrole -o json | jq -r '
          .items[]
          | select(.rules[]? | any(.verbs[]?; . == "create") and any(.resources[]?; . == "pods"))
          | .metadata.name
        ' | sort -u

        kubectl get role -A -o json | jq -r '
          .items[]
          | select(.rules[]? | any(.verbs[]?; . == "create") and any(.resources[]?; . == "pods"))
          | "\(.metadata.namespace):\(.metadata.name)"
        ' | sort -u
        ```

        Review the roles/clusterroles above and decide which truly need to create pods. For each one that should *not* have this right, remove `create` from the `pods` rule.

        Example: editing an over‑permissive ClusterRole named `dev-users`:

        ```bash theme={null}
        # 2) Edit the ClusterRole to remove "create" on pods
        # Run on: any machine with kubectl access

        kubectl get clusterrole dev-users -o yaml > dev-users-clusterrole.yaml
        ```

        Open `dev-users-clusterrole.yaml` in an editor and, in any rule with `resources: ["pods"]` (or including `pods`), remove `create` from `verbs`:

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

        # AFTER (create removed)
        rules:
          - apiGroups: [""]
            resources: ["pods"]
            verbs: ["get","list","watch","delete"]
        ```

        Then apply the change:

        ```bash theme={null}
        kubectl apply -f dev-users-clusterrole.yaml
        ```

        Example: editing a namespaced Role `dev-namespace:dev-role`:

        ```bash theme={null}
        # 3) Edit the Role to remove "create" on pods
        # Run on: any machine with kubectl access

        kubectl get role dev-role -n dev-namespace -o yaml > dev-role.yaml
        ```

        Edit `dev-role.yaml` similarly, removing `create` from any rule that lists `pods` in `resources`, then:

        ```bash theme={null}
        kubectl apply -f dev-role.yaml
        ```

        Repeat this edit/apply process for each Role/ClusterRole that should not be able to create pods.

        ```bash theme={null}
        # 4) Verification: confirm that generic system:authenticated users cannot create pods
        # Run on: any machine with kubectl access

        kubectl auth can-i create pods --all-namespaces --as=system:authenticated
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Minimize Access To Create Pods (CIS Kubernetes 5.1.4)
        #
        # Scope: any machine with kubectl access and credentials
        #
        # Behavior:
        # - Enumerates all Roles and ClusterRoles that allow "create" on "pods"
        # - Prints them for review
        # - For each such role, interactively asks whether to remove that permission
        # - If approved, patches the role rules to drop "create" on "pods" only
        # - Skips system roles (kube-system, system:*)
        # - Verifies using `kubectl auth can-i` at the end
        #
        # NOTE:
        # This control is MANUAL. There is no one-size-fits-all automated fix.
        # This script safely assists review and editing but always requires
        # an explicit per-role decision.

        set -euo pipefail

        # --------- Prerequisites ---------
        command -v kubectl >/dev/null 2>&1 || {
          echo "kubectl not found in PATH." >&2
          exit 1
        }

        echo "Using kubectl context:"
        kubectl config current-context || {
          echo "No current kubectl context; configure access and re-run." >&2
          exit 1
        }
        echo

        # --------- Helper: confirm ---------
        confirm() {
          # $1 = prompt
          while true; do
            read -r -p "$1 [y/N]: " ans
            case "$ans" in
              [Yy]*) return 0 ;;
              [Nn]*|"") return 1 ;;
            esac
          done
        }

        # --------- Helper: patch a Role/ClusterRole to drop 'create' on 'pods' ---------
        patch_role_drop_create_pods() {
          local kind="$1"  # Role or ClusterRole
          local name="$2"
          local namespace="${3:-}"

          # Build kubectl get command
          local get_cmd=(kubectl get "$kind" "$name" -o json)
          if [[ "$kind" == "Role" ]]; then
            get_cmd=(kubectl get role "$name" -n "$namespace" -o json)
          fi

          # Use jq to remove 'create' from verbs where resources include 'pods'
          # and drop any rule that ends up with empty verbs/resources/apiGroups
          local tmpfile
          tmpfile="$(mktemp)"

          "${get_cmd[@]}" \
            | jq '
              .rules |=
              (
                map(
                  if ( .resources? // [] ) | index("pods") != null then
                    # remove "create" from verbs
                    .verbs |= map(select(. != "create"))
                  else
                    .
                  end
                )
                # drop rules that have no verbs or no resources
                | map(select(
                    (.verbs // []) | length > 0
                    and
                    (.resources // []) | length > 0
                  ))
              )
            ' > "$tmpfile"

          # If resulting rules field is unchanged (no pod-create to remove), skip
          if diff -q <("${get_cmd[@]}") "$tmpfile" >/dev/null 2>&1; then
            echo "  No change needed (no 'create' on 'pods' found or already removed)."
            rm -f "$tmpfile"
            return 0
          fi

          echo "  Applying patch..."
          if [[ "$kind" == "Role" ]]; then
            kubectl apply -f "$tmpfile"
          else
            kubectl apply -f "$tmpfile"
          fi

          rm -f "$tmpfile"
          echo "  Patch applied."
        }

        # --------- Enumerate roles with create pods ---------

        echo "Discovering Roles with 'create' verb on 'pods'..."
        mapfile -t roles_with_create_pods < <(
          kubectl get roles --all-namespaces -o json \
            | jq -r '
                .items[]
                | select(
                    any(.rules[]?; (.resources? // []) | index("pods") != null
                                   and (.verbs? // []) | index("create") != null)
                  )
                | "\(.metadata.namespace) \(.metadata.name)"
              '
        )

        echo "Discovering ClusterRoles with 'create' verb on 'pods'..."
        mapfile -t clusterroles_with_create_pods < <(
          kubectl get clusterroles -o json \
            | jq -r '
                .items[]
                | select(
                    any(.rules[]?; (.resources? // []) | index("pods") != null
                                   and (.verbs? // []) | index("create") != null)
                  )
                | .metadata.name
              '
        )

        echo
        echo "Roles with 'create' on 'pods':"
        if ((${#roles_with_create_pods[@]} == 0)); then
          echo "  (none)"
        else
          printf '  %s\n' "${roles_with_create_pods[@]}"
        fi

        echo
        echo "ClusterRoles with 'create' on 'pods':"
        if ((${#clusterroles_with_create_pods[@]} == 0)); then
          echo "  (none)"
        else
          printf '  %s\n' "${clusterroles_with_create_pods[@]}"
        fi
        echo

        # --------- Interactive remediation ---------

        echo "Review each role and decide whether to remove 'create' on 'pods'."
        echo "System and default roles are skipped automatically."
        echo

        # Process namespace Roles
        for line in "${roles_with_create_pods[@]}"; do
          ns="${line%% *}"
          rname="${line#* }"

          # Skip kube-system and system-critical namespaces by default
          if [[ "$ns" == "kube-system" || "$ns" == "kube-public" || "$ns" == "kube-node-lease" ]]; then
            echo "Skipping Role '$rname' in namespace '$ns' (system namespace)."
            continue
          fi

          echo
          echo "Role: $rname"
          echo "Namespace: $ns"
          echo "Current rules (filtered to pods/create):"
          kubectl get role "$rname" -n "$ns" -o json \
            | jq '
                .rules[]
                | select((.resources? // []) | index("pods") != null
                         and (.verbs? // []) | index("create") != null)
              '

          if confirm "Remove 'create' on 'pods' from this Role?"; then
            patch_role_drop_create_pods "Role" "$rname" "$ns"
          else
            echo "  Left unchanged."
          fi
        done

        # Process ClusterRoles
        for cr in "${clusterroles_with_create_pods[@]}"; do
          # Skip system clusterroles
          if [[ "$cr" == system:* || "$cr" == "cluster-admin" || "$cr" == "admin" || "$cr" == "edit" ]]; then
            echo "Skipping ClusterRole '$cr' (commonly system/privileged role)."
            continue
          fi

          echo
          echo "ClusterRole: $cr"
          echo "Current rules (filtered to pods/create):"
          kubectl get clusterrole "$cr" -o json \
            | jq '
                .rules[]
                | select((.resources? // []) | index("pods") != null
                         and (.verbs? // []) | index("create") != null)
              '

          if confirm "Remove 'create' on 'pods' from this ClusterRole?"; then
            patch_role_drop_create_pods "ClusterRole" "$cr"
          else
            echo "  Left unchanged."
          fi
        done

        # --------- Final verification ---------

        echo
        echo "Final verification (CIS 5.1.4):"
        echo "canCreatePodsAsSystemAuthenticated: $(kubectl auth can-i create pods --all-namespaces --as=system:authenticated)"
        echo
        echo "Review the above result: for strict minimization, this should generally be 'no'."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
