Skip to main content

Ensure The CNI In Use Supports NetworkPolicies

More Info:

Without a CNI plugin that supports NetworkPolicies, traffic between pods cannot be restricted. Use a plugin that enforces network policy.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Identify the current CNI plugin and its capabilities

    • Run on: any machine with kubectl access
    • Commands:
      kubectl get pods -n kube-system -o wide
      kubectl get daemonset -n kube-system
      kubectl get pods -n kube-system -l k8s-app=calico-node --ignore-not-found
      kubectl get pods -n kube-system -l k8s-app=weave-net --ignore-not-found
      kubectl get pods -n kube-system -l k8s-app=cilium --ignore-not-found
      kubectl get pods -n kube-system -l k8s-app=flannel --ignore-not-found
      kubectl get pods -n kube-system -l k8s-app=kube-router --ignore-not-found
    • From these outputs, determine which CNI is installed and consult its official documentation to verify whether it implements Kubernetes NetworkPolicy.
  2. Check whether NetworkPolicy objects are being used

    • Run on: any machine with kubectl access
    • Commands:
      kubectl get networkpolicy --all-namespaces
    • If no NetworkPolicy resources exist, document that policies are not in use and decide whether you want to start using them. If they exist, proceed to validate that they are enforced.
  3. Functionally test whether NetworkPolicies are enforced

    • Run on: any machine with kubectl access
    • Create a test namespace and pods:
      kubectl create namespace np-test
      kubectl run np-allowed -n np-test --image=nginx --port=80 --labels=role=allowed --restart=Never
      kubectl run np-denied -n np-test --image=nginx --port=80 --labels=role=denied --restart=Never
      kubectl run np-client -n np-test --image=busybox --restart=Never --command -- sh -c "sleep 3600"
      kubectl wait --for=condition=ready pod -n np-test --all --timeout=120s
    • Verify baseline connectivity (should be allowed before any policy):
      kubectl exec -n np-test np-client -- wget -qO- http://np-allowed.np-test.svc.cluster.local
      kubectl exec -n np-test np-client -- wget -qO- http://np-denied.np-test.svc.cluster.local
  4. Apply a restrictive NetworkPolicy and observe behavior

    • Run on: any machine with kubectl access
    • Create a policy that only allows traffic to np-allowed from pods with label access=granted:
      cat <<'EOF' | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
      name: allow-from-granted-only
      namespace: np-test
      spec:
      podSelector:
      matchLabels:
      role: allowed
      policyTypes:
      - Ingress
      ingress:
      - from:
      - podSelector:
      matchLabels:
      access: granted
      EOF
    • Label the client incorrectly and test (should be blocked if NetworkPolicy is enforced):
      kubectl label pod -n np-test np-client access=denied --overwrite
      kubectl exec -n np-test np-client -- wget -qO- http://np-allowed.np-test.svc.cluster.local --timeout=5
    • Then label it correctly and test again (should succeed if enforced):
      kubectl label pod -n np-test np-client access=granted --overwrite
      kubectl exec -n np-test np-client -- wget -qO- http://np-allowed.np-test.svc.cluster.local --timeout=5
    • If connectivity is unaffected by the policy, your current CNI is not enforcing NetworkPolicy.
  5. Decide and plan remediation if NetworkPolicies are not enforced

    • If the CNI does not support NetworkPolicy, or the tests above show no enforcement:
      • Document the current CNI and its limitations.
      • Select a CNI that supports Kubernetes NetworkPolicy and is compatible with your environment (for example, Calico, Cilium, Weave Net, Kube-router; verify support in their documentation).
      • Plan a migration window, including:
        • Reading the chosen CNI’s install/migration guide for your Kubernetes distribution.
        • Capturing current CNI manifests in kube-system:
          kubectl get daemonset,deploy,cm,svc -n kube-system -o wide
          kubectl get daemonset -n kube-system -o yaml > /tmp/kube-system-daemonsets.yaml
        • Assessing impact on existing workloads and any current (even if non‑enforced) NetworkPolicy objects.
  6. Clean up test resources and re-verify after any CNI change

    • Run on: any machine with kubectl access
    • Clean up test namespace:
      kubectl delete namespace np-test
    • After migrating to a CNI that supports NetworkPolicy, repeat steps 2–4 to confirm that:
      • NetworkPolicy objects exist (if you use them), and
      • Connectivity tests change as expected when policies are applied, demonstrating that the CNI now enforces network policies.
Using kubectl
# 1. Identify which CNI plugin is in use
# Run on: any machine with kubectl access

kubectl get pods -n kube-system -o wide | egrep 'calico|cilium|weave|flannel|canal|antrea|azure-cni|amazon-vpc-cni|gke|ovn|tigera|cni'

# Also list all DaemonSets in kube-system (most CNIs run as a DaemonSet)
kubectl get daemonsets -n kube-system -o wide

