Skip to main content

Ensure That All Namespaces Network Policies Defined

More Info:

Use network policies to isolate traffic in your cluster network.

Risk Level

Low

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS AKS
  • CIS Critical Security Controls v8
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • 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. List namespaces that currently have no NetworkPolicy (run on any machine with kubectl access):

    ns_without_np=$(comm -23 \
    <(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
    <(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))
    printf '%s\n' "$ns_without_np"
  2. For each namespace without a NetworkPolicy, create a default deny-all policy (run on any machine with kubectl access). Substitute the namespace name in place of <namespace>:

    kubectl apply -n <namespace> -f - <<EOF
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: default-deny-all
    spec:
    podSelector: {}
    policyTypes:
    - Ingress
    - Egress
    EOF
  3. (Optional but recommended) For each affected namespace, list the applied NetworkPolicies to confirm they exist and review their names:

    kubectl get networkpolicy -n <namespace>
  4. (Optional) For each namespace, define additional, more specific NetworkPolicies as needed to explicitly allow required traffic, using separate manifest files or inline kubectl apply -f - commands, and apply them with:

    kubectl apply -n <namespace> -f <your-networkpolicy-manifest.yaml>
  5. (Optional) If you have system or kube-system namespaces where a full default-deny could disrupt cluster operations, review with:

    kubectl get ns

    and decide whether to:

    • Keep the default-deny and add explicit allow rules, or
    • Replace it with a more permissive NetworkPolicy tailored to that namespace’s needs.
  6. Verify that all namespaces now have at least one NetworkPolicy (run on any machine with kubectl access):

    ns_without_np=$(comm -23 \
    <(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
    <(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))
    if [ -z "$ns_without_np" ]; then echo "ALL_NAMESPACES_HAVE_NETWORKPOLICIES"; else echo "MISSING_NETWORKPOLICIES"; printf '%s\n' "$ns_without_np"; fi
Using kubectl

On any machine with kubectl access:

  1. List namespaces missing NetworkPolicies (same logic as audit, but show them):
ns_without_np=$(comm -23 \
<(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
<(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))

printf '%s\n' "$ns_without_np"
  1. For each namespace in ns_without_np, create a default deny-all NetworkPolicy:
for ns in $ns_without_np; do
kubectl apply -n "$ns" -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
done

Adjust or add additional NetworkPolicies per namespace as required for your applications to function.

  1. Verification (run again from any machine with kubectl access):
ns_without_np=$(comm -23 \
<(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
<(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))

if [ -z "$ns_without_np" ]; then echo "ALL_NAMESPACES_HAVE_NETWORKPOLICIES"; else echo "MISSING_NETWORKPOLICIES: $ns_without_np"; fi
Automation
#!/usr/bin/env bash
set -euo pipefail

# Automation for: CIS AKS 4.4.2 - Ensure that all Namespaces have Network Policies defined
# Runs on: any machine with kubectl access to the cluster
# Requirements: kubectl configured with cluster-admin or equivalent permissions

# Optional: skip system namespaces if desired (set to "true" or "false")
SKIP_SYSTEM_NAMESPACES="${SKIP_SYSTEM_NAMESPACES:-true}"

# Namespaces to always skip (space-separated)
SYSTEM_NAMESPACES="kube-system kube-public kube-node-lease default"

echo "Discovering namespaces without any NetworkPolicy..."

# Build list of namespaces without any NetworkPolicy
ns_without_np=$(comm -23 \
<(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
<(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))

if [ -z "${ns_without_np}" ]; then
echo "All namespaces already have at least one NetworkPolicy."
else
echo "Namespaces currently without NetworkPolicy:"
echo "${ns_without_np}" | sed 's/^/ - /'
fi

apply_np_to_ns() {
local ns="$1"
echo "Applying default-deny-all NetworkPolicy in namespace: ${ns}"
kubectl apply -n "${ns}" -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
}

# Apply default-deny-all NetworkPolicy to each namespace lacking any policy
for ns in ${ns_without_np:-}; do
if [ "${SKIP_SYSTEM_NAMESPACES}" = "true" ]; then
for sys_ns in ${SYSTEM_NAMESPACES}; do
if [ "${ns}" = "${sys_ns}" ]; then
echo "Skipping system/known namespace '${ns}' (SKIP_SYSTEM_NAMESPACES=true)."
continue 2
fi
done
fi
apply_np_to_ns "${ns}"
done

echo "Re-checking namespaces for NetworkPolicies..."

# Verification (same logic as audit, but prints the remaining offenders if any)
verify_missing=$(comm -23 \
<(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) \
<(kubectl get networkpolicy --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort))

if [ -z "${verify_missing}" ]; then
echo "VERIFICATION PASSED: ALL_NAMESPACES_HAVE_NETWORKPOLICIES"
else
echo "VERIFICATION WARNING: The following namespaces still have no NetworkPolicy:"
echo "${verify_missing}" | sed 's/^/ - /'
echo "If this is intentional, document the exception; otherwise, re-run after fixing permissions/connectivity."
fi

Additional Reading: