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

# Ensure CNI Plugin Supports Network Policies

### More Info:

The CNI plugin must support NetworkPolicy resources for traffic segmentation to be enforceable. Use a CNI plugin that supports network policies and follow least-privilege network design.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Confirm the CNI plugin and its NetworkPolicy support**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             kubectl get pods -n kube-system -o wide | egrep 'calico|cilium|weave|flannel|antrea|kube-router'
             kubectl get daemonset -n kube-system -o wide
             ```
           * Review:
             * Identify the CNI in use (e.g., Calico, Cilium, Antrea) from pod/DaemonSet names.
             * Cross-check its documentation to confirm it supports Kubernetes `NetworkPolicy` (and whether it supports both ingress and egress).

        2. **Check whether NetworkPolicy objects are in use at all**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             kubectl get networkpolicy --all-namespaces
             ```
           * Review:
             * If no `NetworkPolicy` resources exist, the cluster currently has no enforced traffic segmentation. You must design and deploy policies (starting with least-privilege) once you confirm the CNI supports them.

        3. **Identify namespaces lacking a default restrictive policy**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             # List all namespaces
             kubectl get ns

             # For each namespace, list its policies (example for 'default'):
             kubectl get networkpolicy -n default -o yaml
             ```
           * Review for each namespace:
             * Check whether there is at least one “default deny” style policy that selects all pods and denies all ingress and (if supported) egress by default. Typical patterns:
               * PodSelector is empty (`podSelector: {}`) to match all pods.
               * No `ingress` section, or `policyTypes` includes `Ingress` but no allowed peers.
               * For egress control, `policyTypes` includes `Egress` and either no `egress` rules or only narrowly scoped destinations.

        4. **Assess current policies against least-privilege**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             kubectl get networkpolicy --all-namespaces -o yaml > /tmp/all-networkpolicies.yaml
             ```
           * Review `/tmp/all-networkpolicies.yaml`:
             * Look for broad rules such as:
               * `podSelector: {}` combined with `ingress` from all sources or `egress` to `0.0.0.0/0`.
               * `namespaceSelector: {}` without additional constraints.
             * Determine whether each policy exists to explicitly allow necessary traffic given a default-deny stance, or if it unintentionally creates wide-open access.

        5. **Design and apply least-privilege “default deny” and scoped allow policies**
           * Run on: any machine with kubectl access
           * For a namespace missing default-deny, create a manifest like:
             ```yaml theme={null}
             apiVersion: networking.k8s.io/v1
             kind: NetworkPolicy
             metadata:
               name: default-deny-all
               namespace: default
             spec:
               podSelector: {}
               policyTypes:
               - Ingress
               - Egress
             ```
           * Apply:
             ```bash theme={null}
             kubectl apply -f default-deny-all.yaml
             ```
           * Then, iteratively define additional `NetworkPolicy` manifests that:
             * Select only the pods that must communicate.
             * Allow only specific ingress sources and/or egress destinations and ports required for application function.

        6. **Verify enforcement and adjust as needed**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             kubectl get networkpolicy --all-namespaces -o wide
             kubectl describe networkpolicy -n default default-deny-all
             ```
           * Optional functional check:
             * Use test pods (e.g., `kubectl run -it --rm test --image=busybox --restart=Never -- sh`) to attempt connections that should be blocked or allowed, confirming the CNI is enforcing `NetworkPolicy` as designed. Adjust policies if legitimate traffic is unintentionally denied.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) List all installed CNI plugins (pods in kube-system)
        # Run on: any machine with kubectl access
        kubectl get pods -n kube-system -o wide
        ```

        Look for pods with names like `calico-*`, `cilium-*`, `azure-cni-*`, `aws-node`, `weave-net`, `antrea-*`, etc.\
        Investigate the documented capabilities of the detected CNI. If it does not explicitly support Kubernetes NetworkPolicy (or you see only a basic CNI like `flannel` without policy add-ons), network policies will not be enforced.

        ```bash theme={null}
        # 2) Check if any NetworkPolicies exist cluster-wide
        kubectl get networkpolicies --all-namespaces
        ```

        If this returns `No resources found` (or very few policies in only one namespace), then there is likely no meaningful segmentation. This is a policy gap even if the CNI supports NetworkPolicy.

        ```bash theme={null}
        # 3) Inspect network policies in a given namespace
        # Replace NAMESPACE with a real namespace, e.g. "default"
        kubectl get networkpolicy -n NAMESPACE -o wide
        kubectl describe networkpolicy -n NAMESPACE POLICY_NAME
        kubectl get networkpolicy -n NAMESPACE -o yaml
        ```

        Things that indicate a problem:

        * No “default deny” style policy (e.g. policies that select many/all pods and deny all ingress/egress by default).
        * Policies only allow traffic but never restrict it (no baseline deny).
        * `podSelector: {}` with overly broad `ingress`/`egress` rules that effectively allow all.

        ```bash theme={null}
        # 4) Verify whether default namespaces have baseline protection
        kubectl get ns
        # For each namespace of interest, inspect its policies:
        for ns in default kube-system kube-public; do
          echo "Namespace: $ns"
          kubectl get networkpolicy -n "$ns"
        done
        ```

        If `default` or other application namespaces have no `NetworkPolicy` objects at all, pods there can communicate freely with each other and, often, with the internet. That conflicts with a least-privilege design.

        ```bash theme={null}
        # 5) Test that policies are enforced (requires existing policies)
        # 5a) Get two pods in the same namespace
        kubectl get pods -n NAMESPACE -o wide

        # 5b) From one pod, try reaching another (adjust POD_NAME and TARGET_IP)
        kubectl exec -n NAMESPACE -it POD_NAME -- ping -c 3 TARGET_IP
        kubectl exec -n NAMESPACE -it POD_NAME -- nc -vz TARGET_IP TARGET_PORT
        ```

        If you have a NetworkPolicy that should *deny* this traffic but pings / connections still succeed, that suggests:

        * The CNI plugin does not enforce NetworkPolicy, or
        * The policy is misconfigured (e.g. selectors don’t match pods).

        ```bash theme={null}
        # 6) Check if a "default deny" exists in important namespaces
        # Example label-based search (may or may not return results)
        kubectl get networkpolicy -A -l "policy-type=default-deny" -o yaml
        ```

        If no namespaces have any “deny all” style policy (by label or by manual inspection of specs), then the cluster likely lacks a least-privilege baseline; traffic is broadly allowed until explicitly denied.

        Use the findings above to decide:

        * Whether your current CNI needs to be replaced/upgraded to one that supports NetworkPolicy.
        * Where to design and apply deny-all (or global) policies as a baseline and then add narrowly scoped allow rules.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Purpose:
        # - Report which CNI is installed
        # - Check if it is one that supports NetworkPolicy
        # - Summarize NetworkPolicy usage by namespace
        #
        # Run on: any machine with kubectl access and cluster-admin permissions

        set -euo pipefail

        echo "=== 1. Detecting CNI plugin(s) ==="
        echo "-> Inspecting kube-system namespace for common CNI DaemonSets and Pods..."
        kubectl get ds,pod -n kube-system -o wide | grep -Ei 'calico|cilium|weave|flannel|canal|antrea|ovn|amazon-vpc-cni|aws-node|azure|gke|cni' || \
          echo "No obvious CNI DaemonSet/Pod found by name pattern."

        echo
        echo "=== 1a. Detailed CNI pod images (kube-system) ==="
        kubectl get pods -n kube-system -o jsonpath='{range .items[*]}{.metadata.name}{"  "}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' \
          | grep -Ei 'calico|cilium|weave|flannel|canal|antrea|ovn|cni|aws-node|azure|gke' || \
          echo "No obvious CNI container images matched."

        cat <<'EOF'

        INTERPRETATION (CNI):
        - You MUST confirm from documentation whether your detected CNI supports Kubernetes NetworkPolicy.
        - Common cases:
          * Supports NetworkPolicy: calico, cilium, antrea, weave-net (with NP), canal, ovn-kubernetes, GKE-native, Azure CNI (with NP), etc.
          * Does NOT enforce NetworkPolicy (or only partially): basic flannel, some cloud-native CNIs unless NP mode is enabled.
        - If you see only 'flannel' or a cloud CNI known not to enforce NetworkPolicy, traffic segmentation via NetworkPolicy is NOT effective -> PROBLEM.

        EOF

        echo "=== 2. Cluster-wide NetworkPolicy usage ==="
        echo "-> Count NetworkPolicy objects per namespace"
        echo "NAMESPACE  NP_COUNT"
        kubectl get networkpolicy --all-namespaces --no-headers 2>/dev/null \
          | awk '{print $1}' | sort | uniq -c | awk '{printf "%-10s %s\n", $2, $1}' || \
          echo "No NetworkPolicy resources found in any namespace."

        echo
        echo "=== 2a. Namespaces with ZERO NetworkPolicies ==="
        # List all namespaces, join with those that have NPs
        ns_with_np="$(kubectl get networkpolicy --all-namespaces --no-headers 2>/dev/null | awk '{print $1}' | sort -u || true)"
        echo "Namespaces without any NetworkPolicy defined:"
        kubectl get ns --no-headers | awk '{print $1}' | while read -r ns; do
          if ! grep -qx "$ns" <<< "$ns_with_np"; then
            echo "  - $ns"
          fi
        done

        cat <<'EOF'

        INTERPRETATION (NetworkPolicy presence):
        - Namespaces with ZERO NetworkPolicies are likely allowing all traffic by default.
        - If your CNI DOES enforce NetworkPolicy, you should:
          * At least have baseline policies in sensitive namespaces, and
          * Consider a namespace-wide "default deny" (ingress/egress) where appropriate.

        EOF

        echo "=== 3. Detect namespaces missing a 'default deny' style policy ==="
        echo "-> Heuristic: look for NetworkPolicies that set podSelector: {} and policyTypes including Ingress/Egress"
        echo
        echo "Namespaces and policies that LOOK like 'default deny' candidates:"
        kubectl get networkpolicy --all-namespaces -o json \
          | jq -r '
            .items[]
            | select(
                (.spec.podSelector | tostring) == "{}"
              )
            | [
                .metadata.namespace,
                .metadata.name,
                ( .spec.policyTypes // [] | join(",") ),
                ( ( .spec.ingress // [] | length ) | tostring ),
                ( ( .spec.egress // [] | length ) | tostring )
              ]
            | @tsv
          ' 2>/dev/null \
          | awk 'BEGIN{printf "%-20s %-30s %-20s %-8s %-8s\n","NAMESPACE","POLICY","POLICY_TYPES","INGRESS","EGRESS"}
                 {printf "%-20s %-30s %-20s %-8s %-8s\n",$1,$2,$3,$4,$5}' || \
          echo "No NetworkPolicies found that look like namespace-wide defaults."

        cat <<'EOF'

        INTERPRETATION (default deny):
        - A robust least-privilege design usually:
          * Starts with a namespace-wide deny-all (podSelector: {} and policyTypes: [Ingress,Egress]),
          * Then adds specific allow rules.
        - Potential PROBLEMS:
          * Sensitive namespaces (e.g., containing workloads with secrets or external exposure) have:
            - No NetworkPolicies at all, or
            - Only allow rules but no clear default deny foundation.
          * The CNI does not enforce NetworkPolicy, making any defined policies ineffectual.

        EOF

        echo "=== 4. Verification summary ==="
        echo "- Confirm from vendor docs that the detected CNI ENFORCES NetworkPolicy."
        echo "- Review:"
        echo "  * Namespaces with no NetworkPolicies"
        echo "  * Namespaces lacking a clear default deny-style policy"
        echo "If CNI does not support NetworkPolicy, or policies do not follow least privilege, this check is NOT satisfied."
        ```

        Problem indicators in the script output:

        * CNI detection only shows plugins known not to enforce NetworkPolicy (e.g., plain flannel, or a cloud CNI without NP support enabled).
        * `No NetworkPolicy resources found in any namespace.` for a production cluster.
        * Sensitive namespaces listed under “Namespaces without any NetworkPolicy defined”.
        * No or very few “default deny”-style policies in the heuristic section for critical namespaces.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
