> ## 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 Security Context To Your Pods And Containers

### More Info:

Apply Security Context to Your Pods and Containers

### Risk Level

Medium

### 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 pods and namespaces lacking securityContext**
           * On any machine with kubectl access:
             ```bash theme={null}
             kubectl get pods -A -o=jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext}{"\t"}{range .spec.containers[*]}{.name}{"="}{.securityContext}{";"}{end}{"\n"}{end}' \
               | column -t
             ```
           * Flag pods/containers where `.spec.securityContext` is `<nil>` and any container `.securityContext` is missing or empty for review.

        2. **Review current privilege-related settings on suspect workloads**
           * For each flagged pod, inspect full spec:
             ```bash theme={null}
             kubectl get pod <pod-name> -n <namespace> -o yaml
             ```
           * Look for: `securityContext.privileged`, `allowPrivilegeEscalation`, `runAsUser`, `runAsNonRoot`, `capabilities`, `hostNetwork`, `hostPID`, `hostIPC`, `hostPath`/other volume types, `fsGroup`, `supplementalGroups`.
           * Decide, with the application owner, whether the workload truly requires any privileged or host-level access.

        3. **Define or update a restrictive baseline policy per namespace**
           * For namespaces that should be locked down (everything except core infra like `kube-system`), create or adjust a baseline manifest reflecting the benchmark’s restrictive intent, for example (edit names/labels/namespaces as needed):
             ```bash theme={null}
             cat > restricted-baseline.yaml << 'EOF'
             apiVersion: v1
             kind: Namespace
             metadata:
               name: secure-apps
               labels:
                 pod-security.kubernetes.io/enforce: restricted
                 pod-security.kubernetes.io/audit: restricted
                 pod-security.kubernetes.io/warn: restricted
             EOF

             kubectl apply -f restricted-baseline.yaml
             ```
           * For existing namespaces, apply labels directly:
             ```bash theme={null}
             kubectl label namespace <namespace> \
               pod-security.kubernetes.io/enforce=restricted \
               --overwrite
             ```

        4. **Harden pod specs to meet the restrictive intent**
           * For each non-privileged workload, update its Deployment/StatefulSet/Job manifest (never edit bare pods that are not managed by a controller) to add container-level securityContext such as:
             ```yaml theme={null}
             securityContext:
               allowPrivilegeEscalation: false
               privileged: false
               runAsNonRoot: true
               runAsUser: 1000
               readOnlyRootFilesystem: true
               capabilities:
                 drop:
                   - ALL
             ```
           * Apply updated manifests from your IaC/manifest repo using kubectl from any machine with access:
             ```bash theme={null}
             kubectl apply -f <updated-manifest>.yaml
             ```

        5. **Handle necessary exceptions in tightly scoped namespaces**
           * For workloads that require broader access (e.g., logging agents, CNI, storage drivers), ensure they are:
             * Deployed into dedicated namespaces (e.g., `kube-system` or a specific `infra-logging` namespace).
             * Bound to specific service accounts with RBAC tailored to their needs:
               ```bash theme={null}
               kubectl get rolebindings,clusterrolebindings -A \
                 -o wide | grep -E '<service-account-name>|<namespace>'
               ```
           * Loosen securityContext **only** for these pods and document the justification per workload.

        6. **Re-verify posture after changes**
           * Confirm that most pods now carry non-empty securityContext fields and that no unexpected privileged/host-level settings exist:
             ```bash theme={null}
             kubectl get pods -A -o=jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.name}{"="}{.securityContext}{";"}{end}{"\n"}{end}' \
               | column -t
             ```
           * Spot-check a sample of critical namespaces (`default`, app namespaces) with `kubectl get pod <pod> -n <ns> -o yaml` to ensure configurations align with your restrictive baseline and the benchmark’s intent.
      </Accordion>

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

        Run these from any machine with `kubectl` access.

        #### 1. List pods that declare *no* securityContext at all

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | select((.spec.securityContext // {}) == {} and
                     ([(.spec.containers[]?.securityContext),
                       (.spec.initContainers[]?.securityContext)] | map(select(. != null)) | length) == 0)
            | [.metadata.namespace, .metadata.name]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** Any application namespace (e.g. not `kube-system`, `kube-public`, `kube-node-lease`) showing pods here means those pods have no explicit security context and should be reviewed and likely hardened.

        ***

        #### 2. Find containers that can run as root or with no user restriction

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | ($pod.spec.containers + ($pod.spec.initContainers // []))[]
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                c: .name,
                podRunAsNonRoot: $pod.spec.securityContext.runAsNonRoot,
                podRunAsUser: $pod.spec.securityContext.runAsUser,
                cRunAsNonRoot: .securityContext.runAsNonRoot,
                cRunAsUser: .securityContext.runAsUser
              }
            | select(
                # flag if explicitly running as 0
                ( .podRunAsUser == 0 or .cRunAsUser == 0 )
                or
                # or neither pod nor container enforce non-root
                ( (.podRunAsNonRoot // false) == false
                  and (.cRunAsNonRoot // false) == false
                  and (.podRunAsUser // .cRunAsUser // null) == null
                )
              )
            | [.ns, .pod, .c,
               "podRunAsNonRoot=" + ( .podRunAsNonRoot|tostring ),
               "cRunAsNonRoot=" + ( .cRunAsNonRoot|tostring ),
               "podRunAsUser=" + ( .podRunAsUser|tostring ),
               "cRunAsUser=" + ( .cRunAsUser|tostring )
              ]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** Application workloads here are effectively allowed to run as root (UID 0) or have no restriction to non‑root. Compare against your policy; in line with the benchmark, you typically want `runAsNonRoot: true` or a non‑0 `runAsUser`.

        ***

        #### 3. Find containers allowed to escalate privileges

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | ($pod.spec.containers + ($pod.spec.initContainers // []))[]
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                c: .name,
                podAPE: $pod.spec.securityContext.allowPrivilegeEscalation,
                cAPE: .securityContext.allowPrivilegeEscalation
              }
            | select(
                # container explicitly allows escalation, or inherits no restriction
                ( .cAPE == true )
                or
                ( .cAPE == null and (.podAPE == null or .podAPE == true) )
              )
            | [.ns, .pod, .c,
               "podAllowPrivilegeEscalation=" + ( .podAPE|tostring ),
               "cAllowPrivilegeEscalation=" + ( .cAPE|tostring )
              ]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** Non‑system workloads in this list allow privilege escalation. The benchmark recommends `allowPrivilegeEscalation: false` as a default.

        ***

        #### 4. Find privileged containers and host‑level access

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | ($pod.spec.containers + ($pod.spec.initContainers // []))[]
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                c: .name,
                privileged: .securityContext.privileged,
                hostPID: $pod.spec.hostPID,
                hostIPC: $pod.spec.hostIPC,
                hostNetwork: $pod.spec.hostNetwork,
                capAdd: (.securityContext.capabilities.add // [])
              }
            | select(
                .privileged == true or
                .hostPID == true or
                .hostIPC == true or
                .hostNetwork == true or
                (.capAdd | length > 0)
              )
            | [.ns, .pod, .c,
               "privileged=" + (.privileged|tostring),
               "hostPID=" + (.hostPID|tostring),
               "hostIPC=" + (.hostIPC|tostring),
               "hostNetwork=" + (.hostNetwork|tostring),
               "capAdd=" + ( (.capAdd|join(",")) )
              ]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** Any application pod here has elevated privileges (privileged, extra capabilities, or host namespace access). Only tightly‑controlled system or daemon pods should appear, and even those should be explicitly justified.

        ***

        #### 5. Identify containers without restricted capabilities / read‑only root FS

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | ($pod.spec.containers + ($pod.spec.initContainers // []))[]
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                c: .name,
                drop: (.securityContext.capabilities.drop // []),
                rofs: .securityContext.readOnlyRootFilesystem
              }
            | select(
                # missing drop ALL or not read-only root FS
                ( (.drop | index("ALL")) == null or (.rofs // false) == false )
              )
            | [.ns, .pod, .c,
               "drop=" + ( (.drop|join(",")) ),
               "readOnlyRootFilesystem=" + (.rofs|tostring)
              ]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** For most workloads aligned with the sample restrictive policy, you expect `drop: ["ALL"]` and `readOnlyRootFilesystem: true` (or a conscious exception). Entries here are candidates for hardening.

        ***

        #### 6. Review volume types that may bypass restrictions

        ```sh theme={null}
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | {
                ns: .metadata.namespace,
                pod: .metadata.name,
                vols: [.spec.volumes[]? |
                  if .hostPath then "hostPath"
                  elif .nfs then "nfs"
                  elif .glusterfs then "glusterfs"
                  elif .cephfs then "cephfs"
                  elif .iscsi then "iscsi"
                  elif .fc then "fc"
                  elif .cinder then "cinder"
                  elif .gcePersistentDisk then "gcePersistentDisk"
                  elif .awsElasticBlockStore then "awsElasticBlockStore"
                  elif .azureDisk or .azureFile then "azure"
                  else ""
                  end
                ] | unique | map(select(. != "")) }
            | select(.vols | length > 0)
            | [.ns, .pod, "volumes=" + (.vols|join(","))]
            | @tsv' \
          | column -t
        ```

        **Problem indication:** While persistent volumes are generally allowed, widespread `hostPath` or other direct node‑level mounts in application namespaces often signal pods that should be tightly reviewed and potentially restricted or moved under a privileged policy only where strictly necessary.

        ***

        #### 7. Check for Pod-level securityContext defaults

        ```sh theme={null}
        kubectl get pods --all-namespaces -o yaml \
          | sed -n '1,120p'
        ```

        **Problem indication:** When inspecting individual pod specs, look for:

        * `securityContext` at pod and container level missing or overly permissive.
        * Absence of fields that align with your restrictive baseline, such as:
          * `runAsNonRoot: true` or non‑0 `runAsUser`
          * `allowPrivilegeEscalation: false`
          * `readOnlyRootFilesystem: true`
          * `capabilities: { drop: ["ALL"] }`
          * No `privileged: true`, no host namespaces unless strictly required.

        Use the above commands to shortlist pods, then inspect those pods’ full specs with:

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

        A human must decide which pods are legitimate exceptions (e.g. certain `kube-system` components, logging agents) and where manifests or higher‑level policy (PSPs, Pod Security admission, or other policy engines) should be tightened.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report pods/containers without explicit securityContext (or with risky settings)
        # Run on: any machine with kubectl access & current context set

        set -euo pipefail

        # 1) High‑level summary of securityContext usage per pod
        echo "=== Pod-level securityContext summary (per namespace/pod) ==="
        kubectl get pods -A -o json \
        | jq -r '
          .items[]
          | {
              ns: .metadata.namespace,
              pod: .metadata.name,
              podSc: ( .spec.securityContext // {} ),
              containers: [ .spec.containers[] | {name, sc: (.securityContext // {})} ],
              initContainers: ( [ (.spec.initContainers // [])[] | {name, sc: (.securityContext // {})} ] )
            }
          | . as $pod
          | $pod
          | [
              .ns,
              .pod,
              (if (.podSc | length) > 0 then "pod-sc:yes" else "pod-sc:NO" end),
              (if ( [ .containers[] | select((.sc | length) > 0)] | length ) > 0
                 then "ctr-sc:some"
                 else "ctr-sc:NONE"
               end),
              (if ( [ .initContainers[] | select((.sc | length) > 0)] | length ) > 0
                 then "init-sc:some"
                 else (if (.initContainers | length) > 0 then "init-sc:NONE" else "init-sc:none-present" end)
               end)
            ]
          | @tsv
        ' \
        | column -t

        cat <<'EOF'

        Interpretation:
        - pod-sc:NO           => Pod has no pod-level securityContext.
        - ctr-sc:NONE         => No regular container in the pod has a container-level securityContext.
        - init-sc:NONE        => Init containers present but none have securityContext.
        These lines are candidates for manual review to ensure non-root, no privilege escalation, etc.
        EOF

        # 2) Detailed list of containers with clearly risky or missing fields
        echo
        echo "=== Containers with missing or risky securityContext settings ==="
        kubectl get pods -A -o json \
        | jq -r '
          .items[]
          | .metadata.namespace as $ns
          | .metadata.name as $pod
          | (
              (.spec.containers // []) + (.spec.initContainers // [])
            )[]
          | {
              ns: $ns,
              pod: $pod,
              ctype: (if (.name as $n | ( . // {} ) | has("envFrom")) then "container" else "container" end), # label as container
              cname: .name,
              sc: (.securityContext // {})
            }
          | . as $ct
          | {
              ns: .ns,
              pod: .pod,
              cname: .cname,
              runAsNonRoot: (.sc.runAsNonRoot // "UNSET"),
              runAsUser: (.sc.runAsUser // "UNSET"),
              allowPrivilegeEscalation: (.sc.allowPrivilegeEscalation // "UNSET"),
              privileged: (.sc.privileged // "UNSET"),
              readOnlyRootFilesystem: (.sc.readOnlyRootFilesystem // "UNSET"),
              capabilities_add: (.sc.capabilities.add // []),
              capabilities_drop: (.sc.capabilities.drop // [])
            }
          | select(
              # Highlight if *any* of these indicate risk or are unset
              (.runAsNonRoot == "UNSET") or
              (.runAsNonRoot == false) or
              (.allowPrivilegeEscalation == "UNSET") or
              (.allowPrivilegeEscalation == true) or
              (.privileged == true) or
              (.privileged == "UNSET") or
              (.readOnlyRootFilesystem == "UNSET") or
              (.capabilities_add | length > 0) or
              (.capabilities_drop | index("ALL") | not)
            )
          | [
              .ns,
              .pod,
              .cname,
              "runAsNonRoot=" + ( .runAsNonRoot | tostring ),
              "runAsUser=" + ( .runAsUser | tostring ),
              "allowPrivilegeEscalation=" + ( .allowPrivilegeEscalation | tostring ),
              "privileged=" + ( .privileged | tostring ),
              "readOnlyRootFilesystem=" + ( .readOnlyRootFilesystem | tostring ),
              "capAdd=" + ( .capabilities_add | join(",") ),
              "capDrop=" + ( .capabilities_drop | join(",") )
            ]
          | @tsv
        ' \
        | column -t || true

        cat <<'EOF'

        Interpretation (problem indicators):
        - runAsNonRoot=UNSET or false
          => Container may run as root; benchmark expects non-root (and ideally Required via policy).
        - runAsUser=UNSET
          => No explicit user; often defaults to root.
        - allowPrivilegeEscalation=UNSET or true
          => Containers can escalate privileges; benchmark recommends false.
        - privileged=true or privileged=UNSET
          => Privileged container or not explicitly disabled; should be false for general workloads.
        - readOnlyRootFilesystem=UNSET
          => Root FS not explicitly read-only; consider setting to true where possible.
        - capAdd non-empty OR capDrop missing ALL
          => Extra Linux capabilities retained/added; benchmark example drops ALL by default.

        These pods/containers should be reviewed. Decide which ones truly need elevated permissions
        (e.g., logging/monitoring agents) and tighten securityContext everywhere else.

        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/concepts/policy/security-context/](https://kubernetes.io/docs/concepts/policy/security-context/)
