Skip to main content

Ensure That All Namespaces Have Network Policies Defined

More Info:

Without NetworkPolicies, pods accept traffic from any source by default. Every namespace should define at least one NetworkPolicy to control pod-level traffic.

Risk Level

High

Address

Security

Compliance Standards

  • CIS AKS

Triage and Remediation

Remediation

Manual Steps
  1. Identify namespaces missing NetworkPolicies (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 that needs a strict default, create a default-deny-all policy (run on any machine with kubectl access; replace NAMESPACE with one from the list above):

    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. For namespaces where you cannot fully deny all traffic, create an initial restrictive policy and adjust later (example allowing only intra-namespace traffic; run on any machine with kubectl access and replace NAMESPACE):

    kubectl apply -n NAMESPACE -f - <<'EOF'
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: restrict-to-namespace
    spec:
    podSelector: {}
    policyTypes:
    - Ingress
    ingress:
    - from:
    - podSelector: {}
    EOF
  4. Review and customize policies in critical namespaces (e.g., kube-system, monitoring, ingress) to avoid breaking traffic (run on any machine with kubectl access):

    # List policies in a namespace
    kubectl get networkpolicy -n NAMESPACE

    # Show details of a policy
    kubectl describe networkpolicy -n NAMESPACE POLICY_NAME

    # Edit a policy in-place
    kubectl edit networkpolicy -n NAMESPACE POLICY_NAME
  5. Optionally export policies to manifests for version control (run on any machine with kubectl access):

    kubectl get networkpolicy -A -o yaml > all-networkpolicies-backup.yaml
  6. Verification (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 to the cluster:

  1. List namespaces currently missing NetworkPolicies (for your awareness):
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. Create a default-deny NetworkPolicy in each namespace that lacks one (replace the namespace list as needed, or paste from the previous command’s output):
for ns in kube-system default; 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 the for ns in ... list to include every namespace that should receive a default-deny policy, based on your environment and application needs.

  1. Verification (same command used by the audit):
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
# Applies a default-deny NetworkPolicy to every namespace that has none.
# Run on: any machine with kubectl access and current context set to target cluster.

set -euo pipefail

echo "[INFO] Discovering 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) \
|| true)

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

# Apply a default-deny-all NetworkPolicy in each namespace that lacks any policy.
# This is idempotent: apply will create or update the same object safely.
while read -r ns; do
[ -z "${ns}" ] && continue
echo "[INFO] 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

done <<< "${ns_without_np}"
fi

echo "[INFO] Verifying that all namespaces now have at least one NetworkPolicy..."
verify_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) \
|| true)

if [ -z "${verify_ns_without_np}" ]; then
echo "ALL_NAMESPACES_HAVE_NETWORKPOLICIES"
exit 0
else
echo "MISSING_NETWORKPOLICIES"
echo "[WARN] The following namespaces still lack NetworkPolicies (investigate manually):"
echo "${verify_ns_without_np}" | sed 's/^/ - /'
exit 1
fi