> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Every Non-System Namespace Should Have A Default-Deny NetworkPolicy

### More Info:

Verifies each application namespace has a default-deny ingress NetworkPolicy. Without one, every pod is reachable from every other pod.

### Risk Level

High

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List non-system namespaces missing a default-deny NetworkPolicy**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           nps=$(kubectl get networkpolicies --all-namespaces -o json)
           kubectl get namespaces -o json | jq -r --argjson nps "$nps" '
             [ .items[]
             | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ $nps.items[]
                  | select(.metadata.namespace == $m.name)
                  | select((.spec.podSelector == {}) or (.spec.podSelector.matchLabels == null and .spec.podSelector.matchExpressions == null))
                  | select((.spec.policyTypes // []) | index("Ingress")) ] | length) as $deny
             | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $labels == "" then "" else " labels=\($labels)" end)
               + " defaultDenyPolicies=\($deny)"
               + " is_compliant=\(if $deny > 0 then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end' \
           | grep 'is_compliant=false' || true
           ```

        2. **Pick one non-compliant application namespace to fix**\
           From the previous output, note the value after `name=` for each line with `is_compliant=false`. Choose one namespace (for example `app-namespace`) and substitute that name exactly in the following commands.

        3. **Create a default-deny ingress NetworkPolicy manifest for that namespace**\
           Run on: any machine with kubectl access (local file creation)
           ```bash theme={null}
           cat > default-deny-ingress-app-namespace.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: default-deny-ingress
             namespace: app-namespace
           spec:
             podSelector: {}
             policyTypes:
               - Ingress
           EOF
           ```
           Replace **every** occurrence of `app-namespace` with the actual namespace name you are fixing.

        4. **Apply the default-deny ingress NetworkPolicy**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl apply -f default-deny-ingress-app-namespace.yaml
           ```

        5. **Repeat for remaining non-compliant namespaces**\
           For each other namespace shown with `is_compliant=false`, repeat steps 3–4, adjusting the filename and the `namespace:` field each time (or reuse the same filename and overwrite it before each `kubectl apply`).

        6. **Verify all non-system namespaces now have a default-deny ingress NetworkPolicy**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           nps=$(kubectl get networkpolicies --all-namespaces -o json)
           kubectl get namespaces -o json | jq -r --argjson nps "$nps" '
             [ .items[]
             | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ $nps.items[]
                  | select(.metadata.namespace == $m.name)
                  | select((.spec.podSelector == {}) or (.spec.podSelector.matchLabels == null and .spec.podSelector.matchExpressions == null))
                  | select((.spec.policyTypes // []) | index("Ingress")) ] | length) as $deny
             | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $labels == "" then "" else " labels=\($labels)" end)
               + " defaultDenyPolicies=\($deny)"
               + " is_compliant=\(if $deny > 0 then "true" else "false" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
           Confirm there are no lines with `is_compliant=false`.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Identify non-system namespaces that lack a default-deny ingress NetworkPolicy
        # Run on: any machine with kubectl access
        nps=$(kubectl get networkpolicies --all-namespaces -o json)
        kubectl get namespaces -o json | jq -r --argjson nps "$nps" '
          [ .items[]
          | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | ([ $nps.items[]
               | select(.metadata.namespace == $m.name)
               | select((.spec.podSelector == {}) or (.spec.podSelector.matchLabels == null and .spec.podSelector.matchExpressions == null))
               | select((.spec.policyTypes // []) | index("Ingress")) ] | length) as $deny
          | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
            + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
            + (if $labels == "" then "" else " labels=\($labels)" end)
            + " defaultDenyPolicies=\($deny)"
            + " is_compliant=\(if $deny > 0 then "true" else "false" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end' | \
          awk '$0 ~ /is_compliant=false/ {for (i=1;i<=NF;i++) if ($i ~ /^name=/){split($i,a,"="); print a[2]}}' \
          > /tmp/namespaces-missing-default-deny.txt

        cat /tmp/namespaces-missing-default-deny.txt
        ```

        Create a manifest template for the default-deny ingress NetworkPolicy:

        ```bash theme={null}
        # 2) Create a manifest template (edit as needed for naming conventions)
        # Run on: any machine with kubectl access
        cat > /tmp/default-deny-ingress-networkpolicy.yaml << 'EOF'
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
        EOF
        ```

        Apply the default-deny ingress NetworkPolicy to each non-compliant namespace:

        ```bash theme={null}
        # 3) Apply to each listed namespace
        # Run on: any machine with kubectl access
        while read ns; do
          [ -z "$ns" ] && continue
          echo "Applying default-deny ingress NetworkPolicy to namespace: $ns"
          kubectl apply -n "$ns" -f /tmp/default-deny-ingress-networkpolicy.yaml
        done < /tmp/namespaces-missing-default-deny.txt
        ```

        Verification:

        ```bash theme={null}
        # 4) Re-run the audit to confirm every non-system namespace has a default-deny ingress policy
        # Run on: any machine with kubectl access
        nps=$(kubectl get networkpolicies --all-namespaces -o json)
        kubectl get namespaces -o json | jq -r --argjson nps "$nps" '
          [ .items[]
          | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | ([ $nps.items[]
               | select(.metadata.namespace == $m.name)
               | select((.spec.podSelector == {}) or (.spec.podSelector.matchLabels == null and .spec.podSelector.matchExpressions == null))
               | select((.spec.policyTypes // []) | index("Ingress")) ] | length) as $deny
          | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
            + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
            + (if $labels == "" then "" else " labels=\($labels)" end)
            + " defaultDenyPolicies=\($deny)"
            + " is_compliant=\(if $deny > 0 then "true" else "false" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Automation: Ensure every non-system namespace has a default-deny ingress NetworkPolicy
        # Scope: run on any machine with kubectl access and a current kube-context

        set -euo pipefail

        # Name of the default-deny NetworkPolicy to create/ensure in each namespace
        NP_NAME="default-deny-ingress"

        # 1. Discover target namespaces (exclude core system namespaces)
        echo "Discovering non-system namespaces..."
        mapfile -t TARGET_NAMESPACES < <(
          kubectl get namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
          | grep -Ev '^(kube-system|kube-public|kube-node-lease)$' \
          | sort
        )

        if [ "${#TARGET_NAMESPACES[@]}" -eq 0 ]; then
          echo "No non-system namespaces found. Nothing to do."
          exit 0
        fi

        # 2. Ensure a default-deny ingress NetworkPolicy exists in each namespace
        for ns in "${TARGET_NAMESPACES[@]}"; do
          echo "Ensuring default-deny ingress NetworkPolicy in namespace: ${ns}"

          # Idempotent apply: creates if absent, updates if present
          cat <<EOF | kubectl apply -f -
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: ${NP_NAME}
          namespace: ${ns}
        spec:
          podSelector: {}        # Selects all pods in the namespace
          policyTypes:
            - Ingress
          # No ingress rules defined -> deny all ingress traffic by default
        EOF

        done

        # 3. Verification: re-run the benchmark-style logic to confirm compliance
        echo "Verifying that every non-system namespace has at least one default-deny ingress NetworkPolicy..."

        nps_json="$(kubectl get networkpolicies --all-namespaces -o json)"
        kubectl get namespaces -o json | jq -r --argjson nps "$nps_json" '
          [ .items[]
          | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | ([ $nps.items[]
               | select(.metadata.namespace == $m.name)
               | select((.spec.podSelector == {}) or (.spec.podSelector.matchLabels == null and .spec.podSelector.matchExpressions == null))
               | select((.spec.policyTypes // []) | index("Ingress")) ] | length) as $deny
          | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
            + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
            + (if $labels == "" then "" else " labels=\($labels)" end)
            + " defaultDenyPolicies=\($deny)"
            + " is_compliant=\(if $deny > 0 then "true" else "false" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end
        '

        echo "Verification complete. Review the 'is_compliant' field above; all non-system namespaces should report is_compliant=true."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
