Skip to main content

Ensure The CNI In Use Supports Network Policies

More Info:โ€‹

Network Policies are only enforced when the clusters CNI plugin supports them. Enabling Network Policy in GKE updates the CNI to a policy-capable plugin.

Risk Levelโ€‹

Medium

Addressโ€‹

Security

Compliance Standardsโ€‹

  • CIS GKE

Triage and Remediationโ€‹

Remediationโ€‹

Manual Steps
  1. Confirm GKE Network Policy feature status (per cluster)

    • On any machine with gcloud and kubectl access, run:
      gcloud container clusters list --project YOUR_PROJECT_ID
      gcloud container clusters describe YOUR_CLUSTER_NAME \
      --project YOUR_PROJECT_ID \
      --region YOUR_CLUSTER_REGION \
      --format="value(networkPolicy.enabled,networkPolicy.provider)"
    • If networkPolicy.enabled is true and a provider is shown (e.g. CALICO), the control plane is configured for Network Policyโ€“capable CNI. If false or empty, Network Policy is not enabled.
  2. Check that NetworkPolicy objects exist and are being used

    • On any machine with kubectl access:
      kubectl get networkpolicies --all-namespaces
    • If there are no NetworkPolicy objects but you expect network isolation, plan to create them; if there are many, note key namespaces/workloads that rely on them.
  3. Validate that policies are enforced as expected (functional test)

    • Create a temporary test namespace and pods:
      kubectl create namespace netpol-test
      kubectl run allowed-client -n netpol-test --image=busybox --restart=Never \
      --command -- sleep 3600
      kubectl run test-server -n netpol-test --image=nginx --restart=Never
      kubectl expose pod test-server -n netpol-test --port=80
    • From allowed-client, verify it can reach the server before any policy:
      kubectl exec -n netpol-test allowed-client -- wget -qO- http://test-server
  4. Apply a restrictive NetworkPolicy and observe behavior

    • Apply a policy that should block the above traffic:
      cat << 'EOF' | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
      name: deny-all-ingress
      namespace: netpol-test
      spec:
      podSelector: {}
      policyTypes:
      - Ingress
      EOF
    • Test connectivity again; it should now fail:
      kubectl exec -n netpol-test allowed-client -- wget -qO- http://test-server
    • If traffic still succeeds, your CNI is not enforcing NetworkPolicies (or another plugin/feature is overriding behavior).
  5. If Network Policy is not enabled or not enforced, update cluster configuration

    • Decide cluster-by-cluster whether you require NetworkPolicy enforcement. For clusters where you do:
      • Use GKE Console: Edit the cluster โ†’ enable โ€œNetwork Policyโ€ โ†’ save (this may trigger node pool recreation/rolling updates).
      • Or via CLI on any machine with gcloud:
        gcloud container clusters update YOUR_CLUSTER_NAME \
        --project YOUR_PROJECT_ID \
        --region YOUR_CLUSTER_REGION \
        --enable-network-policy
    • Plan maintenance windows as this can recreate nodes and briefly disrupt workloads.
  6. Re-verify after changes

    • After the update completes, repeat steps 1โ€“4 to confirm:
      • networkPolicy.enabled is true with a supported provider.
      • The functional test shows traffic is allowed without policy and blocked with policy.
    • Clean up the test namespace when done:
      kubectl delete namespace netpol-test
Using kubectl
# 1) List all NetworkPolicy objects in all namespaces
# Run on: any machine with kubectl access
kubectl get networkpolicy --all-namespaces -o wide

Review points:

  • If you expect NetworkPolicies to be used and this returns no resources found, then NetworkPolicy is not being used; this may indicate a gap in your design, not in the CNI itself.
# 2) Inspect a sample NetworkPolicy (replace with a real name/namespace)
kubectl get networkpolicy -n default -o yaml
kubectl describe networkpolicy -n default <networkpolicy-name>

Review points:

  • Ensure policies target pods that actually exist (selectors match current pod labels).
  • Check kubectl describe for any events or warnings suggesting policies are not applied as expected.
# 3) Confirm NetworkPolicy is recognized as an API resource
kubectl api-resources | grep -i networkpolicy

