> ## 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 noncompliant Pods (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
             | select($ok | not)
             | "ns=\($m.namespace) pod=\($m.name) container=\(.name) image=\(.image)"
           ][]'
           ```

        2. For a stand-alone Pod (no higher-level controller), edit its spec to set `allowPrivilegeEscalation: false` (any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <NAMESPACE> edit pod <POD_NAME>
           ```
           Under each container (and `initContainers` if present), add or change:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           Save and exit to apply the change (the Pod may be recreated depending on your setup).

        3. For a Pod managed by a controller (Deployment, DaemonSet, StatefulSet, Job, CronJob), find the controller (any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <NAMESPACE> get pod <POD_NAME> -o jsonpath='{.metadata.ownerReferences[0].kind}{" "}{.metadata.ownerReferences[0].name}{"\n"}'
           ```

        4. Edit the controller’s Pod template to set `allowPrivilegeEscalation: false` for every container and initContainer (any machine with kubectl access). Example for a Deployment:
           ```bash theme={null}
           kubectl -n <NAMESPACE> edit deployment <DEPLOYMENT_NAME>
           ```
           In `.spec.template.spec.containers[]` (and `.spec.template.spec.initContainers[]` if present), ensure:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           Save and exit; this will roll out new Pods with the updated setting.

        5. For controllers of other kinds, use their specific edit commands (any machine with kubectl access) and apply the same `securityContext` change:
           ```bash theme={null}
           # DaemonSet
           kubectl -n <NAMESPACE> edit daemonset <DAEMONSET_NAME>

           # StatefulSet
           kubectl -n <NAMESPACE> edit statefulset <STATEFULSET_NAME>

           # Job
           kubectl -n <NAMESPACE> edit job <JOB_NAME>

           # CronJob (edit the job template)
           kubectl -n <NAMESPACE> edit cronjob <CRONJOB_NAME>
           ```
           Add `securityContext.allowPrivilegeEscalation: false` to every container and initContainer spec in the pod template.

        6. Verify all Pods are now compliant (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=\(.securityContext.allowPrivilegeEscalation // "unset")"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
           Confirm that either `is_compliant=true` is printed or all listed containers show `allowPrivilegeEscalation=false is_compliant=true`.
      </Accordion>

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

        1. Identify non‑compliant Pods (example using the provided audit):

        ```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.containers // []) + (.spec.initContainers // []))[]
          | select(.securityContext.allowPrivilegeEscalation != false)
          | "ns=\($m.namespace) pod=\($m.name) container=\(.name)"
          ][]'
        ```

        2. For each workload controller (Deployment, StatefulSet, DaemonSet, Job, CronJob, etc.) that creates the reported Pods, patch the Pod template to set `allowPrivilegeEscalation: false` on all containers.

        Example: Deployment

        ```bash theme={null}
        kubectl -n NAMESPACE edit deployment DEPLOYMENT_NAME
        ```

        In `.spec.template.spec.containers[].securityContext` (and `.initContainers[]` if present), ensure:

        ```yaml theme={null}
        securityContext:
          allowPrivilegeEscalation: false
        ```

        Save and exit; Kubernetes will roll out updated Pods.

        If you prefer a one‑shot patch (single container example):

        ```bash theme={null}
        kubectl -n NAMESPACE patch deployment DEPLOYMENT_NAME \
          --type='json' \
          -p='[
            {
              "op": "add",
              "path": "/spec/template/spec/containers/0/securityContext",
              "value": { "allowPrivilegeEscalation": false }
            }
          ]'
        ```

        Repeat with the appropriate resource kind/name and container index for each non‑compliant controller (StatefulSet, DaemonSet, Job, CronJob).

        3. Do not edit Pods that are directly managed by controllers; instead always edit the owning controller. For standalone Pods you manage directly:

        ```bash theme={null}
        kubectl -n NAMESPACE get pod POD_NAME -o yaml > /tmp/pod-POD_NAME.yaml
        ```

        Edit `/tmp/pod-POD_NAME.yaml` so each container has:

        ```yaml theme={null}
        securityContext:
          allowPrivilegeEscalation: false
        ```

        Then recreate:

        ```bash theme={null}
        kubectl -n NAMESPACE delete pod POD_NAME
        kubectl -n NAMESPACE apply -f /tmp/pod-POD_NAME.yaml
        ```

        4. Verification (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.containers // []) + (.spec.initContainers // []))[]
          | (.securityContext.allowPrivilegeEscalation == false) as $ok
          | select($ok | not)
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Enforce securityContext.allowPrivilegeEscalation=false on all containers
        # in non-system namespaces by patching owning controllers, not Pods.
        #
        # Requirements:
        # - Run on any machine with kubectl access and current-context set
        # - kubectl, jq, and yq (https://github.com/mikefarah/yq) must be installed
        #
        # Idempotent: re-running will keep allowPrivilegeEscalation=false and not break.

        set -euo pipefail

        # Fail fast if required tools are missing
        for bin in kubectl jq yq; do
          if ! command -v "$bin" >/dev/null 2>&1; then
            echo "ERROR: '$bin' is required but not found in PATH" >&2
            exit 1
          fi
        done

        echo "=== Discovering non-system namespaces with non-compliant Pods ==="

        # Get all Pod records as JSON, excluding core system namespaces
        PODS_JSON="$(kubectl get pods --all-namespaces -o json)"

        # Identify owning controllers (kind, name, namespace, apiVersion) for non-compliant containers
        # We skip kube-system, kube-public, kube-node-lease as per the audit.
        CONTROLLERS_JSON="$(
          echo "$PODS_JSON" | jq -r '
            [
              .items[]
              | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
              | .metadata as $m
              | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
              | select($own != null)                            # only pods with a controller
              | .spec as $spec
              | ($spec.containers // [] + $spec.initContainers // []) as $allc
              | select( any($allc[]?; (.securityContext.allowPrivilegeEscalation // true) != false) )
              | {
                  apiVersion: $own.apiVersion,
                  kind: $own.kind,
                  name: $own.name,
                  namespace: $m.namespace
                }
            ]
            | unique
          '
        )"

        if [[ -z "$CONTROLLERS_JSON" || "$CONTROLLERS_JSON" == "[]" ]]; then
          echo "No non-compliant controller-owned Pods found outside core system namespaces."
        else
          echo "=== Patching controllers to set allowPrivilegeEscalation=false ==="
          echo "$CONTROLLERS_JSON" | jq -c '.[]' | while read -r ctrl; do
            apiVersion=$(echo "$ctrl" | jq -r '.apiVersion')
            kind=$(echo "$ctrl"       | jq -r '.kind')
            name=$(echo "$ctrl"       | jq -r '.name')
            namespace=$(echo "$ctrl"  | jq -r '.namespace')

            echo "Processing ${kind}/${namespace}/${name}"

            # Fetch full controller YAML
            tmpfile="$(mktemp)"
            kubectl get "$kind" "$name" -n "$namespace" -o yaml > "$tmpfile"

            # Patch containers and initContainers: ensure securityContext.allowPrivilegeEscalation=false
            # while preserving any existing securityContext fields.
            yq -i '
              .spec.template.spec.containers //= [] |
              .spec.template.spec.initContainers //= [] |
              (.spec.template.spec.containers[] |= (
                .securityContext //= {} |
                .securityContext.allowPrivilegeEscalation = false
              )) |
              (.spec.template.spec.initContainers[] |= (
                .securityContext //= {} |
                .securityContext.allowPrivilegeEscalation = false
              ))
            ' "$tmpfile"

            # Apply the patched controller
            kubectl apply -n "$namespace" -f "$tmpfile" >/dev/null

            rm -f "$tmpfile"
          done
        fi

        echo "=== Patching standalone Pods (no controller owner) ==="

        # Handle Pods that are not owned by a controller (directly created Pods).
        STANDALONE_PODS_JSON="$(
          echo "$PODS_JSON" | jq -r '
            [
              .items[]
              | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
              | .metadata as $m
              | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
              | select($own == null)
              | .spec as $spec
              | ($spec.containers // [] + $spec.initContainers // []) as $allc
              | select( any($allc[]?; (.securityContext.allowPrivilegeEscalation // true) != false) )
              | { name: $m.name, namespace: $m.namespace }
            ]
            | unique
          '
        )"

        if [[ -z "$STANDALONE_PODS_JSON" || "$STANDALONE_PODS_JSON" == "[]" ]]; then
          echo "No non-compliant standalone Pods found outside core system namespaces."
        else
          echo "$STANDALONE_PODS_JSON" | jq -c '.[]' | while read -r pod; do
            pod_name=$(echo "$pod" | jq -r '.name')
            pod_ns=$(echo "$pod"   | jq -r '.namespace')
            echo "Patching Pod/${pod_ns}/${pod_name}"

            tmpfile="$(mktemp)"
            kubectl get pod "$pod_name" -n "$pod_ns" -o yaml > "$tmpfile"

            # Note: editing a running Pod spec directly will recreate it if it is not controlled
            # by a higher-level object; for an existing Pod, kubectl replace will delete/recreate.
            # This has operational impact: the Pod will be restarted.
            yq -i '
              .spec.containers //= [] |
              .spec.initContainers //= [] |
              (.spec.containers[] |= (
                .securityContext //= {} |
                .securityContext.allowPrivilegeEscalation = false
              )) |
              (.spec.initContainers[] |= (
                .securityContext //= {} |
                .securityContext.allowPrivilegeEscalation = false
              ))
            ' "$tmpfile"

            kubectl replace -n "$pod_ns" -f "$tmpfile" >/dev/null

            rm -f "$tmpfile"
          done
        fi

        echo "=== Verification (re-running audit) ==="

        # Re-run the provided audit to confirm compliance
        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=\(.securityContext.allowPrivilegeEscalation // "unset")"
            + " is_compliant=\(if $ok then "true" else "false" end)"
          ] as $rows
          | if ($rows | map(select(. | contains("is_compliant=false"))) | length) == 0
            then "is_compliant=true"
            else $rows[]
            end
        '

        echo "=== Done ==="
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
