> ## 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 that need a default-deny NetworkPolicy (run on any machine with kubectl access):
           ```sh theme={null}
           kubectl get namespaces \
             --no-headers \
             | awk '!/kube-system|kube-public|kube-node-lease/ {print $1}'
           ```

        2. For each application namespace that should be isolated (replace `my-namespace` with the actual namespace), create a default-deny ingress NetworkPolicy (run on any machine with kubectl access):
           ```sh theme={null}
           kubectl apply -n my-namespace -f - <<'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: default-deny-ingress
           spec:
             podSelector: {}
             policyTypes:
               - Ingress
           EOF
           ```

        3. (Optional but recommended) In each namespace where you created the default-deny policy, define explicit allow NetworkPolicies for the traffic that should be permitted (for example, allowing ingress from a specific namespace; run on any machine with kubectl access and adjust selectors as needed):
           ```sh theme={null}
           kubectl apply -n my-namespace -f - <<'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: allow-from-namespace-foo
           spec:
             podSelector: {}
             ingress:
               - from:
                   - namespaceSelector:
                       matchLabels:
                         name: foo
             policyTypes:
               - Ingress
           EOF
           ```

        4. Verify that each non-system namespace now has at least one default-deny ingress NetworkPolicy (run on any machine with kubectl access):
           ```sh theme={null}
           { kubectl get networkpolicies --all-namespaces -o json
             kubectl get namespaces -o json
           } | jq -rs '
             .[0] as $nps | .[1] |
             [ .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 that `is_compliant=true` is reported for the cluster and that each application namespace shows `defaultDenyPolicies` greater than 0.
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with `kubectl` access:

        1. List non-system namespaces that need a default-deny NetworkPolicy

        ```bash theme={null}
        kubectl get ns \
          --no-headers \
          | awk '!/kube-system|kube-public|kube-node-lease/ {print $1}'
        ```

        2. For each application namespace that is missing a default-deny ingress NetworkPolicy, create one. Example manifest (save as `default-deny-ingress.yaml` and apply per namespace):

        ```yaml theme={null}
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: example-namespace
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
        ```

        Apply it:

        ```bash theme={null}
        kubectl apply -f default-deny-ingress.yaml
        ```

        Or create it directly with `kubectl` (replace `example-namespace` each time):

        ```bash theme={null}
        kubectl apply -n example-namespace -f - <<'EOF'
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
        EOF
        ```

        3. Verification

        Re-run the check (same logic as the audit) from any machine with `kubectl` access:

        ```bash theme={null}
        { kubectl get networkpolicies --all-namespaces -o json
          kubectl get namespaces -o json
        } | jq -rs '
          .[0] as $nps | .[1] |
          [ .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
        #
        # Enforce default-deny ingress NetworkPolicy in every non-system namespace
        # that does not already have one.
        #
        # Requirements:
        #   - Run on any machine with kubectl access and current context set to target AKS cluster.
        #   - kubectl, jq must be installed.

        set -euo pipefail

        # Name of the default-deny NetworkPolicy we will manage
        DEFAULT_DENY_NP_NAME="default-deny-ingress"

        echo "Discovering non-system namespaces..."
        # Get all non-system namespaces: exclude kube-system, kube-public, kube-node-lease
        mapfile -t APP_NAMESPACES < <(
          kubectl get namespaces -o json \
          | jq -r '.items[]
                   | select(.metadata.name as $n
                            | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
                   | .metadata.name'
        )

        if [ "${#APP_NAMESPACES[@]}" -eq 0 ]; then
          echo "No non-system namespaces found. Nothing to do."
        else
          echo "Non-system namespaces: ${APP_NAMESPACES[*]}"
        fi

        for ns in "${APP_NAMESPACES[@]}"; do
          echo "Processing namespace: ${ns}"

          # Check if a qualifying default-deny ingress NetworkPolicy already exists
          existing_count="$(
            kubectl get networkpolicies -n "${ns}" -o json 2>/dev/null \
            | jq '[ .items[]
                    | select(
                        ((.spec.podSelector // {}) == {})
                        or (.spec.podSelector.matchLabels == null
                            and .spec.podSelector.matchExpressions == null)
                      )
                    | select((.spec.policyTypes // []) | index("Ingress"))
                  ] | length'
          )" || existing_count="0"

          if [ "${existing_count}" != "0" ]; then
            echo "  Namespace ${ns} already has at least one default-deny ingress NetworkPolicy (${existing_count} found). Skipping creation."
            continue
          fi

          echo "  No default-deny ingress NetworkPolicy found in ${ns}. Creating ${DEFAULT_DENY_NP_NAME}..."

          # Apply an idempotent default-deny ingress NetworkPolicy manifest
          cat <<EOF | kubectl apply -f -
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: ${DEFAULT_DENY_NP_NAME}
          namespace: ${ns}
          labels:
            security.cloud-bp/controls: "C3.1"
        spec:
          podSelector: {}
          policyTypes:
          - Ingress
        EOF

        done

        echo
        echo "Verifying compliance using the benchmark audit logic..."

        # Re-run the audit logic (adapted from the provided command)
        { kubectl get networkpolicies --all-namespaces -o json
          kubectl get namespaces -o json
        } | jq -rs '
          .[0] as $nps | .[1] |
          [ .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
        echo "Verification complete. Ensure all non-system namespaces report is_compliant=true."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
