> ## 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 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.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. For a noncompliant Pod created directly (not via Deployment/ReplicaSet/etc.), edit the Pod spec (any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <namespace> get pod <pod-name> -o yaml > /tmp/pod-fixed.yaml
           ```
           In `/tmp/pod-fixed.yaml`, under each `.spec.containers[].securityContext` and `.spec.initContainers[].securityContext`:
           ```yaml theme={null}
           securityContext:
             capabilities:
               drop:
                 - "ALL"
               # add back only what is required, for example:
               # add:
               #   - "NET_BIND_SERVICE"
           ```
           Then apply and recreate (Pods cannot be updated in place for some fields, so delete and recreate if needed):
           ```bash theme={null}
           kubectl -n <namespace> delete pod <pod-name>
           kubectl -n <namespace> apply -f /tmp/pod-fixed.yaml
           ```

        3. For Pods managed by a higher-level controller (e.g., Deployment, StatefulSet, DaemonSet), find the owning resource (any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <namespace> get pod <pod-name> -o jsonpath='{.metadata.ownerReferences[0].kind}{" "}{.metadata.ownerReferences[0].name}{"\n"}'
           ```
           Then fetch the controller manifest:
           ```bash theme={null}
           kubectl -n <namespace> get <Kind-lowercased> <owner-name> -o yaml > /tmp/owner-fixed.yaml
           ```

        4. Edit the controller manifest to drop all capabilities (any machine with kubectl access). In `/tmp/owner-fixed.yaml`, under each container and initContainer template path like:

           * Deployments: `.spec.template.spec.containers[]` and `.spec.template.spec.initContainers[]`
           * StatefulSets/DaemonSets/ReplicaSets: same template path

           Add or modify:

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

           Save the file.

        5. Apply the updated controller spec and wait for Pods to be recreated (any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <namespace> apply -f /tmp/owner-fixed.yaml
           kubectl -n <namespace> rollout status deployment/<owner-name>    # for a Deployment
           # or:
           # kubectl -n <namespace> rollout status daemonset/<owner-name>
           # kubectl -n <namespace> rollout status statefulset/<owner-name>
           ```

        6. Verify compliance (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'
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Identify non-compliant pods
        # Run on: any machine with kubectl access
        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' \
        | grep 'is_compliant=false' || echo "All non-system pods compliant"

        # 2) Export the owning workload manifest (example: Deployment)
        # Replace <namespace> and <deployment-name> with real values from step 1
        # Run on: any machine with kubectl access
        kubectl -n <namespace> get deploy <deployment-name> -o yaml > /tmp/deploy-<deployment-name>.yaml

        # 3) Edit the manifest to drop ALL capabilities for every container
        # Open /tmp/deploy-<deployment-name>.yaml in an editor and, for each container
        # under spec.template.spec.containers and spec.template.spec.initContainers,
        # add or modify securityContext like:

        # ...
        # spec:
        #   template:
        #     spec:
        #       containers:
        #         - name: app
        #           image: your-image:tag
        #           securityContext:
        #             capabilities:
        #               drop:
        #                 - "ALL"
        #             # OPTIONAL: if the workload truly needs specific capabilities, add them back explicitly:
        #             #   add:
        #             #     - "NET_BIND_SERVICE"
        #           # other fields...
        #       initContainers:
        #         - name: init
        #           image: your-init-image:tag
        #           securityContext:
        #             capabilities:
        #               drop:
        #                 - "ALL"
        #             # add: []  # or specific capabilities if absolutely required

        # 4) Apply the updated manifest
        # Run on: any machine with kubectl access
        kubectl apply -f /tmp/deploy-<deployment-name>.yaml

        # 5) Repeat steps 2–4 for each non-compliant owning object
        # (e.g., Deployment, DaemonSet, StatefulSet, Job, CronJob, or standalone Pod)

        # 6) Verification: re-run the benchmark audit command
        # Run on: any machine with kubectl access
        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'
        ```
      </Accordion>

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

        # Automation for CBP C1.5 on AKS:
        # Ensure every container/initContainer drops ALL capabilities
        # for Pods that are NOT managed by higher-level controllers.
        #
        # This script:
        #   - Detects non-compliant Pods (excluding system namespaces)
        #   - Patches only standalone Pods (no controller ownerReferences)
        #   - Adds securityContext.capabilities.drop: ["ALL"] where missing
        #   - Is idempotent and safe to re-run
        #
        # Run on: any machine with kubectl access to the AKS cluster

        # Prereqs: kubectl, jq, yq (https://github.com/mikefarah/yq) v4+

        command -v kubectl >/dev/null 2>&1 || { echo "kubectl not found"; exit 1; }
        command -v jq >/dev/null 2>&1 || { echo "jq not found"; exit 1; }
        command -v yq >/dev/null 2>&1 || { echo "yq not found (v4 required)"; exit 1; }

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

        echo "Discovering non-compliant standalone 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)
            # Only Pods without controller ownerReferences (standalone Pods)
            | select(((.metadata.ownerReferences // [])
                      | map(select(.controller == true)) | length) == 0)
            as $pod
            | ($pod.spec.containers // [] + $pod.spec.initContainers // []) as $cs
            | [$cs[]
               | (.securityContext.capabilities.drop // []) as $drop
               | (($drop | index("ALL")) or ($drop | index("all"))) as $ok
               | select($ok | not)
              ] as $noncompliant_containers
            | select(($noncompliant_containers | length) > 0)
            | "\($pod.metadata.namespace) \($pod.metadata.name)"
          ' > "$WORKDIR/noncompliant_pods.txt"

        if [[ ! -s "$WORKDIR/noncompliant_pods.txt" ]]; then
          echo "No non-compliant standalone Pods found; nothing to change."
        else
          echo "Found the following non-compliant standalone Pods:"
          cat "$WORKDIR/noncompliant_pods.txt"
        fi

        while read -r NS NAME; do
          [[ -z "$NS" || -z "$NAME" ]] && continue
          echo "Processing Pod ${NS}/${NAME} ..."

          YAML_FILE="$WORKDIR/${NS}_${NAME}.yaml"
          PATCH_FILE="$WORKDIR/${NS}_${NAME}_patch.yaml"

          kubectl get pod "$NAME" -n "$NS" -o yaml > "$YAML_FILE"

          # Build a strategic merge patch that:
          #   - ensures securityContext exists on each container/initContainer
          #   - ensures capabilities.drop contains "ALL"
          #
          # This is done by transforming the live YAML into a patch that
          # only touches the relevant fields.
          yq eval '
            .spec |= (
              . // {} |
              .containers |= (
                . // [] |
                map(
                  .securityContext |= (. // {}) |
                  .securityContext.capabilities |= (. // {}) |
                  .securityContext.capabilities.drop |= (
                    . // [] |
                    (if (map(ascii_upcase) | index("ALL")) == null
                     then . + ["ALL"] | unique
                     else .
                     end)
                  )
                )
              ) |
              .initContainers |= (
                . // [] |
                map(
                  .securityContext |= (. // {}) |
                  .securityContext.capabilities |= (. // {}) |
                  .securityContext.capabilities.drop |= (
                    . // [] |
                    (if (map(ascii_upcase) | index("ALL")) == null
                     then . + ["ALL"] | unique
                     else .
                     end)
                  )
                )
              )
            )
            # Reduce to only the patch-relevant structure
            | {spec: {containers: .spec.containers, initContainers: .spec.initContainers}}
          ' "$YAML_FILE" > "$PATCH_FILE"

          # If nothing meaningful changed, skip
          if diff -q <(yq '.spec' "$YAML_FILE") <(yq '.spec *+ (load("'"$PATCH_FILE"'") | .spec)' "$YAML_FILE") >/dev/null 2>&1; then
            echo "  No changes required for ${NS}/${NAME} (already compliant)."
            continue
          fi

          echo "  Applying patch to ${NS}/${NAME} ..."
          kubectl patch pod "$NAME" -n "$NS" --type merge --patch-file "$PATCH_FILE"

        done < "$WORKDIR/noncompliant_pods.txt"

        echo
        echo "Re-running compliance check to verify..."

        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)
          # Only standalone Pods
          | select(((.metadata.ownerReferences // [])
                    | map(select(.controller == true)) | length) == 0)
          | .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 standalone Pods are now compliant (drop ALL)."
            else "Non-compliant standalone Pods still exist; investigate controller-managed workloads separately."
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
