> ## 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 offending pods and containers (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.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.capabilities.drop // []) as $drop
             | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
             | select($ok | not)
             | "\($m.namespace) \($m.name) \(.name)"
             ][]'
           ```
           Each line is: `NAMESPACE POD_NAME CONTAINER_NAME`. Use it as input for the next steps.

        2. For each non-compliant workload managed by a higher-level controller (Deployment, StatefulSet, DaemonSet, Job, CronJob), edit the controller manifest (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <NAMESPACE> get deployment <DEPLOYMENT_NAME> -o yaml > /tmp/deploy-<DEPLOYMENT_NAME>.yaml
           ```
           Or replace `deployment` with `statefulset`, `daemonset`, `job`, or `cronjob` as appropriate.

        3. In the saved manifest file, add a `securityContext.capabilities.drop: ["ALL"]` to every container (including `initContainers`) under `spec.template.spec`. For example:
           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: app
                     image: your-image
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
                         # add back only what is strictly needed, e.g.:
                         # add:
                         #   - NET_BIND_SERVICE
                 initContainers:
                   - name: init
                     image: your-init-image
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
           ```
           If specific Linux capabilities are required, list them under `add:` explicitly; otherwise omit `add:`.

        4. Apply the updated manifest (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl apply -f /tmp/deploy-<DEPLOYMENT_NAME>.yaml
           ```
           Repeat Steps 2–4 for each affected controller. This will cause controlled rollouts of new pods.

        5. For stand-alone Pods (not owned by a controller), recreate them with the proper securityContext (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <NAMESPACE> get pod <POD_NAME> -o yaml > /tmp/pod-<POD_NAME>.yaml
           ```
           Edit `/tmp/pod-<POD_NAME>.yaml`:
           * Remove `metadata.uid`, `metadata.resourceVersion`, `metadata.creationTimestamp`, `metadata.managedFields`, `status`, and any `ownerReferences`.
           * Under `spec.containers[]` and `spec.initContainers[]` add:
             ```yaml theme={null}
             securityContext:
               capabilities:
                 drop:
                   - "ALL"
                 # add:
                 #   - <ONLY-REQUIRED-CAPABILITY>
             ```
           Then delete and recreate:
           ```bash theme={null}
           kubectl -n <NAMESPACE> delete pod <POD_NAME>
           kubectl apply -f /tmp/pod-<POD_NAME>.yaml
           ```

        6. Verify compliance (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.containers // []) + (.spec.initContainers // []))[]
             | (.securityContext.capabilities.drop // []) as $drop
             | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
             | select($ok | not)
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else "is_compliant=false" end'
           ```
           The output must be `is_compliant=true`.
      </Accordion>

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

        1. Identify the noncompliant pod and its owning controller (from the audit output’s `owner=` field). For example, if you see:
           ```text theme={null}
           owner=Deployment/default/my-app/...
           ```
           then you must edit the `Deployment/my-app` in the `default` namespace (never edit only the live Pod).

        2. Edit the controller and add the capabilities drop to every container (including initContainers if present). Example for a Deployment:

           ```bash theme={null}
           kubectl -n default edit deployment my-app
           ```

           In the opened manifest, under each container, add a `securityContext.capabilities.drop: ["ALL"]`. If the container truly needs a specific capability, add it back under `add`.

           Example `spec.template.spec` snippet:

           ```yaml theme={null}
           spec:
             template:
               spec:
                 securityContext:
                   runAsNonRoot: true
                 containers:
                   - name: app
                     image: nginx:1.27
                     securityContext:
                       allowPrivilegeEscalation: false
                       capabilities:
                         drop:
                           - "ALL"
                         add:
                           - "NET_BIND_SERVICE"   # only if strictly required
                     # ...
                 initContainers:
                   - name: init-job
                     image: busybox:1.36
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
                     # add: [] or omit unless a specific capability is needed
           ```

           Save and exit; Kubernetes will roll out updated Pods with the new securityContext.

        3. For objects not managed by higher-level controllers (for example, a standalone Pod manifest in Git), update the source manifest similarly, then apply:

           ```bash theme={null}
           kubectl apply -f /absolute/path/to/pod-or-controller.yaml
           ```

        4. Verification (from any machine with kubectl):

           ```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 // []) | map(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) container=\(.name) is_compliant=\(if $ok then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```

           Confirm all listed `is_compliant=` values are `true` (or that no rows are output, meaning all applicable pods comply).
      </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)
        # 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

        TMPDIR="$(mktemp -d)"
        trap 'rm -rf "$TMPDIR"' EXIT

        echo "Identifying non-compliant Pods (excluding kube-system, kube-public, kube-node-lease)..."

        # Get namespaced Pod list that is non-compliant (no ALL/all in capabilities.drop)
        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 // [])) as $allc
          | [ $allc[]
              | (.securityContext.capabilities.drop // []) as $drop
              | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
              | select($ok | not)
            ] as $badContainers
          | select(($badContainers | length) > 0)
          | "\($m.namespace) \($m.name)"
        ' | sort -u > "$TMPDIR/non_compliant_pods.txt"

        if ! [[ -s "$TMPDIR/non_compliant_pods.txt" ]]; then
          echo "All Pods already drop ALL capabilities (excluding system namespaces). Nothing to do."
        else
          echo "Non-compliant Pods detected:"
          cat "$TMPDIR/non_compliant_pods.txt"
        fi

        # Function: patch a single Pod manifest yaml to ensure ALL is in drop list for all containers/initContainers
        patch_pod_yaml() {
          local in_yaml=$1 out_yaml=$2

          # jq-based transformation via yq (if available) or kubectl-kustomize-style is complex.
          # Use yq v4 if present for robust YAML editing.
          if command -v yq >/dev/null 2>&1; then
            yq '
              .spec |= (
                if has("containers") then
                  .containers |= map(
                    .securityContext.capabilities.drop |= (
                      (//[]) as $d
                      | if ($d | index("ALL")) != null then $d else ($d + ["ALL"]) end
                    )
                  )
                else . end
              )
              | .spec |= (
                if has("initContainers") then
                  .initContainers |= map(
                    .securityContext.capabilities.drop |= (
                      (//[]) as $d
                      | if ($d | index("ALL")) != null then $d else ($d + ["ALL"]) end
                    )
                  )
                else . end
              )
            ' "$in_yaml" > "$out_yaml"
            return 0
          fi

          # Fallback: server-side strategic merge patch using kubectl (no local YAML change)
          # This function is not used when yq is missing.
          return 1
        }

        if [[ -s "$TMPDIR/non_compliant_pods.txt" ]]; then
          echo
          echo "Patching non-compliant Pods (type: Pod only; higher-level controllers must be fixed via their manifests separately)."

          while read -r NS NAME; do
            [[ -z "$NS" || -z "$NAME" ]] && continue

            echo "Processing Pod: $NS/$NAME"

            POD_JSON="$(kubectl get pod "$NAME" -n "$NS" -o json)"

            # Build a strategic merge patch that adds "ALL" to drop for each container/initContainer
            PATCH="$(echo "$POD_JSON" | jq '
              {
                "spec": {
                  "containers": ( (.spec.containers // []) | map(
                    {
                      "name": .name,
                      "securityContext": {
                        "capabilities": {
                          "drop": (
                            (
                              ((.securityContext.capabilities.drop // []) | map(
                                if . == "all" then "ALL" else . end
                              )) as $d
                              | if ($d | index("ALL")) != null then $d else ($d + ["ALL"]) end
                            )
                          )
                        }
                      }
                    }
                  )),
                  "initContainers": ( (.spec.initContainers // []) | map(
                    {
                      "name": .name,
                      "securityContext": {
                        "capabilities": {
                          "drop": (
                            (
                              ((.securityContext.capabilities.drop // []) | map(
                                if . == "all" then "ALL" else . end
                              )) as $d
                              | if ($d | index("ALL")) != null then $d else ($d + ["ALL"]) end
                            )
                          )
                        }
                      }
                    }
                  ))
                }
              }
            ')"

            echo "$PATCH" > "$TMPDIR/patch-$NS-$NAME.json"

            kubectl patch pod "$NAME" -n "$NS" --type merge -p "$(cat "$TMPDIR/patch-$NS-$NAME.json")" >/dev/null

          done < "$TMPDIR/non_compliant_pods.txt"
        fi

        echo
        echo "Re-running compliance audit to verify result..."

        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)
          ] as $rows
          | if ($rows | length) == 0 then
              "All non-system Pods now have securityContext.capabilities.drop including ALL (is_compliant=true)"
            else
              "Some Pods are still non-compliant (is_compliant=false). Review owning controllers and their manifests."
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
