> ## 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 are not compliant (run on 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)"
             ][]' | grep 'is_compliant=false'
           ```

        2. For each non-compliant application namespace (replace `APPLICATION_NAMESPACE` with the actual name), create a default-deny ingress NetworkPolicy manifest file (run on any machine with kubectl access):
           ```bash theme={null}
           cat > default-deny-ingress-APPLICATION_NAMESPACE.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: default-deny-ingress
             namespace: APPLICATION_NAMESPACE
           spec:
             podSelector: {}
             policyTypes:
               - Ingress
           EOF
           ```

        3. Apply the default-deny NetworkPolicy to that namespace (run on any machine with kubectl access):
           ```bash theme={null}
           sed "s/APPLICATION_NAMESPACE/your-namespace-name/g" \
             default-deny-ingress-APPLICATION_NAMESPACE.yaml | kubectl apply -f -
           ```

        4. (Optional but recommended) For each application, create additional NetworkPolicies in its namespace to allow only required ingress flows (run on any machine with kubectl access). For example, create a file:
           ```bash theme={null}
           cat > allow-namespace-APPLICATION_NAMESPACE.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: allow-required-ingress
             namespace: APPLICATION_NAMESPACE
           spec:
             podSelector:
               matchLabels:
                 app: your-app-label
             policyTypes:
               - Ingress
             ingress:
               - from:
                   - namespaceSelector:
                       matchLabels:
                         name: allowed-namespace
           EOF

           sed -e "s/APPLICATION_NAMESPACE/your-namespace-name/g" \
               -e "s/your-app-label/actual-app-label/g" \
               -e "s/allowed-namespace/actual-allowed-namespace-label/g" \
               allow-namespace-APPLICATION_NAMESPACE.yaml | kubectl apply -f -
           ```

        5. Repeat steps 2–4 for each non-system, non-compliant namespace reported in step 1.

        6. Verify that all non-system namespaces now have at least one default-deny ingress NetworkPolicy (run on 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'
           ```
           Confirm that there are no lines with `is_compliant=false`.
      </Accordion>

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

        1. Identify non-compliant namespaces (replace the jq path if needed, but this is the same logic as the audit):

        ```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
          | ([ $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
          | select($deny == 0)
          | .name' -r
        ```

        Assume this prints (example):

        ```text theme={null}
        team-a
        team-b
        ```

        2. Create a default-deny ingress NetworkPolicy manifest for each non-compliant namespace.

        Example for `team-a`:

        ```bash theme={null}
        cat << 'EOF' > default-deny-ingress-team-a.yaml
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: team-a
        spec:
          podSelector: {}
          policyTypes:
          - Ingress
        EOF
        ```

        Apply it:

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

        Repeat for each namespace that needs the policy, changing only the `namespace:` field and filename:

        ```bash theme={null}
        cat << 'EOF' > default-deny-ingress-team-b.yaml
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: team-b
        spec:
          podSelector: {}
          policyTypes:
          - Ingress
        EOF

        kubectl apply -f default-deny-ingress-team-b.yaml
        ```

        3. Verification (same logic as the audit, run from any machine with kubectl):

        ```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
        #
        # Apply a default-deny ingress NetworkPolicy to every non-system namespace
        # that does not already have one.
        #
        # Run on: any machine with kubectl access to the cluster.
        # Requirements: bash, kubectl, jq in PATH, current context pointing to target OKE cluster.

        set -euo pipefail

        # Namespaces to ignore (system namespaces)
        SYSTEM_NAMESPACES=(
          "kube-system"
          "kube-public"
          "kube-node-lease"
        )

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

        # Convert SYSTEM_NAMESPACES to jq array
        jq_sys_ns_array() {
          local first=1 out="["
          for ns in "${SYSTEM_NAMESPACES[@]}"; do
            if [ "$first" -eq 1 ]; then
              first=0
            else
              out+=","
            fi
            out+="\"$ns\""
          done
          out+="]"
          printf '%s\n' "$out"
        }

        main() {
          # Ensure we can talk to the cluster
          kubectl version --request-timeout='5s' >/dev/null 2>&1 || {
            echo "ERROR: kubectl cannot reach the cluster. Check context and network." >&2
            exit 1
          }

          # Get all namespaces except the system ones
          mapfile -t app_namespaces < <(
            kubectl get namespaces -o json | jq -r \
              --argjson sys "$(jq_sys_ns_array)" '
                .items[]
                | select(.metadata.name as $n | $sys | index($n) | not)
                | .metadata.name
              '
          )

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

          # For each application namespace, ensure a default-deny ingress NetworkPolicy exists
          for ns in "${app_namespaces[@]}"; do
            echo "Processing namespace: ${ns}"

            # Detect if there is already at least one default-deny ingress NetworkPolicy in this namespace
            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))
                           and ((.spec.policyTypes // []) | index("Ingress")))
                ] | length
              ' 2>/dev/null || echo "0"
            )"

            if [ "$existing_count" -gt 0 ]; then
              echo "  Namespace ${ns} already has a default-deny ingress NetworkPolicy (${existing_count} found); skipping creation."
              continue
            fi

            echo "  Creating ${NP_NAME} NetworkPolicy in namespace ${ns}"

            # Apply an idempotent default-deny ingress NetworkPolicy
            # Empty podSelector + policyTypes: [Ingress] -> deny all ingress by default.
            cat <<EOF | kubectl apply -f -
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: ${NP_NAME}
          namespace: ${ns}
        spec:
          podSelector: {}
          policyTypes:
          - Ingress
        EOF

          done

          echo
          echo "Verification (re-running benchmark-style audit):"

          {
            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
          '
        }

        main "$@"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