Expected:

  • You should see an entry like:
    • networkpolicies networking.k8s.io/v1 true NetworkPolicy
  • If there is no line for networkpolicies, the cluster is misconfigured or very old; NetworkPolicy cannot work regardless of CNI.
# 4) Verify GKE cluster Network Policy feature status (GKE only)
# Run from: any machine with gcloud + kubectl configured and same project
gcloud container clusters list \
--format="table(name,location,networkPolicy.networkPolicyConfig.disabled,networkConfig.datapathProvider)"

# For a specific cluster (replace with actual cluster name and location)
gcloud container clusters describe <cluster-name> \
--zone <zone> \
--format="flattened(networkPolicy,networkConfig.datapathProvider)"

Review points:

  • For gcloud container clusters list, look at:
    • networkPolicy.networkPolicyConfig.disabled
      • false โ†’ Network Policy is enabled at the GKE control-plane level.
      • true or empty โ†’ Network Policy is not enabled; even if NetworkPolicy objects exist, they will not be enforced by the CNI.
  • networkConfig.datapathProvider:
    • ADVANCED_DATAPATH or an equivalent policy-capable provider is expected when Network Policy is enabled.
    • If Network Policy is disabled and you rely on it for isolation, this is a problem.
# 5) (Optional) Simple runtime check using a temporary test pod
# Create two test pods with labels (in a non-critical namespace)
kubectl create ns netpol-test
kubectl run client --image=busybox -n netpol-test --restart=Never --command -- sleep 3600
kubectl run server --image=busybox -n netpol-test --restart=Never --command -- sh -c "nc -lk -p 80"

# Wait until both are Running, then:
kubectl get pods -n netpol-test -o wide
# 6) Apply a restrictive NetworkPolicy and test connectivity
cat <<'EOF' | kubectl apply -n netpol-test -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
spec:
podSelector:
matchLabels: {}
policyTypes:
- Egress
EOF

# From client pod: attempt to connect to server and to the internet
kubectl exec -n netpol-test client -- sh -c "nc -vz server 80 || echo 'connect to server failed'"
kubectl exec -n netpol-test client -- sh -c "wget -qO- http://example.com || echo 'connect to internet failed'"

Review points:

  • If NetworkPolicy is supported and enforced, you should see:
    • Connections that were previously succeeding now failing after the policy is applied, consistent with the policy rules.
  • If connections continue to succeed despite a clearly restrictive policy, that strongly suggests:
    • The CNI in use is not enforcing NetworkPolicies, or
    • Network Policy is not enabled at the GKE cluster level.
# 7) Cleanup of test namespace when finished
kubectl delete ns netpol-test

Finding interpretation:

  • Problem indicated when:
    • GKE cluster Network Policy is disabled, yet you rely on NetworkPolicies for pod isolation, or
    • Runtime tests show NetworkPolicies have no effect on traffic, despite being created and recognized by the API.
Automation
#!/usr/bin/env bash
# Purpose: Report whether the cluster's CNI and nodes support Kubernetes NetworkPolicies.
# Run on: any machine with kubectl access and 'kubectl' configured for the target cluster.

set -euo pipefail

echo "=== 1) Detect cluster type (looking for GKE) ==="
kubectl config current-context || {
echo "ERROR: No current kubectl context" >&2
exit 1
}

CONTEXT="$(kubectl config current-context)"
echo "Current context: ${CONTEXT}"

# Heuristic: GKE contexts typically look like gke_PROJECT_ZONE_CLUSTER
if [[ "${CONTEXT}" == gke_* ]]; then
echo "Cluster appears to be GKE (context name starts with 'gke_')."
else
echo "Cluster does not look like a standard GKE context."
echo "This CISGKE control is intended for GKE, but results below may still be informative."
fi
echo

echo "=== 2) Inspect CNI-related DaemonSets in kube-system ==="
kubectl -n kube-system get ds \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,IMAGES:.spec.template.spec.containers[*].image' \
| sed '1!{/cni\|calico\|weave\|cilium\|flannel\|canal/!d}'