What to look for

  • Pods/DaemonSets named like:
    • calico-node, calico-typha, tigera-operator → Calico (supports NetworkPolicy)
    • cilium, cilium-agent → Cilium (supports NetworkPolicy)
    • kube-flannel-ds or flannel-* → Flannel (basic Flannel does NOT enforce NetworkPolicy)
    • weave-net → Weave Net (supports NetworkPolicy)
    • kube-router → kube-router (supports NetworkPolicy)
    • antrea-agent → Antrea (supports NetworkPolicy)
    • Cloud CNIs (amazon-vpc-cni-*, azure-cni-*, gke-*, ovn-kubernetes, etc.) → check their docs for NetworkPolicy support.
  • If you see only kube-proxy and no obvious CNI pods, or see a home‑grown/unknown CNI without clear documentation, treat this as “unknown/likely not supporting NetworkPolicy” until verified.

# 2. Check whether any NetworkPolicy objects exist
# Run on: any machine with kubectl access

kubectl get networkpolicy --all-namespaces

What to look for

  • If no NetworkPolicy objects exist but:
    • Security requirements expect pod‑to‑pod isolation, and
    • The CNI supports NetworkPolicy
      → This is a policy design gap, not a CNI capability problem.
  • If many NetworkPolicy objects exist, but the CNI is known not to support them (e.g., plain Flannel):
    • This indicates a serious problem: policies are being defined but are not enforced at all.

# 3. Inspect an example NetworkPolicy spec
# Run on: any machine with kubectl access

# Replace NAMESPACE and NAME with a policy you saw above
kubectl get networkpolicy -n NAMESPACE NAME -o yaml

What to look for

  • Confirm these are Kubernetes kind: NetworkPolicy (not a CRD from some other system).
  • If the CNI is known not to support NetworkPolicy, any such spec is effectively documentation only, not enforced.

# 4. (Optional) Quick runtime sanity check of isolation behavior
# Run on: any machine with kubectl access

# 4a. Create a test namespace
kubectl create namespace np-test

# 4b. Create two simple test pods
kubectl run client -n np-test --image=busybox --restart=Never -- /bin/sh -c "sleep 3600"
kubectl run server -n np-test --image=nginx --restart=Never

# Wait for them to be Ready
kubectl wait --for=condition=Ready pod/client pod/server -n np-test --timeout=120s

# 4c. Get the server Pod IP
SERVER_IP=$(kubectl get pod server -n np-test -o jsonpath='{.status.podIP}')
echo "$SERVER_IP"

# 4d. Test connectivity BEFORE any NetworkPolicy (should generally succeed in typical clusters)
kubectl exec -n np-test client -- wget -qO- "http://$SERVER_IP"

# 4e. Apply a default-deny NetworkPolicy in np-test
cat << 'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: np-test
spec:
podSelector: {}
policyTypes:
- Ingress
EOF

# 4f. Test connectivity AGAIN after policy is applied
kubectl exec -n np-test client -- wget -qO- "http://$SERVER_IP" || echo "connection blocked"

What indicates a problem

  • If the initial connection (step 4d) fails unexpectedly → there may already be other policies or other controls in place; interpret with caution.
  • Key check: after applying the deny-all NetworkPolicy (step 4e):
    • If the wget in step 4f still succeeds consistently and you are sure:
      • The deny-all policy is applied (check with kubectl get networkpolicy -n np-test deny-all -o yaml), and
      • There are no other NetworkPolicies allowing this traffic
        → This strongly suggests the CNI does not enforce Kubernetes NetworkPolicy (or is misconfigured).
    • If the wget fails or hangs until timeout, this suggests NetworkPolicies are being enforced.

Clean up the test objects when done:

kubectl delete namespace np-test

# 5. Verification summary command (for documentation)
# Run on: any machine with kubectl access

# Summarize CNI-related pods and whether NetworkPolicies exist
echo "=== CNI Pods (kube-system) ==="
kubectl get pods -n kube-system -o wide | egrep 'calico|cilium|weave|flannel|canal|antrea|azure-cni|amazon-vpc-cni|gke|ovn|tigera|cni' || echo "No known CNI pods found"

echo "=== NetworkPolicies in the cluster ==="
kubectl get networkpolicy --all-namespaces || echo "No NetworkPolicies defined"

How to interpret

  • If the CNI identified above is one that does not support NetworkPolicy (e.g., plain Flannel) and there is a requirement to restrict pod‑to‑pod traffic using Kubernetes NetworkPolicy, this finding is not remediated and you must:
    • Migrate to a CNI that supports NetworkPolicies, or
    • Implement alternative network controls outside Kubernetes.
Automation
#!/usr/bin/env bash
#
# Check CNI plugins in use and whether NetworkPolicies are likely to be enforced
# Run on: any machine with kubectl access and cluster-wide RBAC
#
# Requires: kubectl, jq

set -euo pipefail

echo "=== 1) Detect CNI plugins in use on each node ==="
kubectl get nodes -o wide | sed 's/^/NODE: /'

echo
echo "Node-level CNI detection (from kubelet args and CNI config paths):"
kubectl get nodes -o name | while read -r node; do
nodename="${node##*/}"
echo
echo "---- ${nodename} ----"

