Skip to main content

Ensure That All Namespaces Have Network Policies Defined

More Info:​

Namespaces without NetworkPolicies allow unrestricted pod-to-pod traffic. Define at least one NetworkPolicy in each namespace to control and restrict traffic.

Risk Level​

High

Address​

Security

Compliance Standards​

  • CIS EKS

Triage and Remediation​

Remediation​

Manual Steps
  1. List namespaces that currently have no NetworkPolicies (run on any machine with kubectl access):

    ns_without_np=$(kubectl get namespaces -o json | jq -r '.items[].metadata.name' | while read ns; do
    count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l)
    if [ "$count" -eq 0 ]; then echo "$ns"; fi
    done)
    echo "$ns_without_np"
  2. For each namespace without a NetworkPolicy, review what should be allowed:

    • Ingress: which pods/services (by label, namespace, IPs) may talk to pods in this namespace?
    • Egress: which external destinations (namespaces, services, CIDRs, ports) are required? Use these answers to decide labels, ports, and CIDR ranges for your policies.
  3. (Optional but recommended) Label workloads in a target namespace so policies can select them. For example, in namespace example-namespace (run on any machine with kubectl access):

    kubectl -n example-namespace get pods --no-headers -o custom-columns='NAME:.metadata.name' | while read pod; do
    kubectl -n example-namespace label pod "$pod" role=app --overwrite
    done
  4. Create a default deny-all ingress and egress NetworkPolicy for each selected namespace, adjusting namespace and labels as appropriate (run on any machine with kubectl access). Example for example-namespace:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: default-deny-all
    namespace: example-namespace
    spec:
    podSelector: {} # selects all pods in this namespace
    policyTypes:
    - Ingress
    - Egress
    EOF
  5. Add specific allow NetworkPolicies where needed so applications continue to function. For example, allow ingress HTTP traffic from same namespace to pods labeled role=app in example-namespace (run on any machine with kubectl access):

    cat << 'EOF' | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: allow-http-same-namespace
    namespace: example-namespace
    spec:
    podSelector:
    matchLabels:
    role: app
    policyTypes:
    - Ingress
    ingress:
    - from:
    - podSelector: {} # any pod in this namespace
    ports:
    - protocol: TCP
    port: 80
    EOF

    Repeat with additional policies for other required ports, sources, or egress as identified in step 2.

  6. Verify that every namespace has at least one NetworkPolicy (run on any machine with kubectl access):

    ns_without_np=$(kubectl get namespaces -o json | jq -r '.items[].metadata.name' | while read ns; do
    count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l)
    if [ "$count" -eq 0 ]; then echo "$ns"; fi
    done)
    if [ -z "$ns_without_np" ]; then
    echo "ALL_NAMESPACES_HAVE_NETWORK_POLICIES"
    else
    echo "NAMESPACES_WITHOUT_NETWORK_POLICIES: $ns_without_np"
    fi
Using kubectl
# 1) Identify namespaces without any NetworkPolicy
# Run on: any machine with kubectl access
ns_without_np=$(kubectl get namespaces -o json | jq -r '.items[].metadata.name' | while read ns; do
count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l)
if [ "$count" -eq 0 ]; then echo "$ns"; fi
done)
echo "$ns_without_np"
# 2) Create a baseline default-deny-all-ingress policy in each namespace that lacks NetworkPolicies
# Adjust/add more specific policies later as needed for your applications.
# Run on: any machine with kubectl access

for ns in $ns_without_np; do
cat <<EOF | kubectl apply -n "$ns" -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: $ns
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
done
# 3) Optional: create a stricter baseline (deny all ingress and egress)
# WARNING: This can break cross-namespace or external connectivity for pods in these namespaces.
# Run on: any machine with kubectl access

for ns in $ns_without_np; do
cat <<EOF | kubectl apply -n "$ns" -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: $ns
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
done
# 4) Verification: confirm every namespace now has at least one NetworkPolicy
# Run on: any machine with kubectl access

ns_without_np=$(kubectl get namespaces -o json | jq -r '.items[].metadata.name' | while read ns; do
count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l)
if [ "$count" -eq 0 ]; then echo "$ns"; fi
done)

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

# This script:
# - Ensures every namespace has at least one NetworkPolicy
# - Creates a default-deny-all NetworkPolicy in any namespace missing policies
# - Skips kube-system and other core namespaces where you may not want default-deny
# - Is safe to re-run (idempotent)
#
# Run from any machine with kubectl access and a current context pointing at the cluster.

# -------- Configuration --------
# Comma-separated namespaces to SKIP from automatic default-deny policies.
# Adjust as appropriate for your cluster.
SKIP_NAMESPACES="kube-system,kube-public,default,local-path-storage,ingress-nginx"

# Name of the default policy to create (if none exist in a namespace)
DEFAULT_POLICY_NAME="default-deny-all"

# --------------------------------

IFS=',' read -r -a SKIP_ARRAY <<< "$SKIP_NAMESPACES"

ns_in_skip_list() {
local ns="$1"
for s in "${SKIP_ARRAY[@]}"; do
if [[ "$ns" == "$s" ]]; then
return 0
fi
done
return 1
}

echo "Discovering namespaces without any NetworkPolicy..."
ns_without_np=()

# Collect namespaces with zero NetworkPolicies
while read -r ns; do
# Skip terminating namespaces
phase=$(kubectl get ns "$ns" -o jsonpath='{.status.phase}')
if [[ "$phase" != "Active" ]]; then
continue
fi

count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')
if [[ "$count" -eq 0 ]]; then
ns_without_np+=("$ns")
fi
done < <(kubectl get namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

if [[ ${#ns_without_np[@]} -eq 0 ]]; then
echo "All namespaces already have at least one NetworkPolicy."
else
echo "Namespaces with no NetworkPolicy: ${ns_without_np[*]}"
fi

for ns in "${ns_without_np[@]}"; do
if ns_in_skip_list "$ns"; then
echo "Skipping namespace '$ns' (in skip list); please define NetworkPolicies manually if desired."
continue
fi

echo "Creating default-deny-all NetworkPolicy in namespace '$ns'..."

# Apply an idempotent default deny-all policy (ingress and egress)
# Safe to re-run: same name, full manifest.
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ${DEFAULT_POLICY_NAME}
namespace: ${ns}
spec:
podSelector: {} # applies to all pods in this namespace
policyTypes:
- Ingress
- Egress
ingress: [] # deny all ingress
egress: [] # deny all egress
EOF

done

echo
echo "Verifying that all namespaces now have at least one NetworkPolicy..."

verify_ns_without_np=$(kubectl get namespaces -o json | jq -r '.items[].metadata.name' | 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)

if [ -z "$verify_ns_without_np" ]; then
echo "ALL_NAMESPACES_HAVE_NETWORK_POLICIES"
else
echo "NAMESPACES_WITHOUT_NETWORK_POLICIES (manual review required or skipped by config): $verify_ns_without_np"
echo "Review these namespaces and create appropriate NetworkPolicies as needed."
fi