> ## 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 Not Run In Privileged Mode

### More Info:

Verifies no container sets securityContext.privileged=true. A privileged container can compromise the node and every other pod scheduled on it.

### Risk Level

Critical

### 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 privileged containers (any machine with kubectl access):
           ```sh 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.privileged // false) as $priv
             | select($priv == true)
             | "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) privileged=\($priv)"
             ][]'
           ```

        2. For each affected pod, determine the owning controller (any machine with kubectl access). Replace NAMESPACE and POD\_NAME:
           ```sh theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.ownerReferences}'
           ```
           * If empty: pod is standalone.
           * If present: note `.kind` and `.name` to edit the right controller (e.g., Deployment, DaemonSet, StatefulSet).

        3. Edit the owning controller or pod manifest to remove privileged mode (any machine with kubectl access). Examples (run one appropriate command per affected workload):

           * Deployment:
             ```sh theme={null}
             kubectl -n NAMESPACE edit deployment DEPLOYMENT_NAME
             ```
           * DaemonSet:
             ```sh theme={null}
             kubectl -n NAMESPACE edit daemonset DAEMONSET_NAME
             ```
           * StatefulSet:
             ```sh theme={null}
             kubectl -n NAMESPACE edit statefulset STATEFULSET_NAME
             ```
           * Standalone Pod:
             ```sh theme={null}
             kubectl -n NAMESPACE edit pod POD_NAME
             ```

           In the opened manifest, locate each container (including `initContainers`) and remove or change:

           ```yaml theme={null}
           securityContext:
             privileged: true
           ```

           to either remove `privileged` entirely or explicitly set:

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

           If specific kernel capabilities are required, add only those instead of privileged:

           ```yaml theme={null}
           securityContext:
             capabilities:
               add:
                 - NET_ADMIN
                 - SYS_TIME
           ```

        4. If workloads are managed via manifest files or GitOps, update the source manifests (on your config/IaC repo workstation) so changes are not reverted. In each relevant YAML file, apply the same `securityContext` edits as in step 3, then re-apply:
           ```sh theme={null}
           kubectl apply -f path/to/manifest.yaml
           ```

        5. Allow pods to be recreated with the new spec. For controllers this happens automatically; for standalone pods you may need to delete and recreate them if the spec is immutable (any machine with kubectl access):
           ```sh theme={null}
           kubectl -n NAMESPACE delete pod POD_NAME
           # Recreate from updated manifest if needed
           kubectl -n NAMESPACE apply -f updated-pod.yaml
           ```

        6. Verify no containers are running privileged (any machine with kubectl access):
           ```sh 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.privileged // false) as $priv
             | "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) privileged=\($priv)"
               + " is_compliant=\(if $priv then "false" else "true" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
           Ensure the output is either `is_compliant=true` or that every listed line ends with `is_compliant=true`.
      </Accordion>

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

        1. Identify the owning controller of the privileged pod

        Use the audit output to see `owner=...`. If you only have the pod name, re-fetch it:

        ```sh theme={null}
        kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.metadata.ownerReferences[*].kind}{" "}{.metadata.ownerReferences[*].name}{" "}{.metadata.ownerReferences[*].uid}{"\n"}'
        ```

        If this prints a kind such as Deployment/StatefulSet/DaemonSet/Job, you must edit that controller, not the pod.

        2. Export the current manifest for the owning controller

        Example for a Deployment (substitute the correct kind/name/namespace):

        ```sh theme={null}
        kubectl get deployment <DEPLOYMENT_NAME> -n <NAMESPACE> -o yaml > /tmp/<DEPLOYMENT_NAME>.yaml
        ```

        For other controller types:

        ```sh theme={null}
        kubectl get statefulset <STATEFULSET_NAME> -n <NAMESPACE> -o yaml > /tmp/<STATEFULSET_NAME>.yaml
        kubectl get daemonset  <DAEMONSET_NAME>  -n <NAMESPACE> -o yaml > /tmp/<DAEMONSET_NAME>.yaml
        kubectl get job        <JOB_NAME>        -n <NAMESPACE> -o yaml > /tmp/<JOB_NAME>.yaml
        ```

        3. Edit the manifest to remove privileged mode and (optionally) add specific capabilities

        Open the exported file and, for every container (including `initContainers`) that has `securityContext.privileged: true`, remove that field or set it to `false`. If you need specific kernel capabilities, set them explicitly.

        Minimal example patch in the pod template:

        ```yaml theme={null}
        spec:
          template:
            spec:
              containers:
                - name: <CONTAINER_NAME>
                  image: <IMAGE>
                  securityContext:
                    # remove this line if present:
                    # privileged: true
                    # optionally add only required capabilities:
                    capabilities:
                      add:
                        - NET_ADMIN
                        - SYS_TIME
              # if any initContainers are privileged, fix them similarly:
              initContainers:
                - name: <INIT_CONTAINER_NAME>
                  image: <IMAGE>
                  securityContext:
                    # privileged: true  # remove this
                    capabilities:
                      add:
                        - NET_ADMIN
        ```

        Ensure no container has `privileged: true` under `securityContext`.

        4. Apply the updated manifest

        ```sh theme={null}
        kubectl apply -f /tmp/<CONTROLLER_FILE>.yaml
        ```

        This will cause a rolling update for Deployments/StatefulSets/DaemonSets; pods will be recreated with the new security context.

        5. (Optional) Delete any existing non-compliant pods to accelerate rollout

        For a Deployment:

        ```sh theme={null}
        kubectl delete pod -n <NAMESPACE> -l app=<APP_LABEL>
        ```

        Adjust the label selector to match your workload.

        6. Verification

        After the rollout completes, rerun the benchmark audit command from any machine with kubectl access:

        ```sh 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.privileged // false) as $priv
          | "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) privileged=\($priv)"
            + " is_compliant=\(if $priv then "false" else "true" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```

        Confirm that all listed containers show `privileged=false` and `is_compliant=true`, or that the output is `is_compliant=true`.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Purpose: Remove privileged=true from all non-system Pods (and their controllers)
        # Platform: GKE (any machine with kubectl access)

        set -euo pipefail

        # REQUIREMENTS:
        # - kubectl configured with sufficient RBAC to get/patch resources cluster-wide
        # - jq installed

        echo "[INFO] Discovering privileged pods (excluding kube-system, kube-public, kube-node-lease)..."

        privileged_pods_json="$(
          kubectl get pods --all-namespaces -o json | jq '
            .items[]
            | select(.metadata.namespace as $n
                     | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
            | . as $pod
            | ((.spec.containers // []) + (.spec.initContainers // []))[]
            | select(.securityContext.privileged == true)
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                ownerRefs: ($pod.metadata.ownerReferences // []),
                container: .name
              }'
        )"

        if [[ -z "$privileged_pods_json" ]]; then
          echo "[INFO] No privileged containers found."
        else
          echo "[INFO] Found privileged containers. Grouping by owning controller..."
        fi

        # Build a unique list of owner controllers and standalone pods
        # Output format: kind ns name
        controllers_file="$(mktemp)"
        pods_file="$(mktemp)"

        # Iterate over each privileged container record
        jq -c '.' <<< "$privileged_pods_json" | while read -r rec; do
          ns=$(jq -r '.ns' <<< "$rec")
          pod=$(jq -r '.pod' <<< "$rec")

          # Determine if pod has a controller
          owner_json=$(kubectl get pod "$pod" -n "$ns" -o json | jq -c '
              [(.metadata.ownerReferences // [])[] | select(.controller == true)] | first // null
          ')
          if [[ "$owner_json" == "null" ]]; then
            echo "Pod $ns/$pod" >> "$pods_file"
          else
            kind=$(jq -r '.kind' <<< "$owner_json")
            name=$(jq -r '.name' <<< "$owner_json")
            echo "$kind $ns $name" >> "$controllers_file"
          fi
        done

        # De-duplicate
        if [[ -s "$controllers_file" ]]; then
          sort -u "$controllers_file" -o "$controllers_file"
        fi
        if [[ -s "$pods_file" ]]; then
          sort -u "$pods_file" -o "$pods_file"
        fi

        patch_template="$(mktemp)"
        cat > "$patch_template" <<'EOF'
        {
          "spec": {
            "template": {
              "spec": {
                "containers": [
                  {
                    "name": "__ALL__",
                    "securityContext": {
                      "privileged": false
                    }
                  }
                ],
                "initContainers": [
                  {
                    "name": "__ALL__",
                    "securityContext": {
                      "privileged": false
                    }
                  }
                ]
              }
            }
          }
        }
        EOF

        echo "[INFO] Patching controller objects to remove privileged=true..."

        # Helper: patch a controller
        patch_controller() {
          local kind="$1" ns="$2" name="$3"

          # Use jsonpatch to avoid wiping other fields; set privileged to false where present.
          # For idempotence, failures (e.g., resource gone) are tolerated.
          kubectl get "$kind" "$name" -n "$ns" -o json | \
            jq '
              (.. | objects | select(has("securityContext")) | select(has("privileged"))) |=
              (.privileged = false)
            ' | kubectl apply -f - >/dev/null 2>&1 || true
        }

        if [[ -s "$controllers_file" ]]; then
          while read -r kind ns name; do
            echo "[INFO] Patching controller: kind=$kind ns=$ns name=$name"
            patch_controller "$kind" "$ns" "$name"
          done < "$controllers_file"
        else
          echo "[INFO] No controllers to patch."
        fi

        echo "[INFO] Patching standalone pods to remove privileged=true (will not affect controller-managed pods)."

        if [[ -s "$pods_file" ]]; then
          while read -r _ns_pod; do
            ns="${_ns_pod%% *}"
            pod="${_ns_pod##* }"

            # Patch the live Pod only. This is best-effort; controller will override on reschedule.
            kubectl get pod "$pod" -n "$ns" -o json | \
              jq '
                (.. | objects | select(has("securityContext")) | select(has("privileged"))) |=
                (.privileged = false)
              ' | kubectl apply -f - >/dev/null 2>&1 || true
            echo "[INFO] Patched standalone pod: ns=$ns pod=$pod"
          done < <(sed 's/^Pod //g' "$pods_file")
        else
          echo "[INFO] No standalone pods to patch."
        fi

        rm -f "$controllers_file" "$pods_file" "$patch_template"

        echo "[INFO] Waiting for updated workloads to roll out..."
        kubectl rollout status deployment --all --all-namespaces >/dev/null 2>&1 || true
        kubectl rollout status daemonset --all --all-namespaces >/dev/null 2>&1 || true
        kubectl rollout status statefulset --all --all-namespaces >/dev/null 2>&1 || true

        echo "[INFO] Verification: re-running privileged container audit..."
        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.privileged // false) as $priv
          | "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) privileged=\($priv)"
            + " is_compliant=\(if $priv then "false" else "true" end)"
          ] as $rows
          | if ($rows | map(select(. | contains("privileged=true"))) | length) == 0
            then "is_compliant=true"
            else ($rows[] | select(. | contains("privileged=true")))
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
