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

# Apply SecurityContext To Your Pods And Containers

### More Info:

SecurityContexts constrain the privileges and capabilities of pods and containers. Apply them to harden workloads.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify pods lacking a `securityContext`**
           * Run on: any machine with `kubectl` access
           * Command:
             ```bash theme={null}
             kubectl get pods --all-namespaces -o json \
               | jq -r '.items[]
                 | select((.spec.securityContext // {} ) == {} and
                          ( [.spec.containers[].securityContext] | map(select(. != null)) | length == 0 ))
                 | "\(.metadata.namespace) \(.metadata.name)"'
             ```
           * This lists pods where neither the pod nor any containers define a `securityContext`.

        2. **Review current security settings for selected pods**
           * Pick a workload (preferably from a non-system namespace) from the list above.
           * Command:
             ```bash theme={null}
             kubectl get pod -n NAMESPACE PODNAME -o yaml
             ```
           * Inspect `.spec.securityContext` and each `.spec.containers[].securityContext` for settings such as `runAsNonRoot`, `runAsUser`, `runAsGroup`, `readOnlyRootFilesystem`, `allowPrivilegeEscalation`, and `capabilities`.

        3. **Decide required hardening based on workload needs**
           * For each application/team owning the pods, determine:
             * Whether the container can run as non-root (`runAsNonRoot: true`, non-0 `runAsUser`).
             * Whether it needs write access to root filesystem (if not, `readOnlyRootFilesystem: true`).
             * Whether it needs extra Linux capabilities (drop all, then selectively add if required).
             * Whether privilege escalation is needed (`allowPrivilegeEscalation: false` if not).
           * Collect inputs from the app owners before changing manifests.

        4. **Update manifests to include appropriate `securityContext`**
           * Retrieve the controller manifest (Deployment/StatefulSet/Job/etc.):
             ```bash theme={null}
             kubectl get deploy -n NAMESPACE DEPLOYMENTNAME -o yaml > deployment-secctx.yaml
             ```
           * Edit `deployment-secctx.yaml` to add security contexts, for example:
             ```yaml theme={null}
             spec:
               template:
                 spec:
                   securityContext:
                     runAsNonRoot: true
                     runAsUser: 1000
                     runAsGroup: 1000
                   containers:
                     - name: app
                       image: your-image
                       securityContext:
                         readOnlyRootFilesystem: true
                         allowPrivilegeEscalation: false
                         capabilities:
                           drop: ["ALL"]
             ```
           * Apply the updated manifest:
             ```bash theme={null}
             kubectl apply -f deployment-secctx.yaml
             ```
           * Repeat with other controllers (StatefulSets, DaemonSets, Jobs, CronJobs) rather than editing pods directly.

        5. **Handle pods not managed by higher-level controllers**
           * List standalone pods (no ownerReferences):
             ```bash theme={null}
             kubectl get pods --all-namespaces -o json \
               | jq -r '.items[]
                 | select((.metadata.ownerReferences // []) | length == 0)
                 | "\(.metadata.namespace) \(.metadata.name)"'
             ```
           * For any long-lived standalone pod you intend to keep, recreate it from a manifest that includes a `securityContext`; avoid using `kubectl run` without saving and hardening the YAML first.

        6. **Verify that security contexts are now applied**
           * Re-run the initial check:
             ```bash theme={null}
             kubectl get pods --all-namespaces -o json \
               | jq -r '.items[]
                 | select((.spec.securityContext // {} ) == {} and
                          ( [.spec.containers[].securityContext] | map(select(. != null)) | length == 0 ))
                 | "\(.metadata.namespace) \(.metadata.name)"'
             ```
           * Confirm that all non-exempt workloads (per your policy) no longer appear in the output and spot-check a few pods with `kubectl get pod -n NAMESPACE PODNAME -o yaml` to ensure the intended `securityContext` settings are present.
      </Accordion>

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

        #### 1. List pods that have no pod-level securityContext

        Run on: any machine with kubectl access.

        ```bash theme={null}
        kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.securityContext==null)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
        ```

        **Indication of a problem:**\
        Any lines in the output are pods that do not define a pod-level `securityContext` at all and should be manually reviewed. Lack of a pod-level `securityContext` is a red flag, especially for non-system namespaces.

        ***

        #### 2. List containers without a container-level securityContext

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | \
        jq -r '
          .items[]
          | {
              ns: .metadata.namespace,
              pod: .metadata.name,
              containers: [.spec.containers[]? | select(.securityContext == null) | .name],
              initContainers: [.spec.initContainers[]? | select(.securityContext == null) | .name]
            }
          | select((.containers|length) > 0 or (.initContainers|length) > 0)
          | "\(.ns)\t\(.pod)\tcontainers:\(.containers|join(","))\tinitContainers:\(.initContainers|join(","))"
        '
        ```

        **Indication of a problem:**\
        Any line in the output shows a pod where one or more regular or init containers do not define a `securityContext`. These containers must be reviewed to determine if explicit restrictions are needed (usually yes).

        ***

        #### 3. Inspect a specific pod in detail

        Replace `<namespace>` and `<pod-name>`.

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

        Focus your manual review on:

        * `.spec.securityContext`
        * `.spec.containers[].securityContext`
        * `.spec.initContainers[].securityContext`

        **Indication of a problem:**\
        You see missing or overly-permissive fields such as:

        * No `securityContext` at all at pod or container level.
        * `runAsUser: 0` or `runAsNonRoot: false` (or not set where non-root is expected).
        * `privileged: true`.
        * `allowPrivilegeEscalation: true` or not set.
        * `capabilities.add` including dangerous capabilities (e.g., `SYS_ADMIN`, `NET_ADMIN`).
        * `hostNetwork: true`, `hostPID: true`, `hostIPC: true` without a clear, documented reason.
        * `readOnlyRootFilesystem: false` (or missing) where a read-only root FS is possible.

        These require human judgement to determine if the privilege level is justified.

        ***

        #### 4. Quickly surface some high‑risk patterns

        **a. Pods using privileged containers**

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | \
        jq -r '
          .items[]
          | . as $pod
          | (.spec.containers[]?, .spec.initContainers[]?)
          | select(.securityContext.privileged == true)
          | "\($pod.metadata.namespace)\t\($pod.metadata.name)\t\(.name)\tprivileged=true"
        '
        ```

        **Problem indication:** Any output shows containers running in privileged mode, which is usually a serious concern unless explicitly required.

        ***

        **b. Pods allowing privilege escalation**

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | \
        jq -r '
          .items[]
          | . as $pod
          | (.spec.containers[]?, .spec.initContainers[]?)
          | select(.securityContext.allowPrivilegeEscalation == true)
          | "\($pod.metadata.namespace)\t\($pod.metadata.name)\t\(.name)\tallowPrivilegeEscalation=true"
        '
        ```

        **Problem indication:** Any output shows containers explicitly allowing privilege escalation. This is typically not desired.

        ***

        **c. Pods running containers as root (explicitly)**

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | \
        jq -r '
          .items[]
          | . as $pod
          | (.spec.containers[]?, .spec.initContainers[]?)
          | select(.securityContext.runAsUser == 0)
          | "\($pod.metadata.namespace)\t\($pod.metadata.name)\t\(.name)\trunAsUser=0"
        '
        ```

        **Problem indication:** Any output shows containers explicitly configured to run as UID 0. This should be justified and usually avoided.

        *(Note: many images run as root implicitly; this command only catches explicit `runAsUser: 0`. Determining implicit root requires image review, not just kubectl.)*

        ***

        #### 5. Verification after you update manifests

        After you manually adjust pod or deployment manifests to add appropriate `securityContext` settings, re-run:

        * The “no pod-level securityContext” command (step 1).
        * The “containers without securityContext” command (step 2).
        * Any specific high-risk pattern commands you are targeting (step 4).

        **Verification success criteria:**

        * The previously flagged pods/containers no longer appear in the outputs, and
        * A `kubectl get pod <pod> -n <ns> -o yaml` shows the intended `securityContext` fields applied.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Report pods and containers that lack SecurityContext settings
        # Run on: any machine with kubectl access and KUBECONFIG set
        # Requires: kubectl, jq

        set -euo pipefail

        # Check dependencies
        for bin in kubectl jq; do
          if ! command -v "$bin" >/dev/null 2>&1; then
            echo "ERROR: $bin not found in PATH" >&2
            exit 1
          fi
        done

        echo "Collecting pod SecurityContext information from all namespaces..."
        echo

        # Summary counters
        total_pods=0
        pods_without_pod_sc=0
        pods_with_any_container_missing_sc=0

        # Header for detailed report
        printf "NAMESPACE\tPOD\tPOD_SC\tCONTAINER\tCONTAINER_SC\tINIT_CONTAINER\tPROBLEM\n"

        # Get all pods as JSON and iterate
        kubectl get pods --all-namespaces -o json \
        | jq -r '
          .items[]
          | {
              ns: .metadata.namespace,
              pod: .metadata.name,
              pod_sc: (.spec.securityContext // {}),

              # normal containers
              containers: (
                (.spec.containers // [])
                | map({
                    name: .name,
                    sc: (.securityContext // {})
                  })
              ),

              # init containers
              init_containers: (
                (.spec.initContainers // [])
                | map({
                    name: .name,
                    sc: (.securityContext // {})
                  })
              )
            }
          | @base64' \
        | while read -r pod_b64; do
            _jq() { echo "$pod_b64" | base64 --decode | jq -r "$1"; }

            ns=$(_jq '.ns')
            pod=$(_jq '.pod')
            pod_sc_json=$(_jq '.pod_sc')

            total_pods=$((total_pods + 1))

            # Determine if pod-level securityContext is empty
            if [ "$pod_sc_json" = "{}" ] || [ "$pod_sc_json" = "null" ]; then
              pod_sc="none"
              pods_without_pod_sc=$((pods_without_pod_sc + 1))
              pod_sc_problem="POD:missing_pod_securityContext"
            else
              pod_sc="present"
              pod_sc_problem=""
            fi

            # Process regular containers
            echo "$pod_b64" | base64 --decode \
            | jq -r '.containers[]? | @base64' \
            | while read -r c_b64; do
                c_name=$(echo "$c_b64" | base64 --decode | jq -r '.name')
                c_sc_json=$(echo "$c_b64" | base64 --decode | jq -r '.sc')

                if [ "$c_sc_json" = "{}" ] || [ "$c_sc_json" = "null" ]; then
                  c_sc="none"
                  problem="CONTAINER:missing_container_securityContext"
                  pods_with_any_container_missing_sc=$((pods_with_any_container_missing_sc + 1))
                else
                  c_sc="present"
                  problem="$pod_sc_problem"
                fi

                printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
                  "$ns" "$pod" "$pod_sc" "$c_name" "$c_sc" "no" "${problem:-}"
              done

            # Process init containers
            echo "$pod_b64" | base64 --decode \
            | jq -r '.init_containers[]? | @base64' \
            | while read -r ic_b64; do
                ic_name=$(echo "$ic_b64" | base64 --decode | jq -r '.name')
                ic_sc_json=$(echo "$ic_b64" | base64 --decode | jq -r '.sc')

                if [ "$ic_sc_json" = "{}" ] || [ "$ic_sc_json" = "null" ]; then
                  ic_sc="none"
                  problem="INIT_CONTAINER:missing_container_securityContext"
                  pods_with_any_container_missing_sc=$((pods_with_any_container_missing_sc + 1))
                else
                  ic_sc="present"
                  problem="$pod_sc_problem"
                fi

                printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
                  "$ns" "$pod" "$pod_sc" "$ic_name" "$ic_sc" "yes" "${problem:-}"
              done

            # If pod has no containers at all, still emit one line
            if ! echo "$pod_b64" | base64 --decode | jq -e '.containers | length > 0 or .init_containers | length > 0' >/dev/null 2>&1; then
              printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
                "$ns" "$pod" "$pod_sc" "-" "-" "-" "$pod_sc_problem"
            fi
          done

        echo
        echo "Cluster summary:"
        echo "  Total pods:                             $total_pods"
        echo "  Pods without pod-level SecurityContext: $pods_without_pod_sc"
        echo "  Pods with any container lacking SC:     $pods_with_any_container_missing_sc"

        cat <<'EOF'

        How to interpret the output:

        - POD_SC column:
          - "none"    => .spec.securityContext is not set on the pod (possible hardening gap).
          - "present" => Pod has a pod-level securityContext; contents must be reviewed manually.

        - CONTAINER_SC column:
          - "none"    => .spec.containers[].securityContext or .spec.initContainers[].securityContext
                         is not set. This is usually a problem and should be reviewed.
          - "present" => Container has a securityContext; you must still validate it against your
                         policies and the CIS Docker/Kubernetes recommendations.

        - PROBLEM column highlights obvious issues:
          - "POD:missing_pod_securityContext"
          - "CONTAINER:missing_container_securityContext"
          - "INIT_CONTAINER:missing_container_securityContext"

        Any line where POD_SC = "none" or CONTAINER_SC = "none" indicates a workload that
        likely needs a manual securityContext review and possible hardening.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
