> ## 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 Run As Non-Root

### More Info:

Verifies runAsNonRoot is set at pod or container level. Running as root inside a container widens the impact of a container escape.

### 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.securityContext.runAsNonRoot // false) as $podNonRoot
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | ($podNonRoot or (.securityContext.runAsNonRoot // false)) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + " container=\(.name) image=\(.image) runAsNonRoot=\($ok)"
               + " 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. If the pod is controlled by a higher-level object (Deployment, DaemonSet, etc.), get that manifest instead of editing the pod directly (run on any machine with kubectl access, adjust KIND, NAMESPACE, NAME as shown in the audit output `owner=` field):
           ```bash theme={null}
           kubectl get deployment YOUR_DEPLOYMENT_NAME -n YOUR_NAMESPACE -o yaml > /tmp/workload.yaml
           ```

        3. Edit the manifest to set `runAsNonRoot: true` at the pod level `securityContext` (preferred) (edit `/tmp/workload.yaml` on the same machine):
           ```yaml theme={null}
           spec:
             template:
               spec:
                 securityContext:
                   runAsNonRoot: true
                 containers:
                   - name: YOUR_CONTAINER
                     image: your-image
                     # container-specific securityContext is optional if pod-level is set
           ```
           If you cannot use pod-level context (for example, only some containers must be non-root), set it per container instead:
           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: YOUR_CONTAINER
                     image: your-image
                     securityContext:
                       runAsNonRoot: true
           ```

        4. Apply the updated manifest (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl apply -f /tmp/workload.yaml
           ```

        5. For standalone Pods not managed by a controller, export, modify, and recreate them (run on any machine with kubectl access, replace NAMESPACE and POD\_NAME):
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o yaml --export=false > /tmp/pod.yaml
           # Edit /tmp/pod.yaml similarly to step 3 under .spec.securityContext or .spec.containers[].securityContext
           # Remove status section to avoid server-side rejection:
           yq -i 'del(.status)' /tmp/pod.yaml
           kubectl delete pod POD_NAME -n NAMESPACE
           kubectl apply -f /tmp/pod.yaml
           ```

        6. Verify all containers now run as non-root (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.securityContext.runAsNonRoot // false) as $podNonRoot
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | ($podNonRoot or (.securityContext.runAsNonRoot // false)) as $ok
             | "runAsNonRoot=\($ok) is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | map(select(test("is_compliant=false"))) | length) == 0
               then "is_compliant=true"
               else $rows[]
               end'
           ```
      </Accordion>

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

        1. Identify the non-compliant pod (example name/namespace used below; substitute your own from the audit output):

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

        2. Edit the manifest to add a pod-level `securityContext.runAsNonRoot: true`. In `/tmp/myapp-pod.yaml`, under `spec:`, add:

        ```yaml theme={null}
        spec:
          securityContext:
            runAsNonRoot: true
          containers:
          - name: myapp-container
            image: myrepo/myimage:tag
            # existing fields...
        ```

        3. Delete and recreate the pod from the edited manifest (works only for pods not managed by a controller like Deployment/ReplicaSet/DaemonSet; for those, edit the controller instead—see Manual Steps section):

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

        4. Verification (same scope as the 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.nodeName // "") as $node
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
          | (.spec.securityContext.runAsNonRoot // false) as $podNonRoot
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | ($podNonRoot or (.securityContext.runAsNonRoot // 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) runAsNonRoot=\($ok)"
            + " 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
        #
        # Enforce securityContext.runAsNonRoot=true on all non-system Pods in an EKS cluster.
        # Scope: any machine with kubectl access and jq installed.
        # Safe to re-run: patches only Pods/Workloads that lack runAsNonRoot=true.
        #
        # NOTE:
        # - This patches higher-level controllers (Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, CronJobs)
        #   when possible so that recreated Pods inherit the setting.
        # - Standalone Pods are patched directly.
        # - Only user namespaces (excluding kube-system, kube-public, kube-node-lease) are touched.

        set -euo pipefail

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

        echo "Discovering non-compliant Pods (runAsNonRoot != true)..."

        # Capture the raw JSON once to avoid race conditions and multiple API calls
        POD_JSON="$(kubectl get pods --all-namespaces -o json)"

        # Function: list non-compliant pod records as JSON lines with key metadata
        list_non_compliant_pods() {
          echo "${POD_JSON}" | jq -c '
            .items[]
            | select(.metadata.namespace as $n
                     | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
            | . as $pod
            | .spec as $spec
            | .metadata as $m
            | (.spec.securityContext.runAsNonRoot // false) as $podNonRoot
            | ((.spec.containers // []) + (.spec.initContainers // [])) as $allContainers
            | any($allContainers[]?; .securityContext.runAsNonRoot // false | not) as $anyMissing
            | ($podNonRoot | not or $anyMissing) as $isNonCompliant
            | select($isNonCompliant)
            | {
                namespace: $m.namespace,
                name: $m.name,
                uid: $m.uid,
                owner: (
                  ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) // null
                )
              }'
        }

        NON_COMPLIANT="$(list_non_compliant_pods || true)"

        if [[ -z "${NON_COMPLIANT}" ]]; then
          echo "All user Pods are already compliant (runAsNonRoot=true)."
        else
          echo "Non-compliant Pods found; attempting to patch owning controllers where possible..."

          # Helper: patch a workload template at spec.template.spec.securityContext.runAsNonRoot
          patch_workload_template() {
            local kind ns name
            kind="$1"; ns="$2"; name="$3"

            # Check current workload object
            if ! kubectl get "${kind}" "${name}" -n "${ns}" -o json >/tmp/workload.json 2>/dev/null; then
              echo "  - WARNING: ${kind}/${ns}/${name} not found; skipping."
              return
            fi

            # Determine if already compliant
            if jq -e '
                .spec.template.spec.securityContext.runAsNonRoot == true
              ' /tmp/workload.json >/dev/null 2>&1; then
              echo "  - ${kind}/${ns}/${name} already has runAsNonRoot=true; skipping."
              return
            fi

            echo "  - Patching ${kind}/${ns}/${name} to set spec.template.spec.securityContext.runAsNonRoot=true"

            # Build a strategic merge patch that preserves other fields
            kubectl patch "${kind}" "${name}" -n "${ns}" \
              --type merge \
              -p '{
                "spec": {
                  "template": {
                    "spec": {
                      "securityContext": {
                        "runAsNonRoot": true
                      }
                    }
                  }
                }
              }' >/dev/null
          }

          # Helper: patch a standalone Pod (no controller owner) at spec.securityContext.runAsNonRoot
          patch_standalone_pod() {
            local ns name
            ns="$1"; name="$2"

            # Check current pod object
            if ! kubectl get pod "${name}" -n "${ns}" -o json >/tmp/pod.json 2>/dev/null; then
              echo "  - WARNING: Pod/${ns}/${name} not found; skipping."
              return
            fi

            if jq -e '.spec.securityContext.runAsNonRoot == true' /tmp/pod.json >/dev/null 2>&1; then
              echo "  - Pod/${ns}/${name} already has runAsNonRoot=true; skipping."
              return
            fi

            echo "  - Patching Pod/${ns}/${name} to set spec.securityContext.runAsNonRoot=true"

            kubectl patch pod "${name}" -n "${ns}" \
              --type merge \
              -p '{
                "spec": {
                  "securityContext": {
                    "runAsNonRoot": true
                  }
                }
              }' >/dev/null
          }

          # Track which workload objects we have already patched to keep the script idempotent and efficient
          declare -A PATCHED_WORKLOADS=()

          # Iterate over non-compliant pods
          while IFS= read -r line; do
            ns="$(echo "${line}" | jq -r '.namespace')"
            name="$(echo "${line}" | jq -r '.name')"
            ownerKind="$(echo "${line}" | jq -r '.owner.kind // ""')"
            ownerName="$(echo "${line}" | jq -r '.owner.name // ""')"

            if [[ -n "${ownerKind}" && -n "${ownerName}" ]]; then
              # Standardize ownerKind to known workload Kinds we can patch
              case "${ownerKind}" in
                Deployment|StatefulSet|DaemonSet|ReplicaSet|Job|CronJob)
                  key="${ownerKind}:${ns}:${ownerName}"
                  if [[ -z "${PATCHED_WORKLOADS[${key}]+x}" ]]; then
                    PATCHED_WORKLOADS["${key}"]=1
                    patch_workload_template "${ownerKind}" "${ns}" "${ownerName}"
                  else
                    echo "  - ${ownerKind}/${ns}/${ownerName} already patched in this run; skipping."
                  fi
                  ;;
                *)
                  echo "  - Owner ${ownerKind}/${ns}/${ownerName} is not a patchable workload type; patching Pod directly."
                  patch_standalone_pod "${ns}" "${name}"
                  ;;
              esac
            else
              echo "  - Pod/${ns}/${name} has no controller owner; patching Pod directly."
              patch_standalone_pod "${ns}" "${name}"
            fi
          done <<< "${NON_COMPLIANT}"
        fi

        echo
        echo "Waiting for Pods to be updated and recreated where necessary..."
        # Optional small wait; can be adjusted or removed
        sleep 5

        echo "Re-running compliance check to verify runAsNonRoot is now true on all non-excluded 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)
          | .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.securityContext.runAsNonRoot // false) as $podNonRoot
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | ($podNonRoot or (.securityContext.runAsNonRoot // 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) runAsNonRoot=\($ok)"
            + " is_compliant=\(if $ok then "true" else "false" end)"
          ] as $rows
          | if ( [ $rows[] | select(test("is_compliant=false$")) ] | length ) == 0
            then "is_compliant=true"
            else $rows[] end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
