> ## 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 all noncompliant pods
           * 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
             | select($ok | not)
             | "ns=\($m.namespace) pod=\($m.name) container=\(.name)"
             ][]'
           ```

        2. Locate and edit the owning workload manifest(s)
           * For each noncompliant pod, find the controller and kind:
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.ownerReferences[0].kind}{" "}{.metadata.ownerReferences[0].name}{"\n"}'
           ```
           * Export the current manifest for that controller (example for a Deployment):
           ```bash theme={null}
           kubectl get deployment DEPLOYMENT_NAME -n NAMESPACE -o yaml > /tmp/deployment-DEPLOYMENT_NAME.yaml
           ```
           * Edit the file:
           ```bash theme={null}
           vi /tmp/deployment-DEPLOYMENT_NAME.yaml
           ```

        3. Add `securityContext.capabilities.drop: ["ALL"]` to each container
           * In the manifest’s pod template (`spec.template.spec.containers` and, if present, `spec.template.spec.initContainers`), ensure each container has:
           ```yaml theme={null}
           securityContext:
             capabilities:
               drop:
                 - "ALL"
               # add:
               #   - "NET_BIND_SERVICE"   # example; include only if strictly required
           ```
           * If `securityContext` or `capabilities` already exists, merge without removing other needed fields (e.g., `runAsNonRoot`, `readOnlyRootFilesystem`).

        4. Apply the updated manifest
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl apply -f /tmp/deployment-DEPLOYMENT_NAME.yaml
           ```
           * For other controller kinds (StatefulSet, DaemonSet, Job, CronJob), export, edit, and apply their manifests similarly.

        5. Handle pods without controllers (bare Pods)
           * If `ownerReferences` is empty, export and edit the Pod manifest directly:
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o yaml > /tmp/pod-POD_NAME.yaml
           vi /tmp/pod-POD_NAME.yaml
           ```
           * Add the same `securityContext.capabilities.drop: ["ALL"]` stanza to each container, then recreate the pod:
           ```bash theme={null}
           kubectl delete -n NAMESPACE 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)
             ] | if (length)==0 then "is_compliant=true" else .[] end'
           ```
           * The environment is compliant when the command outputs only `is_compliant=true`.
      </Accordion>

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

        1. Identify the noncompliant Pod and its owner (from the audit output). If the Pod is owned by a higher-level resource (Deployment, DaemonSet, Job, etc.), you must patch that owner; changes to a standalone Pod will be lost when it is recreated.

        2. Example: patch a Deployment to drop all capabilities for all app containers.

           ```bash theme={null}
           kubectl -n YOUR_NAMESPACE get deploy YOUR_DEPLOYMENT -o yaml > /tmp/deploy-capabilities.yaml
           ```

           Edit `/tmp/deploy-capabilities.yaml` so each container (and initContainer, if present) has:

           ```yaml theme={null}
           spec:
             template:
               spec:
                 containers:
                   - name: your-container
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
                     # if you must add specific capabilities back:
                     #   add:
                     #     - NET_BIND_SERVICE
                 initContainers:
                   - name: your-init-container
                     securityContext:
                       capabilities:
                         drop:
                           - "ALL"
           ```

           Then apply:

           ```bash theme={null}
           kubectl apply -f /tmp/deploy-capabilities.yaml
           ```

           This will trigger a rollout of the Deployment.

        3. Example: patch a standalone Pod (not recommended for controllers, but works for ad‑hoc Pods):

           ```bash theme={null}
           kubectl -n YOUR_NAMESPACE get pod YOUR_POD -o yaml > /tmp/pod-capabilities.yaml
           ```

           Edit each `containers` and `initContainers` entry as above, adding:

           ```yaml theme={null}
           securityContext:
             capabilities:
               drop:
                 - "ALL"
           ```

           Then delete and recreate the Pod from the edited manifest:

           ```bash theme={null}
           kubectl delete -n YOUR_NAMESPACE pod YOUR_POD
           kubectl apply -f /tmp/pod-capabilities.yaml
           ```

        4. Verification (same 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 `is_compliant=true` for all relevant containers.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Enforce: all containers drop ALL Linux capabilities (CBP C1.5)
        # Scope: EKS – Kubernetes API objects via kubectl
        # Requirements: kubectl, jq installed; current context points to target cluster.

        set -euo pipefail

        # Temporary workspace
        WORKDIR="$(mktemp -d)"
        trap 'rm -rf "$WORKDIR"' EXIT

        echo "Discovering non-compliant Pods..."
        # Capture non-compliant pod JSON (excluding control-plane/system namespaces per check)
        kubectl get pods --all-namespaces -o json > "${WORKDIR}/all-pods.json"

        # Function: list non-compliant pod namespaced-names
        list_non_compliant() {
          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 $cs
            | select(
                any($cs[];
                  .securityContext.capabilities.drop as $drop
                  | (($drop | index("ALL")) or ($drop | index("all"))) | not
                )
              )
            | "\($m.namespace) \($m.name)"
          ' "${WORKDIR}/all-pods.json" | sort -u
        }

        NON_COMPLIANT_LIST="$(list_non_compliant || true)"

        if [ -z "$NON_COMPLIANT_LIST" ]; then
          echo "No non-compliant Pods found. Cluster is already compliant."
          exit 0
        fi

        echo "Found non-compliant Pods:"
        echo "$NON_COMPLIANT_LIST"

        # Helper: ensure securityContext.capabilities.drop contains "ALL"
        patch_pod_json='
          # For each container-like list (containers, initContainers):
          def ensure_drop_all:
            if . == null then
              [] # no containers
            else
              map(
                . as $c
                | ($c.securityContext // {}) as $sc
                | ($sc.capabilities // {}) as $cap
                | ($cap.drop // []) as $drop
                | $c
                | .securityContext = $sc
                | .securityContext.capabilities = $cap
                | .securityContext.capabilities.drop =
                    (if ( ($drop | index("ALL")) or ($drop | index("all")) )
                     then $drop
                     else ($drop + ["ALL"] | unique)
                     end)
              )
            end;

          . as $pod
          | $pod
          | .spec.containers = (.spec.containers | ensure_drop_all)
          | .spec.initContainers = (.spec.initContainers | ensure_drop_all)
        '

        echo
        echo "Patching non-compliant Pods by updating their Pod specs."
        echo "NOTE: If Pods are controlled by Deployments/ReplicaSets/DaemonSets/etc.,"
        echo "      you MUST update the controller manifests instead; otherwise this"
        echo "      change will be overwritten on reschedule."

        # Attempt to patch each non-compliant Pod (best-effort).
        # This is idempotent: reruns will keep drop=["ALL", ...] unchanged.
        while read -r ns name; do
          [ -z "$ns" ] && continue
          echo "Processing Pod ${ns}/${name}..."

          kubectl get pod "${name}" -n "${ns}" -o json > "${WORKDIR}/${ns}-${name}.orig.json" || {
            echo "  Skipping ${ns}/${name}: unable to fetch (may have been deleted)."
            continue
          }

          jq "$patch_pod_json" "${WORKDIR}/${ns}-${name}.orig.json" > "${WORKDIR}/${ns}-${name}.patched.json"

          # Use server-side apply via "kubectl replace" (patching full Pod object)
          # This will restart the Pod.
          kubectl replace -n "${ns}" -f "${WORKDIR}/${ns}-${name}.patched.json" >/dev/null || {
            echo "  WARNING: Failed to replace Pod ${ns}/${name}. It may be controlled by a higher-level resource."
            echo "           Update the owning controller (Deployment/DaemonSet/StatefulSet/Job, etc.) manifest instead."
            continue
          }

          echo "  Patched ${ns}/${name}."
        done <<< "$NON_COMPLIANT_LIST"

        echo
        echo "Re-running compliance check for verification..."

        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
        ' > "${WORKDIR}/compliance-status.txt"

        cat "${WORKDIR}/compliance-status.txt"

        STATUS="$(cat "${WORKDIR}/compliance-status.txt")"
        if [ "$STATUS" != "is_compliant=true" ]; then
          echo
          echo "Some workloads remain non-compliant."
          echo "They are most likely managed by higher-level controllers."
          echo "Identify them with:"
          echo
          echo '  kubectl get pods --all-namespaces -o json | jq -r '\'''
          echo '    [ .items[]'
          echo '    | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)'
          echo '    | .metadata as $m'
          echo '    | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own'
          echo '    | ((.spec.containers // []) + (.spec.initContainers // []))[]'
          echo '    | (.securityContext.capabilities.drop // []) as $drop'
          echo '    | (($drop | index("ALL")) or ($drop | index("all"))) as $ok'
          echo '    | select($ok | not)'
          echo '    | "ns=\($m.namespace) pod=\($m.name) owner=\($own.kind)/\($m.namespace)/\($own.name)"'
          echo '    ][]'\'''
          echo
          echo "Then modify the corresponding Deployment/DaemonSet/StatefulSet/Job manifests"
          echo "to include securityContext.capabilities.drop: [\"ALL\"] for each container."
          exit 1
        fi

        echo "Cluster now compliant for this control."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
