> ## 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.

# Minimize Admission Of Root Containers

### More Info:

Do not generally permit containers to be run as the root user.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On any machine with kubectl access, list all namespaces and identify those that should strongly forbid root containers (typically all except system namespaces):
           ```bash theme={null}
           kubectl get ns
           ```
           Decide which namespaces must enforce non-root (e.g., all except: kube-system, kube-public, kube-node-lease, default if needed for legacy workloads).

        2. For each target namespace, inspect existing Pod Security/Admission policy mechanisms to see whether they already prevent root containers:
           ```bash theme={null}
           # Pod Security admission labels
           kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels}{"\n"}{end}'

           # PodSecurityPolicy objects (if still in use)
           kubectl get psp -o wide || true

           # Gatekeeper/kyverno policies (if used)
           kubectl get constraints --all-namespaces 2>/dev/null || true
           kubectl get cpol,pol --all-namespaces 2>/dev/null || true
           ```
           Review whether any mechanism enforces `runAsNonRoot: true` or `runAsUser` ranges that exclude UID 0.

        3. For each policy mechanism in use, examine the detailed rules to confirm they require non-root UIDs:
           ```bash theme={null}
           # Example: PodSecurityPolicy details
           kubectl get psp <psp-name> -o yaml

           # Example: Gatekeeper constraint
           kubectl get <constraint-kind> <constraint-name> -n <ns> -o yaml

           # Example: Kyverno policy
           kubectl get cpol <policy-name> -o yaml
           ```
           Verify that they enforce either `MustRunAsNonRoot` (or equivalent `runAsNonRoot: true`) or `MustRunAs` with UID ranges that do not include 0 for containers and pods in the target namespaces.

        4. Where no such enforcement exists for a target namespace, design or update a namespace‑scoped policy to require non‑root containers, using the mechanism your cluster supports. For example, with PodSecurityPolicy still enabled, you might define a PSP that contains:
           ```yaml theme={null}
           runAsUser:
             rule: MustRunAsNonRoot
           ```
           or:
           ```yaml theme={null}
           runAsUser:
             rule: MustRunAs
             ranges:
               - min: 1000
                 max: 65535
           ```
           Then bind this policy (or the equivalent Gatekeeper/Kyverno policy) so that it applies to all service accounts in the target namespace.

        5. Before enforcing the new or updated policy, audit existing workloads in each namespace to find pods or workloads that currently run as root and would be blocked:
           ```bash theme={null}
           kubectl get pods -n <ns> -o json | jq -r '
             .items[] |
             select(
               (.spec.securityContext.runAsNonRoot == false)
               or (.spec.securityContext.runAsUser == 0)
               or ([.spec.containers[], (.spec.initContainers // [])[]] |
                   .[] |
                   (.securityContext.runAsNonRoot == false
                    or .securityContext.runAsUser == 0))
             ) |
             .metadata.name'
           ```
           For any listed workloads, review their manifests and application requirements; update them to run as a non‑root UID or formally document and justify an exception.

        6. After updating policies and workloads, verify that the policies are active and effective:
           * Confirm the policy objects and their bindings/assignments:
             ```bash theme={null}
             kubectl get psp -o yaml
             kubectl get role,rolebinding,clusterrole,clusterrolebinding -A
             ```
           * Attempt to deploy a simple pod that runs as root into a target namespace; it should be rejected by admission control. For example:
             ```bash theme={null}
             kubectl run root-test --image=busybox -n <ns> --overrides='
             {
               "apiVersion": "v1",
               "kind": "Pod",
               "spec": {
                 "containers": [
                   {
                     "name": "c",
                     "image": "busybox",
                     "command": ["sh", "-c", "sleep 3600"],
                     "securityContext": {
                       "runAsUser": 0
                     }
                   }
                 ]
               }
             }'
             ```
             Confirm that this creation fails and the error message indicates the non‑root requirement from your policy.
      </Accordion>

      <Accordion title="Using kubectl">
        ### Using kubectl

        #### 1. List all namespaces (scope of review)

        Run on: any machine with kubectl access.

        ```sh theme={null}
        kubectl get ns
        ```

        You will need to review each namespace listed.

        ***

        #### 2. Check PodSecurityPolicies (if PSP is enabled)

        ```sh theme={null}
        kubectl get psp
        ```

        For each PSP, inspect the allowed runAsUser strategies:

        ```sh theme={null}
        kubectl get psp <psp-name> -o yaml
        ```

        Look under `.spec.runAsUser`:

        * **Compliant examples:**
          * `rule: MustRunAsNonRoot`
          * `rule: MustRunAs` with `ranges` where all `min`/`max` are > 0 (no range including UID 0).

        * **Problematic indicators:**
          * `rule: RunAsAny`
          * `rule: MustRunAs` with any range including `0` (for example `min: 0` or `max: 0` or a range spanning 0).

        Also check how PSPs are bound to namespaces via RBAC:

        ```sh theme={null}
        kubectl get role,rolebinding,clusterrole,clusterrolebinding -A | grep -E 'psp|podsecuritypolicy' -i
        ```

        A problem exists where a namespace’s service accounts can use a PSP that allows `RunAsAny` or UID 0.

        ***

        #### 3. Check Pod Security Standards labels on namespaces (if used)

        ```sh theme={null}
        kubectl get ns --show-labels
        ```

        Look for labels like `pod-security.kubernetes.io/enforce`, `pod-security.kubernetes.io/audit`, `pod-security.kubernetes.io/warn`.

        * **Compliant indicators:**
          * Namespaces used for general workloads have `enforce` set to `baseline` or `restricted`.
          * For stronger guarantees against root containers, `restricted` is preferred.

        * **Problematic indicators:**
          * Missing `pod-security.kubernetes.io/enforce` label on application namespaces.
          * `enforce=privileged` or no label at all, combined with no other admission mechanism controlling user IDs.

        Labels alone do not guarantee non-root; they must be interpreted with the Pod Security Standards definition. Namespaces without any restrictive labels need closer manual review.

        ***

        #### 4. Inspect common policy controllers (Kyverno, Gatekeeper) for runAsUser rules

        If you use Kyverno:

        ```sh theme={null}
        kubectl get clusterpolicy,policy -A
        kubectl get clusterpolicy -o yaml | grep -n "runAsUser" -n
        kubectl get policy -A -o yaml | grep -n "runAsUser" -n
        ```

        If you use Gatekeeper:

        ```sh theme={null}
        kubectl get k8spspallowprivilegeescalation -A 2>/dev/null
        kubectl get k8spsprunasuser -A 2>/dev/null
        kubectl get constraints.constraints.gatekeeper.sh -A
        kubectl get k8spsprunasuser.constraints.gatekeeper.sh -A -o yaml 2>/dev/null
        ```

        Review any policies/constraints that reference `runAsUser`, `runAsNonRoot`, or Pod security context:

        * **Compliant indicators:**
          * Policies that deny pods where `securityContext.runAsNonRoot=false` or `runAsUser=0`.
          * Policies that require `runAsNonRoot=true` or `runAsUser` within non-zero ranges.

        * **Problematic indicators:**
          * No policies referencing `runAsUser` or `runAsNonRoot`.
          * Policies scoped only to a subset of namespaces, leaving important namespaces without protection.

        ***

        #### 5. Spot-check workloads in each namespace for actual root usage

        This cannot replace policy, but helps you see current behavior.

        List all pods in a namespace:

        ```sh theme={null}
        kubectl get pods -n <namespace>
        ```

        Inspect a pod spec:

        ```sh theme={null}
        kubectl get pod <pod-name> -n <namespace> -o yaml
        ```

        Look at:

        * `.spec.securityContext.runAsUser`
        * `.spec.securityContext.runAsNonRoot`
        * `.spec.containers[*].securityContext.runAsUser`
        * `.spec.containers[*].securityContext.runAsNonRoot`

        **Problematic indicators:**

        * `runAsUser: 0` anywhere.
        * `runAsNonRoot: false`.
        * No `runAsUser`/`runAsNonRoot` at pod or container level, and you know there is no enforced policy at namespace/cluster level (from steps 2–4); in that case, root containers are possible and not prevented by admission control.

        Because this check is MANUAL, you must decide, based on the policy mechanisms (PSP, PSS labels, Kyverno/Gatekeeper, or others) and the namespaces’ purpose, whether:

        * The namespace has an admission policy that effectively enforces `MustRunAsNonRoot` or `MustRunAs` with UID ranges excluding 0, or
        * It is currently allowing root containers and needs a stricter policy.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report namespaces whose pod security policy (or equivalent) allows running as root.
        # Run on any machine with kubectl access.

        set -euo pipefail

        # 1) Snapshot of PodSecurity admission labels (PSa) – modern clusters (1.25+)
        echo "=== PodSecurity Admission labels by namespace ==="
        kubectl get ns -o json \
          | jq -r '
            .items[]
            | {
                name: .metadata.name,
                enforce: .metadata.labels."pod-security.kubernetes.io/enforce",
                enforce_version: .metadata.labels."pod-security.kubernetes.io/enforce-version"
              }
            | @tsv' \
          | awk -F'\t' 'BEGIN {
              printf "%-32s %-12s %-10s\n", "NAMESPACE", "ENFORCE", "VERSION"
              print "---------------------------------------------------------------------"
            }
            {
              ns=$1; enforce=$2; ver=$3;
              if (enforce == "" ) enforce="-";
              if (ver == "" ) ver="-";
              printf "%-32s %-12s %-10s\n", ns, enforce, ver
            }'

        cat <<'EOF'

        [INTERPRETATION: PodSecurity Admission]
        - Namespaces with ENFORCE of "privileged" or "-" (unset) can admit root containers
          unless additional mechanisms (PSP, PSP-equivalent, or admission webhooks) deny them.
        - Namespaces with ENFORCE of "restricted" or a hardened custom profile are less likely
          to allow root, but you must still review any other policies below.

        EOF

        # 2) PodSecurityPolicy (PSP) – for clusters that still have PSP enabled
        echo "=== PodSecurityPolicies: runAsUser settings ==="
        if kubectl get psp >/dev/null 2>&1; then
          kubectl get psp -o json \
            | jq -r '
              .items[]
              | {
                  name: .metadata.name,
                  rule: ( .spec.runAsUser.rule // "UNSET" ),
                  ranges: ( .spec.runAsUser.ranges // [] )
                }
              | @base64' \
            | while read -r line; do
                obj=$(echo "$line" | base64 -d)
                name=$(echo "$obj" | jq -r '.name')
                rule=$(echo "$obj" | jq -r '.rule')
                ranges=$(echo "$obj" | jq -c '.ranges')

                problem=""

                if [ "$rule" = "RunAsAny" ] || [ "$rule" = "UNSET" ]; then
                  problem="YES (RunAsAny/UNSET allows root)"
                elif [ "$rule" = "MustRunAsNonRoot" ]; then
                  problem="OK (MustRunAsNonRoot)"
                elif [ "$rule" = "MustRunAs" ]; then
                  # Check if any range includes UID 0
                  includes_zero=$(echo "$ranges" | jq 'map(select(.min <= 0 and .max >= 0)) | length')
                  if [ "$includes_zero" -gt 0 ]; then
                    problem="YES (MustRunAs ranges include UID 0)"
                  else
                    problem="OK (MustRunAs ranges exclude UID 0)"
                  fi
                else
                  problem="REVIEW (unknown rule)"
                fi

                printf "%-40s %-18s %s\n" "$name" "$rule" "$problem"
              done

          cat <<'EOF'

        [INTERPRETATION: PodSecurityPolicy]
        - "RunAsAny" or "UNSET": PROBLEM – these PSPs allow containers to run as root (UID 0).
        - "MustRunAsNonRoot": OK – aligns with the requirement to avoid UID 0.
        - "MustRunAs" with any range where min <= 0 <= max: PROBLEM – UID 0 is allowed.
        - "MustRunAs" where all ranges exclude 0: OK – meets the benchmark intent.
        Next, check which namespaces and service accounts are bound to PROBLEM PSPs
        (see ClusterRoleBinding/RoleBinding associations).

        EOF
        else
          echo "No PodSecurityPolicies found (kubectl get psp failed); skipping PSP analysis."
        fi

        # 3) Namespace-level securityContext defaults (optional signal)
        echo "=== Namespace-level Pod securityContext defaults (if any) ==="
        kubectl get ns -o json \
          | jq -r '
            .items[]
            | {
                name: .metadata.name,
                runAsNonRoot: .metadata.annotations."pod-security.kubernetes.io/default-run-as-non-root",
                runAsUser: .metadata.annotations."pod-security.kubernetes.io/default-run-as-user"
              }
            | @tsv' \
          | awk -F'\t' 'BEGIN {
              printf "%-32s %-22s %-18s\n", "NAMESPACE", "DEFAULT runAsNonRoot", "DEFAULT runAsUser"
              print "--------------------------------------------------------------------------------"
            }
            {
              ns=$1; nonroot=$2; uid=$3;
              if (nonroot == "" ) nonroot="-";
              if (uid == "" ) uid="-";
              printf "%-32s %-22s %-18s\n", ns, nonroot, uid
            }'

        cat <<'EOF'

        [INTERPRETATION: Namespace defaults]
        - These annotations are NOT standard and may not exist in your cluster; they are shown
          only if present as hints. Any default UID of 0 or an explicit default that allows 0
          should be treated as a problem and reviewed.

        EOF

        # 4) Sample of existing Pods that actually run as root (evidence for review)
        echo "=== Sample of running Pods that are effectively root (UID 0) ==="
        # This inspects securityContext but does NOT exec into containers.
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | {
                ns: .metadata.namespace,
                pod: .metadata.name,
                sc: .spec.securityContext,
                containers: .spec.containers
              }
            | . as $pod
            | $pod.containers[]
            | {
                ns: $pod.ns,
                pod: $pod.pod,
                cname: .name,
                csc: .securityContext,
                pod_sc: $pod.sc
              }
            | {
                ns,
                pod,
                cname,
                # Effective runAsNonRoot / runAsUser calculation:
                c_runAsNonRoot: .csc.runAsNonRoot,
                c_runAsUser: .csc.runAsUser,
                pod_runAsNonRoot: .pod_sc.runAsNonRoot,
                pod_runAsUser: .pod_sc.runAsUser
              }
            | select(
                # Flag containers that clearly request UID 0, or have *no* non-root guarantee.
                ( ( .c_runAsUser == 0 ) or ( .pod_runAsUser == 0 ) )
                or
                (
                  ( (.c_runAsNonRoot // false) == false )
                  and ( (.pod_runAsNonRoot // false) == false )
                )
              )
            | @tsv' \
          | awk -F'\t' 'BEGIN {
              printf "%-20s %-40s %-25s\n", "NAMESPACE", "POD", "CONTAINER (REVIEW)"
              print "--------------------------------------------------------------------------------------"
            }
            {
              printf "%-20s %-40s %-25s\n", $1, $2, $3
            }'

        cat <<'EOF'

        [INTERPRETATION: Existing Pods]
        - Listed containers are *candidates* for running as root because:
          * They explicitly set runAsUser: 0 at pod or container level, OR
          * Neither pod nor container enforces runAsNonRoot=true.
        - This is evidence for human review. Not all listed workloads must be changed
          (some system components may legitimately require root), but they should be
          justified and documented.

        EOF

        echo "=== Completed root-admission policy and workload inventory ==="
        echo "Review the sections marked PROBLEM or REVIEW and decide per-namespace policy:"
        echo "- Ensure policy uses MustRunAsNonRoot OR MustRunAs with UID ranges that exclude 0."
        ```

        **Output indicating a problem (requires review/decision):**

        * PodSecurity Admission:
          * Namespaces with `ENFORCE` of `privileged` or `-` (unset).
        * PodSecurityPolicy:
          * PSP lines ending with `YES (RunAsAny/UNSET allows root)` or\
            `YES (MustRunAs ranges include UID 0)` or `REVIEW (unknown rule)`.
        * Namespace defaults:
          * Any annotation (if present) that sets a default UID of `0` or otherwise includes `0`.
        * Existing Pods:
          * Any row in the “Sample of running Pods that are effectively root (UID 0)” table.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
