> ## 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 Root Containers

### More Info:

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

### Risk Level

Critical

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS EKS
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify where root is allowed today**
           * On any machine with kubectl access:
             ```bash theme={null}
             kubectl get psp --all-namespaces -o yaml
             kubectl get clusterroles.rbac.authorization.k8s.io,roles.rbac.authorization.k8s.io \
               --all-namespaces -o yaml
             kubectl get clusterrolebindings.rbac.authorization.k8s.io,rolebindings.rbac.authorization.k8s.io \
               --all-namespaces -o yaml
             ```
           * Review any existing PodSecurityPolicies (if still in use) and RBAC bindings to see which subjects (users, groups, service accounts) are allowed to use PSPs or policies that let containers run as root.

        2. **Review current admission / security posture per namespace**
           * On any machine with kubectl access:
             ```bash theme={null}
             kubectl get ns
             kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels}{"\n"}{end}'
             kubectl get psp -o yaml 2>/dev/null
             kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.runAsUser}{"\t"}{range .spec.containers[*]}{.name}{"="}{.securityContext.runAsUser}{";"}{end}{"\n"}{end}'
             ```
           * Use these outputs to map which namespaces are enforcing non-root (via PSP, Pod Security Admission labels, or other policies) and which are not.

        3. **Identify workloads currently running as root or likely to run as root**
           * On any machine with kubectl access:
             ```bash theme={null}
             kubectl get pods -A -o wide
             kubectl get pods -A -o json | jq -r '
               .items[] |
               .metadata.namespace as $ns |
               .metadata.name as $pod |
               .spec.initContainers[]? as $c |
               [$ns, $pod, "init", $c.name,
                ($c.securityContext.runAsUser // "inherit"),
                ($c.securityContext.runAsNonRoot // "inherit")] | @tsv
             '
             kubectl get pods -A -o json | jq -r '
               .items[] |
               .metadata.namespace as $ns |
               .metadata.name as $pod |
               .spec.containers[] as $c |
               [$ns, $pod, "container", $c.name,
                ($c.securityContext.runAsUser // "inherit"),
                ($c.securityContext.runAsNonRoot // "inherit")] | @tsv
             '
             ```
           * Cross-check with image documentation or Dockerfiles for key workloads to determine whether they expect to run as root.

        4. **Decide namespace policy: where to forbid root and where (if anywhere) to allow it**
           * Using the evidence above, classify namespaces into:
             * **Strict**: must not allow root containers (most application namespaces).
             * **Exception**: temporarily or permanently require root (e.g., system add-ons, legacy apps, node-level agents).
           * For each **exception** namespace, document:
             * Business/technical justification for root.
             * Owner and review date.
             * Plan (if any) to migrate to non-root.

        5. **Implement or tighten admission controls to enforce non-root**
           * On any machine with kubectl access, for namespaces that should be strict, configure or adjust admission policy according to your environment:
             * If you still use PodSecurityPolicy, ensure PSPs used by those namespaces have:
               ```yaml theme={null}
               spec:
                 runAsUser:
                   rule: MustRunAsNonRoot
               ```
               or:
               ```yaml theme={null}
               spec:
                 runAsUser:
                   rule: MustRunAs
                   ranges:
                     - min: 1000
                       max: 65535
               ```
             * Update RBAC so only appropriate subjects can use any PSP that permits root.
             * If using Pod Security Admission or a 3rd-party policy engine (OPA/Gatekeeper, Kyverno, etc.), configure equivalent policies that deny pods whose containers can run as UID 0, except in documented exception namespaces.

        6. **Re-verify and monitor**
           * On any machine with kubectl access, re-check that policies and workloads align with your decisions:
             ```bash theme={null}
             kubectl get psp -o yaml 2>/dev/null
             kubectl get pods -A -o json | jq -r '
               .items[] |
               .metadata.namespace as $ns |
               .metadata.name as $pod |
               .spec.containers[] as $c |
               [$ns, $pod, $c.name,
                ($c.securityContext.runAsUser // "inherit"),
                ($c.securityContext.runAsNonRoot // "inherit")] | @tsv
             '
             ```
           * Attempt to deploy a test pod running as root into a strict namespace and confirm it is rejected by admission controls.
      </Accordion>

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

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

        #### 1. List namespaces and existing PodSecurityPolicies (if PSPs are enabled)

        ```bash theme={null}
        kubectl get ns
        kubectl get podsecuritypolicies.policy
        ```

        Problem indication:

        * No PodSecurityPolicies exist, or
        * There is no PSP clearly intended to restrict `runAsUser` away from root.

        #### 2. Inspect PodSecurityPolicies for root-user allowances

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

        In the output, examine each PSP’s `spec.runAsUser`:

        You are looking for entries like:

        ```yaml theme={null}
        spec:
          runAsUser:
            rule: RunAsAny
        ```

        or:

        ```yaml theme={null}
        spec:
          runAsUser:
            rule: MustRunAs
            ranges:
              - min: 0
                max: 0
        ```

        or any `ranges` that include `0`.

        Problem indication:

        * `rule: RunAsAny`, or
        * `rule: MustRunAs` with any range that includes UID `0`, or
        * `runAsUser` missing entirely (treated as allowing root, depending on other policies).

        A compliant PSP for this control will have:

        ```yaml theme={null}
        spec:
          runAsUser:
            rule: MustRunAsNonRoot
        ```

        or:

        ```yaml theme={null}
        spec:
          runAsUser:
            rule: MustRunAs
            ranges:
              - min: 10000
                max: 20000   # example non-root range, must not include 0
        ```

        #### 3. Check which PSPs are actually usable in each namespace

        First, list service accounts and their PSP-related bindings:

        ```bash theme={null}
        kubectl get serviceaccounts --all-namespaces
        kubectl get clusterrolebindings.rbac.authorization.k8s.io
        kubectl get rolebindings.rbac.authorization.k8s.io --all-namespaces
        ```

        Then, for bindings that grant `use` on PSPs, get details:

        ```bash theme={null}
        kubectl get clusterrole -o yaml | grep -A5 "podsecuritypolicies.policy"
        kubectl get role -A -o yaml | grep -A5 "podsecuritypolicies.policy"
        ```

        Problem indication:

        * Workload service accounts (or `system:serviceaccounts:<ns>`) are bound to PSPs that:
          * have `runAsUser.rule: RunAsAny`, or
          * allow UID ranges including `0`,
          * or there is no binding to any restrictive PSP, so only permissive/default PSPs apply.

        #### 4. Spot workloads currently configured to run as root (for human review)

        This does not prove admission policy, but highlights where root may be in use.

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

        Problem indication:

        * Pods or containers explicitly configured with `runAsUser: 0`.
        * Pods/containers without `runAsNonRoot: true` and no policy preventing root, combined with permissive PSPs from steps 2–3.

        #### 5. Verification after any policy changes

        Re-run:

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

        Confirm:

        * Every PSP intended for general workloads has `.spec.runAsUser.rule` set to `MustRunAsNonRoot` or `MustRunAs` with UID ranges that do not include `0`.
        * RBAC bindings from step 3 ensure that regular workload service accounts are not able to `use` any PSP that allows `RunAsAny` or UID `0`.

        Human judgement is required:

        * Decide which namespaces/workloads, if any, are allowed to run as root.
        * Ensure that PSPs and RBAC bindings reflect that decision, and that unrestricted PSPs are not broadly bound.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Run on: any machine with kubectl access and current context set to the target cluster
        # Purpose: Report namespaces and workloads that can admit root containers (no enforced non-root policy)

        set -euo pipefail

        echo "=== Cluster-wide admission/root-container posture report ==="
        echo "Context: $(kubectl config current-context)"
        echo

        ############################################
        # 1) PodSecurity (built-in admission) NS labels
        ############################################
        echo "== 1) Namespaces and PodSecurity labels (privileged/baseline/restricted) =="
        kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range $k,$v := .metadata.labels}{$k}={"$v"}{";"}{end}{"\n"}{end}' \
          | column -t
        echo
        cat <<'EOF'
        INTERPRETATION (PodSecurity):
        - Namespaces WITHOUT any pod-security.kubernetes.io/* labels:
            -> PROBLEM: No PodSecurity standard level is enforced; pods may run as root unless restricted elsewhere.
        - Namespaces labeled with:
            pod-security.kubernetes.io/enforce: privileged
            -> PROBLEM: Effectively no PodSecurity restrictions; root containers are allowed.
        - Namespaces labeled with:
            pod-security.kubernetes.io/enforce: baseline
            -> REVIEW: Baseline allows many images that default to root; you must rely on other policies (PSP, PSP-equivalent, or admission).
        - Namespaces labeled with:
            pod-security.kubernetes.io/enforce: restricted
            -> BETTER: Restricted profile *tends* to require non-root, but still review workload-level settings below.
        EOF
        echo

        ############################################
        # 2) PodSecurityPolicy (if present)
        ############################################
        echo "== 2) PodSecurityPolicies and runAsUser rules =="
        if kubectl get psp >/dev/null 2>&1; then
          kubectl get psp -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.runAsUser.rule}{"\t"}{.spec.runAsUser.ranges}{"\n"}{end}' \
            | column -t
        else
          echo "No PodSecurityPolicy resources detected (PSP likely disabled or removed)."
        fi
        echo
        cat <<'EOF'
        INTERPRETATION (PSP):
        - PSP with spec.runAsUser.rule = RunAsAny:
            -> PROBLEM: Does not prevent root containers.
        - PSP with spec.runAsUser.rule = MustRunAsNonRoot:
            -> GOOD: Prevents root UID 0 from being used.
        - PSP with spec.runAsUser.rule = MustRunAs with ranges that include 0:
            -> PROBLEM: Explicitly allows UID 0.
        - PSP with spec.runAsUser.rule = MustRunAs with ranges that EXCLUDE 0:
            -> GOOD: Only non-root UIDs are allowed.
        NOTE: You must also check which PSPs are bound via RBAC to which subjects/namespaces.
        EOF
        echo

        ############################################
        # 3) Workload-level securityContext that may allow / force root
        ############################################
        echo "== 3) Workloads with securityContext that may allow or force root (per namespace) =="

        NAMESPACES=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{" "}{end}')

        for ns in $NAMESPACES; do
          echo "--- Namespace: ${ns} ---"

          # Pods owned by controllers (for effective spec review)
          kubectl get pods -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.securityContext.runAsUser}{"\t"}{.spec.securityContext.runAsNonRoot}{"\t"}{range .spec.containers[*]}{.name}{"="}{.securityContext.runAsUser}","{.securityContext.runAsNonRoot}{";"}{end}{"\n"}{end}' \
            2>/dev/null | sed '1iPOD\tPOD.runAsUser\tPOD.runAsNonRoot\tCONTAINER(name=runAsUser,runAsNonRoot)' | column -t

          echo
        done

        cat <<'EOF'
        INTERPRETATION (Workloads):
        For each namespace row:
        - If POD or CONTAINER runAsUser is 0:
            -> PROBLEM: Explicitly configured to run as root.
        - If runAsUser is empty AND runAsNonRoot is empty:
            -> RISK: UID defaults to image/user; often root (0) if image not hardened.
        - If runAsNonRoot is true (pod or container) and runAsUser is NOT 0:
            -> BETTER: Admission should reject containers running as root.
        NOTE: This only shows spec hints. Actual admission behavior depends on PodSecurity, PSP, and any external admission controllers.
        EOF
        echo

        ############################################
        # 4) Quick summary of potential problem namespaces
        ############################################
        echo "== 4) Summary: Namespaces likely to admit root containers (heuristic) =="

        echo "Namespaces with NO PodSecurity labels:"
        kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{" "}{range $k,$v := .metadata.labels}{$k}{"="}{$v}{" "}{end}{"\n"}{end}' \
          | awk '!/pod-security.kubernetes.io\/enforce=|pod-security.kubernetes.io\/audit=|pod-security.kubernetes.io\/warn=/' \
          | awk '{print $1}' | sort -u

        echo
        echo "Namespaces explicitly labeled as privileged:"
        kubectl get ns -l 'pod-security.kubernetes.io/enforce=privileged' --no-headers -o custom-columns='NAMESPACE:.metadata.name' || true

        echo
        echo "Namespaces with pods explicitly setting runAsUser: 0 (root):"
        for ns in $NAMESPACES; do
          if kubectl get pods -n "$ns" >/dev/null 2>&1; then
            ROOTPODS=$(kubectl get pods -n "$ns" -o json | \
              jq -r '.items[]
                | select(
                    (.spec.securityContext.runAsUser == 0)
                    or ([(.spec.containers[]?.securityContext.runAsUser)] | any(.==0))
                  )
                | .metadata.name' 2>/dev/null || true)
            if [ -n "$ROOTPODS" ]; then
              echo "Namespace: $ns"
              echo "$ROOTPODS" | sed 's/^/  pod: /'
            fi
          fi
        done

        cat <<'EOF'

        HOW TO USE THIS REPORT:
        - Any namespace listed above, or with:
            * pod-security.kubernetes.io/enforce=privileged, OR
            * workloads explicitly setting runAsUser: 0,
          indicates a PROBLEM for this control and requires manual review and policy tightening.
        - This script does NOT change the cluster; it only surfaces where root containers are allowed or used so you can make informed decisions.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

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