> ## 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 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.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 a privileged pod that is controlled by a higher-level object (e.g., Deployment/DaemonSet/StatefulSet), edit the controller (run on any machine with kubectl access). Example for a Deployment:
           ```bash theme={null}
           kubectl -n NAMESPACE get pod POD_NAME -o jsonpath='{.metadata.ownerReferences[0].kind}{"\n"}{.metadata.ownerReferences[0].name}{"\n"}'
           # Suppose kind is Deployment and name is APP_DEPLOYMENT
           kubectl -n NAMESPACE edit deployment APP_DEPLOYMENT
           ```
           In the editor, locate each affected container or initContainer and remove or change:
           ```yaml theme={null}
           securityContext:
             privileged: true
           ```
           If specific kernel capabilities are needed, add only those:
           ```yaml theme={null}
           securityContext:
             capabilities:
               add:
                 - NET_ADMIN
                 - SYS_TIME
           ```

        3. For a privileged pod that is not controlled by any owner (standalone Pod), edit or recreate its manifest (run on any machine with kubectl access):
           ```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 each container or initContainer, remove:
           ```yaml theme={null}
           securityContext:
             privileged: true
           ```
           or replace with a minimal capabilities block as needed:
           ```yaml theme={null}
           securityContext:
             capabilities:
               add:
                 - NET_ADMIN
           ```
           Then reapply:
           ```bash theme={null}
           kubectl -n NAMESPACE delete pod POD_NAME
           kubectl -n NAMESPACE apply -f /tmp/pod-POD_NAME.yaml
           ```

        4. If multiple workloads share the same pattern, update their source manifests or Helm charts (run where your manifests/Helm live) so that future deployments do not reintroduce:
           ```yaml theme={null}
           securityContext:
             privileged: true
           ```
           and instead use only required `securityContext.capabilities.add` entries.

        5. Wait for updated workloads to roll out (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n NAMESPACE rollout status deployment/APP_DEPLOYMENT
           # Repeat for other controllers such as daemonset/STATEFULSET as appropriate
           ```

        6. Verify no remaining privileged containers (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.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[]
               end'
           ```
      </Accordion>

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

        1. Identify all privileged containers (for context before changing anything):

        ```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.privileged == true)
          | "ns=\($m.namespace) pod=\($m.name) container=\(.name)"
          ][]'
        ```

        2. For each affected pod that is managed by a higher-level controller (Deployment, StatefulSet, DaemonSet, Job, CronJob), edit the controller manifest so that new pods are created without `privileged: true`.

        Example for a Deployment (replace names/namespace as needed):

        ```bash theme={null}
        kubectl -n my-namespace edit deploy my-deployment
        ```

        In the editor, in each affected container (and initContainer) under `spec.template.spec.containers` (or `initContainers`), remove or change:

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

        If specific kernel capabilities are required, replace with only the needed ones, for example:

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

        Save and exit; Kubernetes will roll out updated pods automatically.

        3. For pods created directly (not via a controller), export, modify, and re-apply:

        ```bash theme={null}
        kubectl -n my-namespace get pod my-pod -o yaml --export > /tmp/my-pod-fixed.yaml
        ```

        Edit `/tmp/my-pod-fixed.yaml`:

        * Remove `metadata.creationTimestamp`, `metadata.resourceVersion`, `metadata.uid`, `metadata.selfLink`, `metadata.managedFields`, `status` sections if present.
        * Under each affected container/initContainer, remove `securityContext.privileged: true` or replace with a minimal `securityContext.capabilities.add` block as required.

        Then delete and recreate the pod:

        ```bash theme={null}
        kubectl -n my-namespace delete pod my-pod
        kubectl apply -f /tmp/my-pod-fixed.yaml
        ```

        4. 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.containers // []) + (.spec.initContainers // []))[]
          | (.securityContext.privileged // false) as $priv
          | "ns=\($m.namespace) pod=\($m.name) container=\(.name) privileged=\($priv)"
          ] as $rows
          | if ([$rows[] | select(. | test("privileged=true"))] | length) == 0
            then "is_compliant=true"
            else $rows[]
            end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediate privileged containers in an OKE cluster by:
        # - Detecting Pods with securityContext.privileged=true (excluding system namespaces)
        # - Identifying their owning workload (Deployment/DaemonSet/StatefulSet/Job/CronJob/ReplicaSet)
        # - Patching the owning workload template to remove privileged=true
        # - Falling back to patching standalone Pods
        #
        # Requirements (run on any machine with kubectl access):
        # - kubectl
        # - jq
        #
        # Idempotent: safe to re-run; repeated patches are no-ops.

        set -euo pipefail

        echo "Scanning for privileged containers (excluding kube-system, kube-public, kube-node-lease)..."

        # Capture audit output once
        AUDIT_OUTPUT="$(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
          | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | (.securityContext.privileged // false) as $priv
          | "ns=\($m.namespace) pod=\($m.name) container=\(.name) owner_kind=\($own.kind // "") owner_name=\($own.name // "") privileged=\($priv)"
          ][]' \
        )"

        # Filter only privileged=true lines
        PRIV_LINES="$(printf '%s\n' "$AUDIT_OUTPUT" | awk '$NF=="privileged=true"')"

        if [ -z "$PRIV_LINES" ]; then
          echo "No privileged containers found. Cluster is compliant."
          exit 0
        fi

        echo "Found privileged containers:"
        printf '%s\n' "$PRIV_LINES"

        # Helper: patch a workload template to drop securityContext.privileged
        patch_workload() {
          local ns="$1"
          local kind="$2"
          local name="$3"

          echo "Patching $kind/$ns/$name to remove container securityContext.privileged..."

          # We must handle both containers and initContainers in the pod template.
          # The patch deletes the privileged field where present; if absent, no-op.
          kubectl -n "$ns" patch "$kind" "$name" --type='merge' -p '{
            "spec": {
              "template": {
                "spec": {
                  "containers": [
                  ]
                }
              }
            }
          }' >/dev/null 2>&1 || true

          # Use strategic JSON patch to clear privileged from all containers and initContainers
          kubectl -n "$ns" patch "$kind" "$name" --type='json' -p '[
            {
              "op": "remove",
              "path": "/spec/template/spec/containers/0/securityContext/privileged"
            }
          ]' >/dev/null 2>&1 || true

          kubectl -n "$ns" patch "$kind" "$name" --type='json' -p '[
            {
              "op": "remove",
              "path": "/spec/template/spec/initContainers/0/securityContext/privileged"
            }
          ]' >/dev/null 2>&1 || true
        }

        # Helper: patch a standalone Pod (no controller owner)
        patch_pod() {
          local ns="$1"
          local pod="$2"

          echo "Patching Pod/$ns/$pod to remove container securityContext.privileged..."

          kubectl -n "$ns" patch pod "$pod" --type='json' -p '[
            {
              "op": "remove",
              "path": "/spec/containers/0/securityContext/privileged"
            }
          ]' >/dev/null 2>&1 || true

          kubectl -n "$ns" patch pod "$pod" --type='json' -p '[
            {
              "op": "remove",
              "path": "/spec/initContainers/0/securityContext/privileged"
            }
          ]' >/dev/null 2>&1 || true
        }

        # Derive unique workload owners and standalone pods from the audit output
        echo
        echo "Determining owning workloads..."

        # Process each privileged record
        printf '%s\n' "$PRIV_LINES" | while read -r line; do
          ns="$(printf '%s\n' "$line" | sed -E 's/.*ns=([^ ]+).*/\1/')"
          pod="$(printf '%s\n' "$line" | sed -E 's/.*pod=([^ ]+).*/\1/')"
          owner_kind="$(printf '%s\n' "$line" | sed -E 's/.*owner_kind=([^ ]*).*/\1/')"
          owner_name="$(printf '%s\n' "$line" | sed -E 's/.*owner_name=([^ ]*).*/\1/')"

          if [ -n "$owner_kind" ] && [ -n "$owner_name" ]; then
            # Normalize known owner kinds to top-level controllers
            # Pods owned by ReplicaSets -> patch the Deployment (if any)
            case "$owner_kind" in
              ReplicaSet)
                # Try to find the Deployment owning this ReplicaSet
                rs_json="$(kubectl -n "$ns" get rs "$owner_name" -o json 2>/dev/null || true)"
                if [ -n "$rs_json" ]; then
                  dep_name="$(printf '%s\n' "$rs_json" | jq -r '([.metadata.ownerReferences[]? | select(.controller==true and .kind=="Deployment")] | first // empty).name')"
                  if [ -n "$dep_name" ]; then
                    owner_kind="Deployment"
                    owner_name="$dep_name"
                  fi
                fi
                ;;
            esac

            echo "$ns $owner_kind $owner_name"
          else
            echo "$ns Pod $pod"
          fi
        done | sort -u | while read -r ns kind name; do
          if [ "$kind" = "Pod" ]; then
            patch_pod "$ns" "$name"
          else
            patch_workload "$ns" "$kind" "$name"
          fi
        done

        echo
        echo "Waiting for updated workloads to roll out (if applicable)..."
        sleep 10

        echo "Re-running privileged container check to verify remediation..."
        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.privileged // false) as $priv
          | select($priv == true)
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else "is_compliant=false" end
        '

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