> ## 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 the non-compliant Pod(s) (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
             | select($ok | not)
             | "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=false"
             ][]'
           ```

        2. For a Pod managed by a higher-level controller (Deployment/StatefulSet/DaemonSet, etc.), edit the controller manifest to set `allowPrivilegeEscalation: false` on every container (run on any machine with kubectl access; repeat per owning resource):
           ```bash theme={null}
           kubectl -n NAMESPACE edit DEPLOYMENT/NAME
           ```
           In each `.spec.template.spec.containers[]` and `.spec.template.spec.initContainers[]` entry, ensure:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           If `securityContext` exists, just add `allowPrivilegeEscalation: false` under it.

        3. For a standalone Pod (no controller owner listed in step 1 output), export, modify, and re-create it (run on any machine with kubectl access; replace NAMESPACE and POD\_NAME):
           ```bash theme={null}
           kubectl -n NAMESPACE get pod POD_NAME -o yaml > /tmp/pod-POD_NAME.yaml
           ```
           Edit `/tmp/pod-POD_NAME.yaml` and, for every entry in `spec.containers[]` and `spec.initContainers[]`, set:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           Then delete `metadata.resourceVersion`, `metadata.uid`, `metadata.creationTimestamp`, `metadata.managedFields`, and `status` sections from the file. Apply the fixed Pod:
           ```bash theme={null}
           kubectl -n NAMESPACE delete pod POD_NAME
           kubectl apply -f /tmp/pod-POD_NAME.yaml
           ```

        4. If your AKS cluster is managed via GitOps or IaC (e.g., manifests in a Git repo, Bicep/Terraform/ARM), update the source manifests instead of using `kubectl edit`, ensuring all container and initContainer specs include:
           ```yaml theme={null}
           securityContext:
             allowPrivilegeEscalation: false
           ```
           Commit and deploy according to your existing pipeline so changes persist.

        5. Consider operational impact before saving each change: updating a Pod template in a controller triggers rollout of new Pods; standalone Pods will be deleted and recreated, briefly interrupting workloads.

        6. Verify compliance (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'
           ```
           Ensure the output is exactly `is_compliant=true`.
      </Accordion>

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

        1. Identify non‑compliant Pods and their owners (for context only):

        ```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'
        ```

        2. Patch an existing Pod’s containers to set `allowPrivilegeEscalation: false` (for Pods you manage directly, knowing this will recreate them via their controller, not edit live static Pods):

        ```bash theme={null}
        NAMESPACE=default
        POD=my-pod

        kubectl get pod "${POD}" -n "${NAMESPACE}" -o yaml \
          | yq '(.spec.containers[].securityContext //={}) |= . + {"allowPrivilegeEscalation": false}
                | (.spec.initContainers[]? //.securityContext //={}) |= . + {"allowPrivilegeEscalation": false}' \
          | kubectl apply -f -
        ```

        3. Preferred: edit the owning workload manifest and re‑apply (Deployment, DaemonSet, StatefulSet, Job, etc.). Example for a Deployment (apply from any machine with kubectl):

        ```bash theme={null}
        cat << 'EOF' > deployment-secure.yaml
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: my-deployment
          namespace: default
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: my-app
          template:
            metadata:
              labels:
                app: my-app
            spec:
              containers:
                - name: my-container
                  image: my-image:tag
                  securityContext:
                    allowPrivilegeEscalation: false
              initContainers:
                - name: my-init
                  image: my-init-image:tag
                  securityContext:
                    allowPrivilegeEscalation: false
        EOF

        kubectl apply -f deployment-secure.yaml
        ```

        4. Verification (run on any machine with kubectl):

        ```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'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Remediate: Set securityContext.allowPrivilegeEscalation=false on all pod & init containers
        # Scope: Any machine with kubectl access to the AKS cluster
        set -euo pipefail

        # 1) Pre-flight: ensure kubectl & jq are available and we can talk to the cluster
        if ! command -v kubectl >/dev/null 2>&1; then
          echo "kubectl not found in PATH" >&2
          exit 1
        fi
        if ! command -v jq >/dev/null 2>&1; then
          echo "jq not found in PATH" >&2
          exit 1
        fi

        kubectl_version=$(kubectl version --short 2>/dev/null || true)
        if [ -z "$kubectl_version" ]; then
          echo "kubectl cannot reach a cluster (check KUBECONFIG / context)" >&2
          exit 1
        fi

        echo "Using kubectl context:"
        kubectl config current-context

        # 2) Find all non-excluded pods that have any container/initContainer with allowPrivilegeEscalation!=false
        echo "Discovering non-compliant pods..."
        non_compliant_pods=$(
          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 // [])) as $all
            | any($all[]?;
                   (.securityContext.allowPrivilegeEscalation // "unset") != false) as $has_bad
            | select($has_bad)
            | "\(.metadata.namespace) \(.metadata.name)"
          '
        )

        if [ -z "$non_compliant_pods" ]; then
          echo "No non-compliant pods found."
        else
          echo "Non-compliant pods (namespace name):"
          echo "$non_compliant_pods"
        fi

        # 3) Warn about controllers and mutate their templates instead of pods
        echo
        echo "NOTE:"
        echo "- Pods created by Deployments/DaemonSets/StatefulSets/Jobs/CronJobs should be fixed by editing the controller spec."
        echo "- This script will NOT patch controllers automatically; review suggested edits and apply them to your manifests or via kubectl edit."
        echo

        # Function: show suggested patch for a single Pod spec (for reference when editing controllers)
        suggest_pod_patch() {
          ns="$1"
          pod="$2"
          echo "==== Suggested securityContext patch for Pod $ns/$pod ===="
          kubectl get pod "$pod" -n "$ns" -o json | jq '
            {
              metadata: { name: .metadata.name, namespace: .metadata.namespace },
              spec: {
                containers: ((.spec.containers // []) | map(
                  .securityContext = (.securityContext // {}) + {allowPrivilegeEscalation: false}
                )),
                initContainers: ((.spec.initContainers // []) | map(
                  .securityContext = (.securityContext // {}) + {allowPrivilegeEscalation: false}
                ))
              }
            }
          '
          echo
        }

        if [ -n "$non_compliant_pods" ]; then
          while read -r ns name; do
            [ -z "$ns" ] && continue
            suggest_pod_patch "$ns" "$name"
          done <<< "$non_compliant_pods"
        fi

        # 4) Optional: interactive patch of standalone Pods (those without a controller ownerRef)
        echo "Attempting to automatically patch standalone Pods (no controller ownerReference)..."

        while read -r ns name; do
          [ -z "$ns" ] && continue

          owner_kind=$(kubectl get pod "$name" -n "$ns" -o json |
            jq -r '([(.metadata.ownerReferences // [])[] | select(.controller) | .kind] | first) // "NONE"')

          if [ "$owner_kind" != "NONE" ]; then
            echo "Skipping $ns/$name (owned by $owner_kind) - patch the controller instead."
            continue
          fi

          echo "Patching standalone Pod $ns/$name ..."
          # Idempotent JSON patch: ensures allowPrivilegeEscalation=false on all containers/initContainers
          patch='
        {
          "spec": {
            "containers": [],
            "initContainers": []
          }
        }
        '
          # Build patch dynamically from current Pod to preserve other fields
          pod_json=$(kubectl get pod "$name" -n "$ns" -o json)

          containers_patch=$(echo "$pod_json" | jq -c '
            (.spec.containers // []) | map(
              .securityContext = (.securityContext // {}) + {allowPrivilegeEscalation: false}
            )
          ')
          init_containers_patch=$(echo "$pod_json" | jq -c '
            (.spec.initContainers // []) | map(
              .securityContext = (.securityContext // {}) + {allowPrivilegeEscalation: false}
            )
          ')

          final_patch=$(jq -n \
            --argjson c "$containers_patch" \
            --argjson i "$init_containers_patch" \
            '{spec: {containers: $c, initContainers: $i}}')

          kubectl patch pod "$name" -n "$ns" --type merge -p "$final_patch"

        done <<< "$non_compliant_pods"

        # 5) Verification: re-run the audit to confirm all pods are compliant
        echo
        echo "Re-running compliance check..."
        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'
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
