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

# Containers Should Disallow Privilege Escalation

### More Info:

Verifies allowPrivilegeEscalation is false on every container. It defaults to true, letting a process gain more privileges than its parent.

### Risk Level

High

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. Identify all noncompliant Pods
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(\.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.allowPrivilegeEscalation == false) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " container=\(.name) image=\(.image)"
               + " allowPrivilegeEscalation=\(if .securityContext.allowPrivilegeEscalation == null then "unset" else .securityContext.allowPrivilegeEscalation end)"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end' \
           | grep 'is_compliant=false'
           ```

        2. For Pods with a controller owner (Deployment/DaemonSet/StatefulSet/Job/CronJob), edit the controller manifest
           * Pick one line from step 1 with `owner=Deployment/<ns>/<name>/...` (or other controller kind) and note its kind and name.
           * Run on: any machine with kubectl access
           ```bash theme={null}
           # Example for a Deployment; replace <namespace> and <deployment-name> with actual values
           kubectl -n <namespace> edit deployment <deployment-name>
           ```
           * In the editor, under each `containers:` and `initContainers:` entry, ensure a `securityContext` with `allowPrivilegeEscalation: false`, for example:
           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: app
                     image: your-image
                     securityContext:
                       allowPrivilegeEscalation: false
                 initContainers:
                   - name: init
                     image: your-init-image
                     securityContext:
                       allowPrivilegeEscalation: false
           ```
           * Save and exit; Kubernetes will roll out updated Pods.

        3. For naked Pods without an owner, export and edit the Pod spec, then recreate it
           * Pick a line from step 1 where `owner=` is empty and note its namespace and name.
           * Run on: any machine with kubectl access
           ```bash theme={null}
           # Export the current Pod spec without status
           kubectl -n <namespace> get pod <pod-name> -o yaml \
             | sed '/^status:/q' > /tmp/<pod-name>.yaml
           ```
           * Edit the file:
           ```bash theme={null}
           vi /tmp/<pod-name>.yaml
           ```
           * Under `.spec.containers[]` and `.spec.initContainers[]`, add or update:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           * Delete the existing Pod and recreate it from the edited manifest:
           ```bash theme={null}
           kubectl -n <namespace> delete pod <pod-name>
           kubectl -n <namespace> apply -f /tmp/<pod-name>.yaml
           ```

        4. Repeat edits for all remaining noncompliant controllers and Pods
           * Use the output from step 1 as the source of truth.
           * For each unique `owner=...` entry, repeat step 2.
           * For each line with no `owner=`, repeat step 3.

        5. (Optional hardening) Add a default policy to prevent new Pods without this setting
           * Run on: any machine with kubectl access
           * Example: a `PodSecurity` admission label enforcing `restricted` in a namespace (if not already using Pod Security or Policy Controller):
           ```bash theme={null}
           kubectl label namespace <namespace> pod-security.kubernetes.io/enforce=restricted --overwrite
           ```

        6. Verify remediation
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(\.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.allowPrivilegeEscalation == false) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " container=\(.name) image=\(.image)"
               + " allowPrivilegeEscalation=\(if .securityContext.allowPrivilegeEscalation == null then "unset" else .securityContext.allowPrivilegeEscalation end)"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
           * Confirm that the output is either `is_compliant=true` or contains no lines with `is_compliant=false`.
      </Accordion>

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

        1. Identify non‑compliant Pods (from the audit output) and, for each Pod, determine its controller (Deployment, StatefulSet, DaemonSet, Job, CronJob, etc.) from the `owner=` field in the audit output. You must patch the controller, not the live Pod.

        2. Example: patch a Deployment to set `allowPrivilegeEscalation: false` for all containers (including initContainers) using a declarative manifest.

           a. Export the existing Deployment spec:

           ```bash theme={null}
           kubectl get deployment <deployment-name> -n <namespace> -o yaml > /tmp/deployment-<deployment-name>.yaml
           ```

           b. Edit `/tmp/deployment-<deployment-name>.yaml` and, under every `containers[]` and `initContainers[]` entry in `.spec.template.spec`, ensure:

           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: <container-name>
                     image: <image>
                     securityContext:
                       allowPrivilegeEscalation: false
                     # ...other fields...
                 initContainers:
                   - name: <init-container-name>
                     image: <image>
                     securityContext:
                       allowPrivilegeEscalation: false
                     # ...other fields...
           ```

           If `securityContext` already exists, just add/update `allowPrivilegeEscalation: false` under it.

           c. Apply the updated manifest:

           ```bash theme={null}
           kubectl apply -f /tmp/deployment-<deployment-name>.yaml
           ```

           This will trigger a rolling update and recreate Pods from this Deployment with the new setting.

        3. Repeat the same export/edit/apply pattern for other controllers (DaemonSet, StatefulSet, Job, CronJob) that own non‑compliant Pods:

           ```bash theme={null}
           # DaemonSet
           kubectl get daemonset <daemonset-name> -n <namespace> -o yaml > /tmp/daemonset-<daemonset-name>.yaml
           kubectl apply -f /tmp/daemonset-<daemonset-name>.yaml

           # StatefulSet
           kubectl get statefulset <statefulset-name> -n <namespace> -o yaml > /tmp/statefulset-<statefulset-name>.yaml
           kubectl apply -f /tmp/statefulset-<statefulset-name>.yaml

           # Job
           kubectl get job <job-name> -n <namespace> -o yaml > /tmp/job-<job-name>.yaml
           kubectl apply -f /tmp/job-<job-name>.yaml

           # CronJob (edit the Pod template under spec.jobTemplate.spec.template.spec.*)
           kubectl get cronjob <cronjob-name> -n <namespace> -o yaml > /tmp/cronjob-<cronjob-name>.yaml
           kubectl apply -f /tmp/cronjob-<cronjob-name>.yaml
           ```

        4. For standalone Pods without an owning controller (no `owner=` in the audit output), recreate them from a manifest that explicitly sets `allowPrivilegeEscalation: false` on every container and init container:

           ```bash theme={null}
           kubectl get pod <pod-name> -n <namespace> -o yaml > /tmp/pod-<pod-name>.yaml
           ```

           Edit `/tmp/pod-<pod-name>.yaml` to add/update:

           ```yaml theme={null}
           spec:
             containers:
               - name: <container-name>
                 image: <image>
                 securityContext:
                   allowPrivilegeEscalation: false
             initContainers:
               - name: <init-container-name>
                 image: <image>
                 securityContext:
                   allowPrivilegeEscalation: false
           ```

           Then delete and recreate:

           ```bash theme={null}
           kubectl delete pod <pod-name> -n <namespace>
           kubectl apply -f /tmp/pod-<pod-name>.yaml
           ```

        5. Verification (same machine with kubectl access):

           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.allowPrivilegeEscalation == false) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " container=\(.name) image=\(.image)"
               + " allowPrivilegeEscalation=\(if .securityContext.allowPrivilegeEscalation == null then "unset" else .securityContext.allowPrivilegeEscalation end)"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```

           Confirm all reported containers show `allowPrivilegeEscalation=false` and `is_compliant=true` (or only `is_compliant=true` is printed).
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Remediate: Set securityContext.allowPrivilegeEscalation=false on all containers in non-system namespaces.
        # Requirements: kubectl, jq, yq (v4+). Run on any machine with kubectl access.

        set -euo pipefail

        BACKUP_DIR="./pod-allowPrivilegeEscalation-backups-$(date +%Y%m%d%H%M%S)"
        mkdir -p "${BACKUP_DIR}"

        echo "Identifying noncompliant Pods..."
        NONCOMPLIANT_FILE="${BACKUP_DIR}/noncompliant-pods.txt"
        kubectl get pods --all-namespaces -o json | jq -r '
          .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | . as $pod
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | select(.securityContext.allowPrivilegeEscalation != false)
          | "\($pod.metadata.namespace) \($pod.metadata.name)"
        ' | sort -u > "${NONCOMPLIANT_FILE}" || true

        if [[ ! -s "${NONCOMPLIANT_FILE}" ]]; then
          echo "No noncompliant Pods found. Nothing to do."
        else
          echo "Noncompliant Pods:"
          cat "${NONCOMPLIANT_FILE}"
        fi

        # Function: patch a single Pod manifest YAML on stdin
        patch_pod_yaml() {
          yq eval '
            .spec.containers |= (map(
              .securityContext.allowPrivilegeEscalation = false
            ))
            |
            ( .spec.initContainers // [] ) as $ic
            | if ($ic | length) > 0 then
                .spec.initContainers |= (map(
                  .securityContext.allowPrivilegeEscalation = false
                ))
              else
                .
              end
          ' -
        }

        while read -r NS NAME; do
          [[ -z "${NS}" || -z "${NAME}" ]] && continue
          echo "Processing Pod ${NS}/${NAME}..."

          # Backup original
          kubectl get pod "${NAME}" -n "${NS}" -o yaml > "${BACKUP_DIR}/${NS}__${NAME}.yaml"

          # Get owning controller (if any)
          OWNER_KIND=""
          OWNER_NAME=""
          OWNER_APIVERSION=""
          read -r OWNER_KIND OWNER_NAME OWNER_APIVERSION < <(
            kubectl get pod "${NAME}" -n "${NS}" -o json | jq -r '
              .metadata.ownerReferences // []
              | map(select(.controller)) | .[0] // empty
              | "\(.kind) \(.name) \(.apiVersion)"
            ' 2>/dev/null || true
          )

          if [[ -n "${OWNER_KIND}" && -n "${OWNER_NAME}" ]]; then
            echo "  Pod is controlled by ${OWNER_KIND}/${OWNER_NAME} (${OWNER_APIVERSION}). Patching controller template."

            # Determine full resource identifier for kubectl
            CASE_INSENSITIVE_KIND=$(echo "${OWNER_KIND}" | tr '[:upper:]' '[:lower:]')

            # Fetch controller manifest
            CTRL_FILE="${BACKUP_DIR}/controller-${NS}__${CASE_INSENSITIVE_KIND}__${OWNER_NAME}.yaml"
            kubectl get "${CASE_INSENSITIVE_KIND}" "${OWNER_NAME}" -n "${NS}" -o yaml > "${CTRL_FILE}"

            # Patch pod template containers in controller
            yq eval '
              .spec.template.spec.containers |= (map(
                .securityContext.allowPrivilegeEscalation = false
              ))
              |
              ( .spec.template.spec.initContainers // [] ) as $ic
              | if ($ic | length) > 0 then
                  .spec.template.spec.initContainers |= (map(
                    .securityContext.allowPrivilegeEscalation = false
                  ))
                else
                  .
                end
            ' "${CTRL_FILE}" > "${CTRL_FILE}.patched"

            kubectl apply -f "${CTRL_FILE}.patched"

            echo "  Patched controller ${OWNER_KIND}/${NS}/${OWNER_NAME}. Rolling update will replace Pods."

          else
            echo "  Pod has no controller. Patching Pod directly (may be overwritten if recreated externally)."

            POD_FILE="${BACKUP_DIR}/pod-${NS}__${NAME}.yaml"
            kubectl get pod "${NAME}" -n "${NS}" -o yaml > "${POD_FILE}"

            patch_pod_yaml < "${POD_FILE}" > "${POD_FILE}.patched"
            kubectl apply -f "${POD_FILE}.patched"
          fi

        done < "${NONCOMPLIANT_FILE}"

        echo "Waiting briefly for rollouts..."
        sleep 10

        echo "Verification:"
        kubectl get pods --all-namespaces -o json | jq -r '
          [ .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | (.securityContext.allowPrivilegeEscalation == false) as $ok
          | select($ok | not)
          ] as $rows
          | if ($rows | length) == 0 then
              "is_compliant=true"
            else
              "is_compliant=false (remaining noncompliant containers exist)"
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
