Skip to main content

Ensure Network Policy Is Enabled And Set Appropriate

More Info:

Configure Network Policy for the Cluster.

Risk Level

Low

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS OKE
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Manual Steps
  1. Identify current cluster network plugin and policy support

    • Run on any machine with cloud CLI access:
      • For OKE:
        oci ce cluster get --cluster-id <CLUSTER_OCID> \
        --query 'data."endpoint-config"."is-private-endpoint"' --raw-output
        oci ce cluster get --cluster-id <CLUSTER_OCID> \
        --query 'data.options."kubernetes-network-config"'
      • Review the output for which CNI/networking option is in use (Flannel, OCI VCN-Native, Calico, etc.) and whether it supports Kubernetes NetworkPolicy.
  2. Check cluster-level Network Policy feature/configuration in provider

    • In the OCI Console:
      • Go to Developer Services → Kubernetes Clusters (OKE) → select the cluster.
      • Review Networking or Cluster Options tabs for:
        • Selected network type/plugin.
        • Any “Network Policy”, “Calico”, or similar options (varies by OKE version/shape).
    • With IaC (if used), inspect Terraform/Resource Manager definitions for the cluster (e.g., oci_containerengine_cluster resources) for networking-related attributes to confirm whether a NetworkPolicy‑capable plugin is configured.
  3. Enumerate existing Kubernetes NetworkPolicy objects

    • On any machine with kubectl access:
      kubectl get networkpolicy --all-namespaces
    • If none are listed or coverage is sparse, plan to introduce or tighten NetworkPolicy rules for critical namespaces (at minimum: system, control, and sensitive application namespaces).
  4. Assess current traffic exposure and required communication patterns

    • Gather application/service inventory:
      kubectl get ns
      kubectl get svc --all-namespaces -o wide
      kubectl get pods --all-namespaces -o wide
    • For each critical namespace, document:
      • Which services must be reachable from the internet, from other namespaces, and from internal-only components.
      • Required egress destinations (DNS, databases, external APIs).
    • Use this to determine the intended ingress/egress model so you can express it via NetworkPolicy.
  5. Decide and implement a NetworkPolicy strategy in cloud/IaC configuration

    • If the current OKE networking option does not support NetworkPolicy, plan a cluster migration or recreation using a NetworkPolicy‑capable option per OCI/OKE documentation and your IaC (Terraform, etc.).
    • If NetworkPolicy is supported but unused or incomplete:
      • Define baseline policies in manifests/IaC (even though this check is about provider configuration, NetworkPolicy objects themselves are Kubernetes resources):
        • Default‑deny ingress (and optionally egress) per namespace.
        • Explicit allow policies for required flows identified in step 4.
      • Ensure future namespaces get default‑deny policies via templates or admission controls in your deployment/IaC process.
  6. Verify effective Network Policy enablement and coverage

    • Confirm provider/networking configuration still indicates a NetworkPolicy‑capable CNI:
      oci ce cluster get --cluster-id <CLUSTER_OCID> \
      --query 'data.options."kubernetes-network-config"'
    • Confirm NetworkPolicy objects are present and cover intended namespaces:
      kubectl get networkpolicy --all-namespaces -o wide
    • Optionally validate behavior by attempting disallowed connections between pods/namespaces to ensure they are blocked as expected.
Using kubectl

kubectl cannot be used to enable or configure the cluster-level network policy feature for this finding, because it is controlled at the managed control-plane / cloud provider layer (for example, in the provider console, CLI, or IaC). Please refer to the Manual Steps section for guidance on reviewing and updating the provider-side network policy configuration.

Automation
#!/usr/bin/env bash
#
# audit-network-policies.sh
#
# Report Kubernetes NetworkPolicy usage across all namespaces.
# Run from any machine with kubectl access and sufficient RBAC.
# Requires: bash, kubectl

set -euo pipefail

echo "=== NetworkPolicy audit: $(date -Iseconds) ==="
echo

# 1) Cluster-level summary
echo "== Cluster-wide summary =="

echo "- NetworkPolicy resource presence:"
if kubectl api-resources | grep -qE '^networkpolicies[[:space:]]'; then
echo " * NetworkPolicy CRD/API: PRESENT"
else
echo " * NetworkPolicy CRD/API: MISSING"
echo " !! Problem: Your cluster API does not expose the NetworkPolicy resource."
echo " This usually means the network plugin or cluster configuration"
echo " does not support Kubernetes NetworkPolicy."
fi
echo

echo "- Network plugin hint (from kube-system pods):"
kubectl get pods -n kube-system -o wide \
| awk 'NR==1 || /calico|cilium|weave|antrea|azure-cni|aws-node|flannel|cni/ {print}'
echo
echo " NOTE: You must confirm from provider docs whether the CNI/plugin actually"
echo " enforces Kubernetes NetworkPolicy objects in this managed environment."
echo

