> ## 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 Set CPU And Memory Requests

### More Info:

Verifies every container sets resources.requests so the scheduler can place the pod correctly and QoS is not BestEffort.

### Risk Level

Low

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On any machine with kubectl access, list all non-compliant containers (those without CPU or memory requests):
           ```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 // [])[]
             | ((.resources.requests.cpu != null) and (.resources.requests.memory != null)) as $ok
             | select($ok | not)
             | "ns=\($m.namespace) pod=\($m.name) container=\(.name) image=\(.image)"
             ][]'
           ```

        2. For each affected Pod, identify whether it is controlled by a higher-level object (Deployment, DaemonSet, StatefulSet, Job, CronJob, etc.):
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.ownerReferences[*].kind}{" "}{.metadata.ownerReferences[*].name}{"\n"}'
           ```
           * If there is an ownerReference, you must edit the owner (e.g., Deployment), not the Pod.
           * If there is no ownerReference, edit the Pod directly.

        3. For Pods controlled by a higher-level controller (example: Deployment), edit the controller spec and add CPU and memory requests for each container:
           ```bash theme={null}
           kubectl edit deployment DEPLOYMENT_NAME -n NAMESPACE
           ```
           In the opened manifest, under each `spec.template.spec.containers[].resources`, ensure something like:
           ```yaml theme={null}
           resources:
             requests:
               cpu: "100m"
               memory: "128Mi"
           ```
           Save and exit; the controller will roll out new Pods with the defined requests.

        4. For standalone Pods (no ownerReference), patch them to add CPU and memory requests for a specific container (repeat per container as needed):
           ```bash theme={null}
           kubectl patch pod POD_NAME -n NAMESPACE \
             --type='json' \
             -p='[
               {
                 "op": "add",
                 "path": "/spec/containers/0/resources",
                 "value": {
                   "requests": {
                     "cpu": "100m",
                     "memory": "128Mi"
                   }
                 }
               }
             ]'
           ```
           Adjust the container index in `/spec/containers/0/...` and request values as appropriate for your workload.

        5. For workloads managed via manifests/IaC (e.g., GitOps, Helm, Terraform), locate and edit the source manifest instead of using `kubectl edit`, then apply:
           ```bash theme={null}
           kubectl apply -f PATH/TO/MANIFEST.yaml
           ```
           Ensure each container spec in the source includes `resources.requests.cpu` and `resources.requests.memory` before applying.

        6. Verification (on any machine with kubectl access): after changes roll out, rerun the compliance check and confirm `is_compliant=true` or no rows with `is_compliant=false`:
           ```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 // [])[]
             | ((.resources.requests.cpu != null) and (.resources.requests.memory != null)) 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)"
               + " requestsCpu=\(.resources.requests.cpu // "unset") requestsMemory=\(.resources.requests.memory // "unset")"
               + " 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 show non-`unset` `requestsCpu` and `requestsMemory` and `is_compliant=true`.
      </Accordion>

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

        1. Identify non‑compliant pods and their controllers

        ```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 // [])[]
          | ((.resources.requests.cpu != null) and (.resources.requests.memory != null)) as $ok
          | select($ok|not)
          | { ns: $m.namespace, pod: $m.name, ownerKind: ($own.kind // "Pod"), ownerName: ($own.name // $m.name) }
          ] | (reduce .[] as $i ({}; .["\($i.ns)|\($i.ownerKind)|\($i.ownerName)"]=1) | keys[])' \
        | column -t -s'|'
        ```

        This lists unique `<namespace> <ownerKind> <ownerName>` you need to edit (e.g. `default Deployment myapp`).

        2. Export the controller manifest, add requests, and re‑apply

        Example for a Deployment named `myapp` in namespace `default`:

        ```bash theme={null}
        kubectl -n default get deploy myapp -o yaml > myapp-patched.yaml
        ```

        Edit `myapp-patched.yaml` and, under each container, add `resources.requests.cpu` and `resources.requests.memory` if missing, for example:

        ```yaml theme={null}
        spec:
          template:
            spec:
              containers:
                - name: myapp
                  image: 111122223333.dkr.ecr.us-east-1.amazonaws.com/myapp:1.2.3
                  resources:
                    requests:
                      cpu: "100m"
                      memory: "128Mi"
                    # (optional but recommended)
                    limits:
                      cpu: "500m"
                      memory: "512Mi"
        ```

        Apply the updated manifest:

        ```bash theme={null}
        kubectl apply -f myapp-patched.yaml
        ```

        Repeat these steps for each non‑compliant controller kind (Deployment, StatefulSet, DaemonSet, Job, CronJob, etc.). For standalone Pods you manage directly, export/edit/apply similarly:

        ```bash theme={null}
        kubectl -n default get pod mypod -o yaml > mypod-patched.yaml
        # edit: add resources.requests for each container
        kubectl apply -f mypod-patched.yaml
        ```

        3. Verify remediation

        Run the benchmark audit command again 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 // [])[]
          | ((.resources.requests.cpu != null) and (.resources.requests.memory != null)) 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)"
            + " requestsCpu=\(.resources.requests.cpu // "unset") requestsMemory=\(.resources.requests.memory // "unset")"
            + " is_compliant=\(if $ok then "true" else "false" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```

        Confirm either `is_compliant=true` overall or that all listed containers now show non‑`unset` `requestsCpu` and `requestsMemory` with `is_compliant=true`.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Remediate CBP C1.9: ensure all containers set CPU and memory requests
        # Scope: any machine with kubectl access to the EKS cluster
        # Requirements: kubectl, jq, yq (https://github.com/mikefarah/yq) in PATH

        set -euo pipefail

        DEFAULT_CPU_REQUEST="100m"
        DEFAULT_MEM_REQUEST="128Mi"

        echo "Discovering non-compliant pods (excluding kube-system, kube-public, kube-node-lease)..."

        NON_COMPLIANT_JSON=$(kubectl get pods --all-namespaces -o json | jq '
          .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | . as $pod
          | .spec.containers[]
          | select((.resources.requests.cpu == null) or (.resources.requests.memory == null))
          | {
              ns: $pod.metadata.namespace,
              pod: $pod.metadata.name,
              container: .name
            }
        ' | jq -s '.')

        if [[ "$(echo "$NON_COMPLIANT_JSON" | jq 'length')" -eq 0 ]]; then
          echo "No non-compliant running pods found. Nothing to patch."
        else
          echo "Found non-compliant containers:"
          echo "$NON_COMPLIANT_JSON" | jq -r '.[] | "- ns=\(.ns) pod=\(.pod) container=\(.container)"'
        fi

        # Build unique owner references for non-compliant pods
        echo "Identifying owning workload objects to patch (Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicaSet, ReplicationController)..."

        OWNERS_JSON=$(kubectl get pods --all-namespaces -o json | jq '
          .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | . as $pod
          | .spec.containers as $containers
          | [
              $containers[]
              | select((.resources.requests.cpu == null) or (.resources.requests.memory == null))
            ] as $bad
          | select(($bad | length) > 0)
          | (.metadata.ownerReferences // [])[]
          | select(.controller == true)
          | {
              kind: .kind,
              name: .name,
              uid: .uid,
              namespace: $pod.metadata.namespace
            }
        ' | jq -s '
          # de-duplicate by (kind,namespace,name,uid)
          (unique_by(.kind,.namespace,.name,.uid))
        ')

        if [[ "$(echo "$OWNERS_JSON" | jq 'length')" -eq 0 ]]; then
          echo "Non-compliant pods have no controller owner (likely bare Pods)."
          echo "Patching Pods directly; changes will not persist if something recreates them."

          # Generate and apply patches for bare Pods
          echo "$NON_COMPLIANT_JSON" | jq -r '.[] | "\(.ns) \(.pod) \(.container)"' | sort -u | while read -r NS POD CONTAINER; do
            echo "Patching Pod/${POD} in namespace ${NS}, container ${CONTAINER}..."
            PATCH=$(cat <<EOF
        spec:
          containers:
            - name: ${CONTAINER}
              resources:
                requests:
                  cpu: "${DEFAULT_CPU_REQUEST}"
                  memory: "${DEFAULT_MEM_REQUEST}"
        EOF
        )
            kubectl -n "${NS}" patch pod "${POD}" --type merge -p "$(echo "${PATCH}")" || true
          done
        else
          echo "Found owning workload objects to patch:"
          echo "$OWNERS_JSON" | jq -r '.[] | "- kind=\(.kind) ns=\(.namespace) name=\(.name)"'

          # For each owner, fetch manifest, patch container resources, and apply
          echo "$OWNERS_JSON" | jq -r '.[] | "\(.namespace) \(.kind) \(.name)"' | sort -u | while read -r NS KIND NAME; do
            echo "Processing ${KIND}/${NAME} in namespace ${NS}..."

            # Export current manifest (as YAML)
            TMP_YAML=$(mktemp)
            kubectl -n "${NS}" get "${KIND}" "${NAME}" -o yaml > "${TMP_YAML}"

            # Patch containers in-place using yq:
            # - For all .spec.template.spec.containers[].resources.requests.*
            #   set defaults only if not already set.
            yq -i "
              (.spec.template.spec.containers[]? |
                select(.resources.requests.cpu == null) |
                .resources.requests.cpu) |= \"${DEFAULT_CPU_REQUEST}\" |
              (.spec.template.spec.containers[]? |
                select(.resources.requests.memory == null) |
                .resources.requests.memory) |= \"${DEFAULT_MEM_REQUEST}\"
            " "${TMP_YAML}"

            # Apply patched manifest (idempotent)
            kubectl apply -f "${TMP_YAML}"

            rm -f "${TMP_YAML}"
          done

          # Handle bare Pods that remain (if any)
          BARE_PODS_JSON=$(kubectl get pods --all-namespaces -o json | jq '
            .items[]
            | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
            | select((.metadata.ownerReferences // []) | length == 0)
            | . as $pod
            | .spec.containers[]
            | select((.resources.requests.cpu == null) or (.resources.requests.memory == null))
            | {
                ns: $pod.metadata.namespace,
                pod: $pod.metadata.name,
                container: .name
              }
          ' | jq -s '.')
          if [[ "$(echo "$BARE_PODS_JSON" | jq 'length')" -gt 0 ]]; then
            echo "Also patching bare Pods lacking ownerReferences:"
            echo "$BARE_PODS_JSON" | jq -r '.[] | "- ns=\(.ns) pod=\(.pod) container=\(.container)"'
            echo "$BARE_PODS_JSON" | jq -r '.[] | "\(.ns) \(.pod) \(.container)"' | sort -u | while read -r NS POD CONTAINER; do
              echo "Patching Pod/${POD} in namespace ${NS}, container ${CONTAINER}..."
              PATCH=$(cat <<EOF
        spec:
          containers:
            - name: ${CONTAINER}
              resources:
                requests:
                  cpu: "${DEFAULT_CPU_REQUEST}"
                  memory: "${DEFAULT_MEM_REQUEST}"
        EOF
        )
              kubectl -n "${NS}" patch pod "${POD}" --type merge -p "$(echo "${PATCH}")" || true
            done
          fi
        fi

        echo "Waiting for updated workloads to roll out (if any)..."
        kubectl get deploy,statefulset,daemonset -A >/dev/null 2>&1 || true

        echo "Re-running compliance audit..."

        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 // [])[]
          | ((.resources.requests.cpu != null) and (.resources.requests.memory != null)) as $ok
          | "ns=\($m.namespace) pod=\($m.name) container=\(.name) " +
            "requestsCpu=\(.resources.requests.cpu // "unset") " +
            "requestsMemory=\(.resources.requests.memory // "unset") " +
            "is_compliant=\(if $ok then "true" else "false" end)"
          ] as $rows
          | if ($rows | map(select(. | test("is_compliant=false$"))) | length) == 0
            then "is_compliant=true"
            else $rows[]
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
