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

# Containers Should Drop All Linux Capabilities

### More Info:

Verifies every container drops ALL capabilities and adds back only what it needs. Excess capabilities expand the attack surface of a compromised container.

### Risk Level

High

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. Identify noncompliant pods and their owning workloads (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.capabilities.drop // []) as $drop
             | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
             | select($ok | not)
             | "ns=\($m.namespace) pod=\($m.name) container=\(.name)"
               + (if $own == null then "" else " ownerKind=\($own.kind) ownerName=\($own.name)" end)
             ][]'
           ```

        2. For each listed pod, edit the owning workload manifest (Deployment, StatefulSet, DaemonSet, Job, CronJob, or the Pod itself) to drop all capabilities (run on any machine with kubectl access). Example for a Deployment:
           ```bash theme={null}
           kubectl -n <namespace> edit deployment <deployment-name>
           ```
           Under each `spec.template.spec.containers[]` (and `initContainers[]` if present), add or modify:
           ```yaml theme={null}
           securityContext:
             capabilities:
               drop:
                 - "ALL"
               # add:
               #   - "NET_BIND_SERVICE"   # example only if strictly required
           ```

        3. If the pod is not controlled by a higher-level workload (no ownerReferences), edit the Pod spec directly and reapply it as a new manifest (pods cannot be updated in place for some fields). Export the pod spec, clean it, and save as a manifest (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <namespace> get pod <pod-name> -o yaml > /tmp/<pod-name>.yaml
           ```
           Edit `/tmp/<pod-name>.yaml`:
           * Remove `status:` section.
           * Remove fields under `metadata:` such as `uid`, `resourceVersion`, `managedFields`, `creationTimestamp`, and `ownerReferences`.
           * Under each container and initContainer, ensure:
             ```yaml theme={null}
             securityContext:
               capabilities:
                 drop:
                   - "ALL"
                 # add:
                 #   - "<ONLY_WHAT_IS_NEEDED>"
             ```

        4. Apply the updated standalone Pod manifest (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl apply -f /tmp/<pod-name>.yaml
           ```

        5. Confirm updated workloads have rolled out successfully (run on any machine with kubectl access), for example for a Deployment:
           ```bash theme={null}
           kubectl -n <namespace> rollout status deployment/<deployment-name>
           ```

        6. Verify compliance across the cluster (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.capabilities.drop // []) as $drop
             | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " container=\(.name) image=\(.image)"
               + " capabilitiesDrop=\(if ($drop | length) == 0 then "none" else ($drop | join("+")) end)"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
           Ensure that the output is either a single line `is_compliant=true` or that every listed container has `is_compliant=true`.
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with kubectl access:

        1. Identify the non‑compliant Pod and its controller
           ```bash theme={null}
           kubectl get pods -A
           kubectl get pod <POD_NAME> -n <NAMESPACE> -o yaml | yq '.metadata.ownerReferences'
           ```
           If the Pod is owned by a controller (Deployment, StatefulSet, DaemonSet, Job, CronJob, etc.), you must edit the controller, not the Pod, or the change will be overwritten.

        2. Edit the Pod spec (ephemeral / stand‑alone Pod only)\
           For a Pod not managed by a controller:
           ```bash theme={null}
           kubectl edit pod <POD_NAME> -n <NAMESPACE>
           ```
           Under each container (and initContainer if present), add:
           ```yaml theme={null}
           spec:
             containers:
               - name: <container-name>
                 securityContext:
                   capabilities:
                     drop:
                       - "ALL"
                     # add:
                     #   - "NET_BIND_SERVICE"   # example only; include only what is required
             initContainers:
               - name: <init-container-name>
                 securityContext:
                   capabilities:
                     drop:
                       - "ALL"
           ```

        3. Edit the owning controller (preferred, declarative)

           Deployment example:

           ```bash theme={null}
           kubectl edit deployment <DEPLOYMENT_NAME> -n <NAMESPACE>
           ```

           Add the same block under every container and initContainer:

           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: <container-name>
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
                         # add:
                         #   - "NET_BIND_SERVICE"
                 initContainers:
                   - name: <init-container-name>
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
           ```

           For other controllers, replace `deployment` with `statefulset`, `daemonset`, `job`, or `cronjob` and edit `.spec.template.spec` similarly.

           If you manage manifests declaratively, update your YAML files with the same `securityContext.capabilities.drop: ["ALL"]` blocks and apply:

           ```bash theme={null}
           kubectl apply -f <your-manifest>.yaml
           ```

        4. Verification

           Re‑run the benchmark audit command from any machine with kubectl access:

           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | ((.spec.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.capabilities.drop // []) as $drop
             | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " container=\(.name) image=\(.image)"
               + " capabilitiesDrop=\(if ($drop | length) == 0 then "none" else ($drop | join("+")) end)"
               + " is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```

           Confirm that all listed containers now show `capabilitiesDrop=ALL` and `is_compliant=true` (or that the output is just `is_compliant=true`).
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # Automation for: Containers Should Drop All Linux Capabilities (CBP C1.5)
        # Scope: Oracle OKE, all namespaces except: kube-system, kube-public, kube-node-lease
        # Runs on: any machine with kubectl access and jq installed

        if ! command -v kubectl >/dev/null 2>&1; then
          echo "kubectl not found in PATH" >&2
          exit 1
        fi

        if ! command -v jq >/dev/null 2>&1; then
          echo "jq not found in PATH" >&2
          exit 1
        fi

        WORKDIR="$(pwd)/capability-fix-$(date +%s)"
        mkdir -p "${WORKDIR}"

        echo "Discovering non-compliant pods..."
        kubectl get pods --all-namespaces -o json | jq -r '
          .items[]
          | select(.metadata.namespace as $n
                   | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | select((
              ((.spec.containers // []) + (.spec.initContainers // []))[]
              | (.securityContext.capabilities.drop // []) as $drop
              | (($drop | index("ALL")) or ($drop | index("all"))) == false
            ) // false)
          | [.metadata.namespace, .metadata.name]
          | @tsv' | sort -u > "${WORKDIR}/non_compliant_pods.tsv" || true

        if [[ ! -s "${WORKDIR}/non_compliant_pods.tsv" ]]; then
          echo "No non-compliant pods found. Nothing to change."
        else
          echo "Found non-compliant pods:"
          cat "${WORKDIR}/non_compliant_pods.tsv"
        fi

        fix_pod() {
          local ns="$1"
          local pod="$2"

          echo "Processing Pod ${ns}/${pod}..."

          # Determine owner (Deployment/StatefulSet/DaemonSet/Job/CronJob) if any
          owner_json="$(kubectl get pod "${pod}" -n "${ns}" -o jsonpath='{.metadata.ownerReferences}' 2>/dev/null || echo "")"
          owner_kind=""
          owner_name=""
          if [[ -n "${owner_json}" && "${owner_json}" != "null" ]]; then
            owner_kind="$(kubectl get pod "${pod}" -n "${ns}" -o jsonpath='{.metadata.ownerReferences[0].kind}' || true)"
            owner_name="$(kubectl get pod "${pod}" -n "${ns}" -o jsonpath='{.metadata.ownerReferences[0].name}' || true)"
          fi

          # Decide target resource: prefer owner controller if present
          target_kind="Pod"
          target_name="${pod}"
          if [[ -n "${owner_kind}" && -n "${owner_name}" ]]; then
            target_kind="${owner_kind}"
            target_name="${owner_name}"
          fi

          # Get raw YAML for target
          yaml_path="${WORKDIR}/${ns}-${target_kind,,}-${target_name}.yaml"
          echo "  Fetching ${target_kind} ${ns}/${target_name}..."
          if ! kubectl get "${target_kind,,}" "${target_name}" -n "${ns}" -o yaml > "${yaml_path}"; then
            echo "  WARNING: Failed to fetch ${target_kind} ${ns}/${target_name}, skipping." >&2
            return
          fi

          # Create a patched copy
          patched_path="${yaml_path%.yaml}.patched.yaml"
          cp "${yaml_path}" "${patched_path}"

          # Use yq if available for safer YAML edits; otherwise use jq on JSON
          if command -v yq >/dev/null 2>&1; then
            echo "  Patching capabilities with yq..."
            yq '
              (.. | select(has("containers")) ) as $p
              | . as $root
              | ($root | path($p)) as $path
              | ($root | getpath($path)) as $obj
              | ($obj.containers // []) |=
                  (map(
                    .securityContext.capabilities.drop =
                      ( ((.securityContext.capabilities.drop // [])
                          | map(select(. != "all" and . != "ALL"))
                          + ["ALL"]) | unique )
                  ))
              | ($obj.initContainers // []) |=
                  (map(
                    .securityContext.capabilities.drop =
                      ( ((.securityContext.capabilities.drop // [])
                          | map(select(. != "all" and . != "ALL"))
                          + ["ALL"]) | unique )
                  ))
              ' "${yaml_path}" > "${patched_path}.tmp" && mv "${patched_path}.tmp" "${patched_path}"
          else
            echo "  yq not found; patching via JSON round-trip with jq..."
            json_path="${yaml_path%.yaml}.json"
            json_patched_path="${yaml_path%.yaml}.patched.json"
            kubectl get "${target_kind,,}" "${target_name}" -n "${ns}" -o json > "${json_path}"
            jq '
              def ensure_drop_all:
                .securityContext |= ( . // {} )
                | .securityContext.capabilities |= ( . // {} )
                | .securityContext.capabilities.drop |= (
                    ( . // [] )
                    | map(select(. != "all" and . != "ALL"))
                    | . + ["ALL"]
                    | unique
                  );
              if .spec.template? then
                .spec.template.spec.containers |= (map(ensure_drop_all)) |
                .spec.template.spec.initContainers |= (map(ensure_drop_all) // .)
              else
                .spec.containers |= (map(ensure_drop_all)) |
                .spec.initContainers |= (map(ensure_drop_all) // .)
              end
              ' "${json_path}" > "${json_patched_path}"
            # Convert back to YAML with kubectl
            kubectl apply -f "${json_patched_path}" --dry-run=client -o yaml > "${patched_path}"
          fi

          echo "  Applying patched manifest for ${target_kind} ${ns}/${target_name}..."
          kubectl apply -f "${patched_path}"

          echo "  Waiting for updated pods from ${target_kind} ${ns}/${target_name} to be Ready..."
          case "${target_kind}" in
            Deployment|StatefulSet|DaemonSet)
              kubectl rollout status "${target_kind,,}/${target_name}" -n "${ns}" --timeout=5m || \
                echo "  WARNING: rollout status for ${target_kind} ${ns}/${target_name} did not complete in time." >&2
              ;;
            CronJob)
              echo "  NOTE: CronJob pods will reflect changes on next scheduled run."
              ;;
            Job|Pod)
              kubectl get pod -n "${ns}" "${pod}" >/dev/null 2>&1 || true
              ;;
          esac
        }

        if [[ -s "${WORKDIR}/non_compliant_pods.tsv" ]]; then
          while IFS=$'\t' read -r ns pod; do
            fix_pod "${ns}" "${pod}"
          done < "${WORKDIR}/non_compliant_pods.tsv"
        fi

        echo
        echo "Verifying compliance after remediation..."
        kubectl get pods --all-namespaces -o json | jq -r '
          [ .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | ((.spec.containers // []) + (.spec.initContainers // []))[]
          | (.securityContext.capabilities.drop // []) as $drop
          | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
          | select($ok | not)
          ] | if length == 0 then "is_compliant=true" else "is_compliant=false" end'
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