echo
echo "Details for suspected CNI DaemonSets (kube-system) ==="
for ds in $(kubectl -n kube-system get ds -o name | sed -n '/cni\|calico\|weave\|cilium\|flannel\|canal/p'); do
echo "--- ${ds} ---"
kubectl -n kube-system get "${ds}" -o yaml | awk '
/kind: DaemonSet/ {print "# DaemonSet metadata:"}
/name: / && /DaemonSet/ {print " " $0}
/image: / {print " " $0}
' || true
done
echo

echo "=== 3) Show CNI configuration files on each node (via hostPath mounts) ==="
echo "Looking for known CNI config directories mounted into pods in kube-system..."
kubectl -n kube-system get pods -o wide

echo
echo "Pods in kube-system with hostPath mounts under /etc/cni or /opt/cni: "
kubectl -n kube-system get pods -o json \
| jq -r '
.items[]
| {name: .metadata.name, ns: .metadata.namespace, volumes: .spec.volumes}
| select(.volumes != null)
| . as $pod
| $pod.volumes[]
| select(.hostPath != null)
| select(.hostPath.path | test("^/etc/cni|^/opt/cni"))
| "Pod: \($pod.ns)/\($pod.name) hostPath: \(.hostPath.path)"
'

echo
echo "NOTE: The above shows where CNI configs live on nodes (via hostPath mounts)."
echo "You must manually log into nodes to inspect exact CNI config if needed."
echo

echo "=== 4) Check if any NetworkPolicy objects exist in the cluster ==="
kubectl get networkpolicy --all-namespaces || true
echo
echo "Interpretation:"
echo "- If you have NO NetworkPolicy objects, this control is low-risk right now,"
echo " but you still must ensure the CNI supports NetworkPolicy BEFORE creating any."
echo

echo "=== 5) Check for typical GKE Network Policy signals ==="
echo "Checking for GKE-specific annotations/labels that often indicate Network Policy enablement..."
echo

echo "-- Cluster-wide hint from kube-system namespace (not authoritative) --"
kubectl get ns kube-system -o yaml \
| sed -n '/annotations:/,/labels:/p' || true
echo

echo "-- GKE-managed network policy controller (if present) --"
kubectl -n kube-system get deploy \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' \
| sed -n '/netpol\|network-policy\|calico\|cilium/p' || true
echo

echo "=== 6) Summary / what indicates a potential PROBLEM ==="
cat <<'EOF'
You must manually decide whether the CNI in use supports Kubernetes NetworkPolicy.
Use the data above and the guidance below:

POTENTIAL PROBLEM indicators:
- The only visible CNI-related DaemonSets/images are known NON-policy CNIs (e.g. plain 'k8s.gcr.io/pause'
does not count; common non-policy CNIs include plain 'flannel' without policy add-ons).
- You see NetworkPolicy objects in the cluster (step 4 lists them), BUT:
* There is no known policy-capable CNI DaemonSet (e.g. no Calico, Cilium, GKE Network Policy add-on),
OR
* You know from GKE console that "Network Policy" is DISABLED for this cluster.
- On GKE specifically:
* GKE console shows Network Policy is disabled for the cluster (you must check this manually),
OR
* Your CNI images look like the older non-policy CNI used by GKE before Network Policy was enabled.

LIKELY OK indicators (but still require human confirmation):
- On GKE:
* GKE console shows Network Policy ENABLED for the cluster, AND
* You see CNI/Network Policy components consistent with the enabled add-on.
- On non-GKE clusters:
* You clearly identify a CNI with documented NetworkPolicy support (e.g. Calico, Cilium, Weave Net
with policy, Canal, etc.) from the DaemonSet/images and node CNI configs.

Because this is a MANUAL control, there is no automated pass/fail:
- Use this script to inventory:
* Which CNI DaemonSets and images are present
* Whether NetworkPolicy resources are being used
- Then:
* For GKE: verify in the GKE console/CLI that Network Policy is enabled for the cluster.
* For other environments: consult the CNI plugin's official documentation to confirm it
supports Kubernetes NetworkPolicy semantics.

If you discover:
- NetworkPolicies in use AND a CNI that does NOT support them:
-> This is a finding. You must plan a migration to a policy-capable CNI
(on GKE, by enabling Network Policy for the cluster).
EOF