> ## 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 The Admission Of Root Containers

### More Info:

Containers running as root (UID 0) increase the impact of a container escape. Require workloads to run as non-root.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List all namespaces and identify those that should host only non-root workloads**
           * Run on: any machine with kubectl access
           * Command:
             ```bash theme={null}
             kubectl get ns
             ```
           * Decide which namespaces must be restricted (for example: `prod`, `staging`, or all except explicitly “infra/ops” namespaces that may need privileged containers).

        2. **Review existing PodSecurity admission / security policies per target namespace**
           * Run on: any machine with kubectl access
           * Commands (use what’s relevant to your cluster):
             * For built-in Pod Security Admission labels:
               ```bash theme={null}
               kubectl get ns --show-labels
               ```
               Look for labels like `pod-security.kubernetes.io/enforce=restricted` (which already forbids root in most cases).
             * For PodSecurityPolicy (legacy clusters):
               ```bash theme={null}
               kubectl get psp -o yaml
               ```
               Review `runAsUser` fields; confirm `rule: MustRunAsNonRoot` or `rule: MustRunAs` with all `ranges` having `min > 0`.
             * For common policy engines (example: Gatekeeper):
               ```bash theme={null}
               kubectl get constraints --all-namespaces
               ```
               Review any constraints controlling `runAsUser` / `runAsNonRoot`.

        3. **Inspect current pod specs to find workloads that run as root or allow root**
           * Run on: any machine with kubectl access
           * Command (namespaced, repeat for each important namespace):
             ```bash theme={null}
             NAMESPACE=default
             kubectl get pods -n "$NAMESPACE" -o json \
               | jq -r '.items[]
                 | .metadata.name as $p
                 | (.spec.securityContext.runAsUser // "namespace-default") as $podUID
                 | (.spec.securityContext.runAsNonRoot // "namespace-default") as $podNonRoot
                 | .spec.containers[]
                 | {
                     pod: $p,
                     container: .name,
                     cRunAsUser: (.securityContext.runAsUser // $podUID),
                     cRunAsNonRoot: (.securityContext.runAsNonRoot // $podNonRoot)
                   }' \
               | jq -r 'select(.cRunAsUser == 0 or .cRunAsNonRoot == false or .cRunAsNonRoot == "namespace-default")'
             ```
           * Use this output to identify pods that are explicitly root or unconstrained (no non-root requirement and no non-root namespace default).

        4. **Design and apply namespace-level policy requiring non-root UIDs**
           * Decide whether you can adopt a strict policy (no root anywhere in that namespace) or need exceptions.
           * For Pod Security Admission (recommended where available), raise the namespace to at least `restricted` (which enforces non-root by default) or confirm it is already at that level:
             ```bash theme={null}
             NAMESPACE=default
             kubectl label ns "$NAMESPACE" \
               pod-security.kubernetes.io/enforce=restricted \
               pod-security.kubernetes.io/audit=restricted \
               pod-security.kubernetes.io/warn=restricted \
               --overwrite
             ```
           * For policy engines (e.g., Gatekeeper/Kyverno), create or update a policy in each target namespace so that containers must set `runAsNonRoot: true` or `runAsUser` with UID > 0, and exclude 0 from any allowed ranges (done via their CRDs and admission rules).

        5. **Refactor or exempt workloads that cannot yet run as non-root**
           * Using the pods discovered in step 3, update their deployment/statefulset/daemonset manifests to set non-root contexts:
             * Example change in the pod template:
               ```yaml theme={null}
               securityContext:
                 runAsNonRoot: true
                 runAsUser: 1000
               ```
               And, if needed, per-container overrides under `spec.template.spec.containers[].securityContext`.
           * If some workloads absolutely require root, formally document them and either:
             * move them into a separate, tightly controlled namespace without the non-root policy, or
             * configure scoped policy exceptions (policy engine exemptions or narrower admission rules) only for those workloads.

        6. **Verify enforcement and absence of new root-running pods**
           * Run on: any machine with kubectl access
           * Attempt to create a pod that runs as root in a restricted namespace; it should be rejected:
             ```bash theme={null}
             cat <<'EOF' >/tmp/root-pod-test.yaml
             apiVersion: v1
             kind: Pod
             metadata:
               name: root-pod-test
             spec:
               securityContext:
                 runAsUser: 0
               containers:
               - name: test
                 image: busybox
                 command: ["sh", "-c", "id -u && sleep 3600"]
             EOF

             NAMESPACE=default
             kubectl apply -n "$NAMESPACE" -f /tmp/root-pod-test.yaml
             ```
           * Confirm that admission rejects this pod (error message from PSA or your policy engine).
           * Re-run the inspection from step 3 to ensure no newly created pods are running as root or without a non-root requirement.
      </Accordion>

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

        Run these commands from any machine with `kubectl` access.

        #### 1. List all namespaces to scope your review

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

        Use this to plan which namespaces you will check, especially those where user workloads run.

        ***

        #### 2. Inspect PodSecurity admission / PodSecurityPolicy-like controls per namespace

        ##### 2.1. Check for Pod Security standards labels (if PodSecurity admission is enabled)

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

        Look for labels such as:

        * `pod-security.kubernetes.io/enforce=baseline` or `restricted`
        * `pod-security.kubernetes.io/enforce-version=v1.30` (version may differ)

        **Potential problems:**

        * Namespaces with **no** `pod-security.kubernetes.io/enforce` label.
        * Namespaces where `pod-security.kubernetes.io/enforce=privileged`.
        * Namespaces intended to be restricted that have no PodSecurity labels at all.

        These indicate that nothing is preventing root containers from being admitted in those namespaces.

        ***

        ##### 2.2. If using Gatekeeper/Kyverno or similar, list policies related to runAsNonRoot

        For Gatekeeper (OPA):

        ```bash theme={null}
        kubectl get k8spsps,configs,constraints.constraints.gatekeeper.sh,crd -A 2>/dev/null | grep -i runasnonroot || true
        kubectl get constraints.constraints.gatekeeper.sh -A 2>/dev/null | grep -Ei 'runas(non)?root|securitycontext' || true
        ```

        For Kyverno:

        ```bash theme={null}
        kubectl get cpol,pol -A 2>/dev/null | grep -Ei 'runas(non)?root|securitycontext' || true
        ```

        **Potential problems:**

        * No constraint/policy objects that mention `runAsNonRoot`, `runAsUser`, or `securityContext`.
        * Policies exist but are `audit` or `warn` only (no `enforce` mode) where enforcement is desired.

        This suggests no cluster-wide or namespace-wide policy enforcing `MustRunAsNonRoot`-style behavior.

        ***

        #### 3. Examine existing policies (where present) for MustRunAs / MustRunAsNonRoot semantics

        Adjust the kind to match what you use (Gatekeeper/Kyverno/PSP-like CRDs).

        Example for a Gatekeeper constraint enforcing non-root:

        ```bash theme={null}
        kubectl get <constraint-kind> -A -o yaml | less
        ```

        Look for fields in the policy spec equivalent to:

        * `runAsNonRoot: true`
        * `runAsUser` strategy using `MustRunAs` with `rule: MustRunAs` and `ranges` **excluding UID 0**
        * Or explicit deny rules if `runAsUser: 0` is set.

        **Potential problems:**

        * No mention of `runAsNonRoot` or `runAsUser` in the policy.
        * `MustRunAs` ranges include `0` (for example `min: 0`).
        * Policies scoped only to a small subset of namespaces, leaving others unprotected.

        ***

        #### 4. Spot-check workloads’ securityContext to understand current behavior

        This does **not** replace policy-based control, but helps assess risk.

        For a given namespace (replace `myns`):

        ```bash theme={null}
        kubectl get pods -n myns -o yaml | grep -E "name:|runAsUser:|runAsNonRoot:" -n
        ```

        Or more structured:

        ```bash theme={null}
        kubectl get pods -n myns -o jsonpath='{range .items[*]}{@.metadata.name}{"\t"}{@.spec.securityContext.runAsNonRoot}{"\t"}{@.spec.securityContext.runAsUser}{"\n"}{end}'
        ```

        **Potential problems:**

        * Pods with `runAsUser: 0`.
        * Pods with no `runAsUser` and no `runAsNonRoot`, combined with images that default to root (this needs human review of the images).
        * Absence of any namespace-level policy while such pods exist.

        ***

        #### 5. Verify absence or presence of PodSecurityPolicy (older clusters only)

        If your cluster might still have PSP:

        ```bash theme={null}
        kubectl get podsecuritypolicies.policy 2>/dev/null
        ```

        If PSPs exist, inspect them:

        ```bash theme={null}
        kubectl get podsecuritypolicies.policy -o yaml | less
        ```

        In the PSP spec, look for `runAsUser`:

        * `rule: MustRunAsNonRoot` **or**
        * `rule: MustRunAs` with `ranges` where all `min` > 0.

        **Potential problems:**

        * `runAsUser.rule` is `RunAsAny`.
        * `MustRunAs` ranges include UID 0.
        * No PSP bound via RBAC to the service accounts in the reviewed namespaces.

        ***

        These commands only surface configuration; they do not decide or apply the correct policy. Use the outputs to determine where you must define or tighten policies so that namespaces have an enforced strategy equivalent to `MustRunAsNonRoot` or `MustRunAs` with UID ranges that exclude 0.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report pods and controllers that can run as root (UID 0) or lack non-root restrictions.
        # Run on any machine with kubectl access and a current context.

        set -euo pipefail

        echo "=== Cluster-wide Pod Security Settings Report (focus: root containers) ==="
        echo "Timestamp: $(date)"
        echo

        ###############################################################################
        # 1. Namespaces WITHOUT any PodSecurityPolicy/PodSecurityAdmission-equivalent
        #    namespace-level policy label that enforces non-root.
        #    NOTE: You must adapt this section to your cluster's admission controller:
        #      - For Pod Security Admission (built-in): uses pod-security.kubernetes.io/*
        #      - For OPA Gatekeeper/Kyverno/etc.: list and review their constraints separately.
        ###############################################################################

        echo "==[1] Namespaces and Pod Security labels (for built-in Pod Security Admission) =="
        kubectl get ns --show-labels | sed 's/,/\n    /g'
        echo
        cat <<'EOF'
        Review:
        - For clusters using built-in Pod Security Admission:
          * Namespaces that do NOT have labels like:
              pod-security.kubernetes.io/enforce=baseline
              pod-security.kubernetes.io/enforce=restricted
            or equivalent, are likely NOT protected by a baseline/restricted policy and
            may allow root containers. These are candidates for new policies.
        - If you use another admission mechanism (Gatekeeper, Kyverno, etc.), review its
          constraints separately; this script only surfaces PSA labels.
        EOF
        echo

        ###############################################################################
        # 2. Pods with effective root user (runAsUser=0 or defaulting to root) or that
        #    do not explicitly forbid root (runAsNonRoot != true).
        #    This is for REVIEW ONLY; it does NOT mean "always unsafe", but these are
        #    the prime candidates to bring under policy.
        ###############################################################################

        echo "==[2] Pods that can run as root or do not explicitly require non-root =="

        # Show:
        # - Namespace, Pod, Container
        # - Pod-level securityContext.runAsUser / runAsNonRoot
        # - Container-level securityContext.runAsUser / runAsNonRoot
        # - ServiceAccount
        kubectl get pods --all-namespaces -o json \
        | jq -r '
          .items[]
          | . as $pod
          | ($pod.spec.containers[]? // []), ($pod.spec.initContainers[]? // []) 
          | . as $c
          | {
              ns: $pod.metadata.namespace,
              pod: $pod.metadata.name,
              kind: (if ($pod.spec.initContainers // []) | index($c) then "initContainer" else "container" end),
              cname: .name,
              sa: ($pod.spec.serviceAccountName // "default"),
              podRunAsUser: ($pod.spec.securityContext.runAsUser // "null"),
              podRunAsNonRoot: ($pod.spec.securityContext.runAsNonRoot // "null"),
              cRunAsUser: (.securityContext.runAsUser // "null"),
              cRunAsNonRoot: (.securityContext.runAsNonRoot // "null")
            }
          | . as $r
          | $r
          | select(
              # Flag if:
              # 1) Explicitly configured to run as UID 0 at pod or container level
              ($r.podRunAsUser == 0 or $r.cRunAsUser == 0)
              or
              # 2) Neither pod nor container explicitly has runAsNonRoot=true,
              #    meaning root is not forbidden and may be used.
              (
                ($r.podRunAsNonRoot != true)
                and ($r.cRunAsNonRoot != true)
              )
            )
          | [
              .ns,
              .pod,
              .kind,
              .cname,
              "sa=" + .sa,
              "podRunAsUser=" + (.podRunAsUser|tostring),
              "podRunAsNonRoot=" + (.podRunAsNonRoot|tostring),
              "cRunAsUser=" + (.cRunAsUser|tostring),
              "cRunAsNonRoot=" + (.cRunAsNonRoot|tostring)
            ]
          | @tsv
        ' | column -t

        cat <<'EOF'

        Interpretation of section [2] output (POTENTIAL PROBLEMS):

        Each line shows:
          NAMESPACE  POD  [container|initContainer]  CONTAINER_NAME  sa=SERVICEACCOUNT \
          podRunAsUser=...  podRunAsNonRoot=...  cRunAsUser=...  cRunAsNonRoot=...

        Pay special attention to:
        - podRunAsUser=0 or cRunAsUser=0
          -> These are explicitly configured to run as root (UID 0). This is a direct
             violation of "MustRunAsNonRoot" guidance unless there is a strong,
             documented exception.

        - podRunAsNonRoot=null AND cRunAsNonRoot=null with podRunAsUser=null AND cRunAsUser=null
          -> Neither pod nor containers demand non-root, and no explicit UID is set.
             In many images the default user is root, so these are likely root-capable.
             These are candidates to:
               * Set runAsNonRoot: true (pod and/or container level), or
               * Set runAsUser to a non-zero UID.

        The benchmark remediation requires you to create a policy for each namespace
        ensuring that:
          - runAsUser is configured via MustRunAsNonRoot, OR
          - MustRunAs is used with a UID range that excludes 0.

        This script only surfaces workloads that currently:
          - Can run as root, or
          - Do not clearly require non-root.
        You must then:
          - Decide where non-root is feasible,
          - Adjust images/manifests accordingly,
          - And enforce via your chosen admission policy mechanism.
        EOF
        ```

        **Verification after you adjust policies/manifests:**

        * Re-run the script on any machine with kubectl access.
        * A healthy state is when:
          * Namespaces have appropriate policy labels (or equivalent policy via another controller).
          * Section `[2]` returns:
            * No lines with `podRunAsUser=0` or `cRunAsUser=0`.
            * As few as possible lines where `runAsNonRoot` is not `true`; any remaining should be documented exceptions.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