# 2) Per-namespace NetworkPolicy coverage
echo "== Per-namespace NetworkPolicy coverage =="

# Get list of namespaces
namespaces=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

# Table header
printf "%-32s %-10s %-12s %-12s\n" "NAMESPACE" "NP_COUNT" "HAS_DEFAULT" "HAS_INGRESS_EGRESS"
printf "%-32s %-10s %-12s %-12s\n" "---------" "--------" "----------" "---------------"

for ns in $namespaces; do
# Count all NetworkPolicies in the namespace
np_count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')

# Check for any policy that appears to be a "default deny" or restrictive policy:
# - spec.podSelector == {} (selects all pods)
# - and either:
# * no ingress rules (deny-all ingress), or
# * no egress rules (deny-all egress), or
# * both missing (deny-all both directions)
has_default=$(kubectl get networkpolicy -n "$ns" -o json 2>/dev/null \
| jq -r '
.items[]
| select(.spec.podSelector == {} or .spec.podSelector == null)
| ( (has("spec") and (.spec | has("ingress") | not)) as $noIngress
| (has("spec") and (.spec | has("egress") | not)) as $noEgress
| if $noIngress or $noEgress then "yes" else empty end
)
' 2>/dev/null | head -n1)

if [[ -z "${has_default:-}" ]]; then
has_default="no"
fi

# Check if any NetworkPolicy in the namespace has both ingress and egress sections
has_ingress_egress=$(kubectl get networkpolicy -n "$ns" -o json 2>/dev/null \
| jq -r '
.items[]
| select((.spec.ingress | length > 0) and (.spec.egress | length > 0))
| "yes"
' 2>/dev/null | head -n1)

if [[ -z "${has_ingress_egress:-}" ]]; then
has_ingress_egress="no"
fi

printf "%-32s %-10s %-12s %-12s\n" "$ns" "$np_count" "$has_default" "$has_ingress_egress"
done

echo
echo "Interpretation of per-namespace table:"
echo " NP_COUNT : Number of NetworkPolicy objects in the namespace."
echo " HAS_DEFAULT : 'yes' if any policy appears to select all pods with"
echo " no ingress and/or no egress rules (default-deny style)."
echo " HAS_INGRESS_EGRESS: 'yes' if any policy uses both ingress and egress rules,"
echo " which often indicates more complete traffic control."
echo

# 3) Highlight potentially unprotected namespaces
echo "== Namespaces with NO NetworkPolicy defined =="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| while read -r ns; do
count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')
if [[ "$count" -eq 0 ]]; then
echo " - $ns"
fi
done

echo
echo "== Namespaces with NetworkPolicy but no apparent default-deny =="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| while read -r ns; do
json=$(kubectl get networkpolicy -n "$ns" -o json 2>/dev/null || echo '{}')
count=$(echo "$json" | jq '.items | length')
if [[ "$count" -eq 0 ]]; then
continue
fi
has_default=$(echo "$json" | jq -r '
.items[]
| select(.spec.podSelector == {} or .spec.podSelector == null)
| ( (has("spec") and (.spec | has("ingress") | not)) as $noIngress
| (has("spec") and (.spec | has("egress") | not)) as $noEgress
| if $noIngress or $noEgress then "yes" else empty end
)
' | head -n1)
if [[ -z "$has_default" ]]; then
echo " - $ns"
fi
done

echo
echo "=== How to interpret potential problems ==="
echo
echo "1) If 'NetworkPolicy CRD/API: MISSING':"
echo " - Problem: The cluster CNI / managed control plane likely does not support"
echo " Kubernetes NetworkPolicy, or it is disabled in the provider settings."
echo
echo "2) Namespaces listed under 'NO NetworkPolicy defined':"
echo " - Problem: Pods in these namespaces are generally fully open to network"
echo " traffic (subject to provider/CNI defaults). For security-sensitive workloads,"
echo " this is usually non-compliant with CIS recommendations."
echo
echo "3) Namespaces listed under 'NetworkPolicy but no apparent default-deny':"
echo " - Problem: There are some policies, but they may not provide a clear baseline"
echo " default-deny posture. You should manually review policies in those namespaces"
echo " to confirm they actually restrict traffic as intended."
echo
echo "NOTE: This script does NOT automatically fix issues or guarantee compliance."
echo " Use it as input for a manual review and for updating cloud-provider"
echo " network policy / CNI configuration and per-namespace policies."

To verify after changes, re-run:

bash audit-network-policies.sh

and confirm:

  • NetworkPolicy CRD/API: PRESENT is shown.
  • Security-sensitive namespaces no longer appear in:
    • “NO NetworkPolicy defined”
    • “NetworkPolicy but no apparent default-deny” (unless deliberately open by design).