# Try to detect kubelet CNI-related flags from the kubelet config (if present)
# This only works on some distros that expose config via the ConfigMap
if kubectl -n kube-system get cm kubelet-config -o json >/dev/null 2>&1; then
echo " kubelet CNI configuration (cluster-wide, from kubelet-config ConfigMap):"
kubectl -n kube-system get cm kubelet-config -o json \
| jq -r '.data | to_entries[] | select(.key|test("kubelet")) | .value' \
| jq -r '.cniConfDir? // "<unknown>", .cniBinDir? // "<unknown>"' \
| awk 'NR==1{printf " cniConfDir: %s\n",$0} NR==2{printf " cniBinDir: %s\n",$0}'
else
echo " kubelet-config ConfigMap not found; CNI paths may need to be checked on nodes directly."
fi

# Look for CNI-related DaemonSets on this node via nodeSelector / tolerations
echo " CNI-related DaemonSets scheduled on this node:"
kubectl get daemonsets -A -o json \
| jq -r --arg NODE "${nodename}" '
.items[]
| select(.metadata.name|test("calico|cilium|weave|flannel|antrea|canal|ovn|kube-ovn";"i"))
| "\(.metadata.namespace)/\(.metadata.name)"' \
| sed 's/^/ /' || true
done

echo
echo "=== 2) Detect installed CNI plugin components (best-effort from known labels) ==="
echo "Known network/CNI DaemonSets:"
kubectl get daemonsets -A \
| grep -Ei 'calico|cilium|weave|flannel|antrea|canal|ovn|kube-ovn|kube-router|tigera' \
|| echo " No known CNI DaemonSets matched by heuristic grep."

echo
echo "For each candidate CNI, basic capability hints:"
kubectl get daemonsets -A -o json \
| jq -r '
.items[]
| select(.metadata.name|test("calico|cilium|weave|flannel|antrea|canal|ovn|kube-ovn|kube-router|tigera";"i"))
| "- CNI: \(.metadata.namespace)/\(.metadata.name)
Images: \(.spec.template.spec.containers[].image)
Annotations: \(.metadata.annotations // {} | to_entries[]? | select(.key|test(\"networkpolicy|network-policy|policies\";\"i\")) | .key + \"=\" + .value)"' \
| sed 's/^[ ]\+//'

echo
echo "=== 3) Detect presence of NetworkPolicy objects in the cluster ==="
kubectl get networkpolicies --all-namespaces || echo "No NetworkPolicies found (no output)."

echo
echo "=== 4) Probe whether basic egress isolation is likely enforced (heuristic) ==="
echo "NOTE: This does NOT prove correctness; it only checks if any default-deny policies exist."
echo "Default-deny ingress NetworkPolicies:"
kubectl get networkpolicies --all-namespaces -o json \
| jq -r '
.items[]
| select(
(.spec.podSelector | has("matchLabels") or has("matchExpressions"))
and
((.spec.ingress | length == 0) or (.spec.ingress == null))
)
| "\(.metadata.namespace)/\(.metadata.name)"' \
|| echo " None detected."

echo
echo "Default-deny egress NetworkPolicies:"
kubectl get networkpolicies --all-namespaces -o json \
| jq -r '
.items[]
| select(
(.spec.podSelector | has("matchLabels") or has("matchExpressions"))
and
((.spec.egress | length == 0) or (.spec.egress == null))
and
(.spec.policyTypes[]? | ascii_downcase == "egress")
)
| "\(.metadata.namespace)/\(.metadata.name)"' \
|| echo " None detected."

echo
echo "=== 5) Summary of potential issues to review manually ==="
echo "1) If no CNI DaemonSet or plugin could be identified above, manually check:"
echo " - Which CNI is installed on each node (e.g., /etc/cni/net.d on the node)."
echo " - Whether that CNI's documentation states explicit support for Kubernetes NetworkPolicy."
echo
echo "2) If the identified CNI is known NOT to support NetworkPolicies (e.g., vanilla Flannel),"
echo " this is a finding: NetworkPolicies defined in the cluster will NOT be enforced."
echo
echo "3) If NetworkPolicy objects exist but the CNI plugin does not support them, this is a finding."
echo " Compare the CNIs detected in section (2) against vendor docs."
echo
echo "4) If no NetworkPolicy objects exist at all, this script cannot tell whether the CNI"
echo " would enforce them; you must still confirm the plugin's capabilities from its docs."
echo
echo "This check is MANUAL: use the above data + the CNI vendor documentation to decide whether"
echo "the CNI in use truly supports Kubernetes NetworkPolicies."

How to interpret output (what indicates a problem):

  • No CNI DaemonSet or plugin is detected, or only a plugin known not to support NetworkPolicies is present (for example, basic Flannel without policy extensions).
  • NetworkPolicy objects exist (kubectl get networkpolicies --all-namespaces shows entries), but the detected CNI plugin’s documentation does not explicitly state support for Kubernetes NetworkPolicy.
  • Operators cannot identify any CNI plugin at all or cannot confirm from documentation that it enforces NetworkPolicies.