> ## 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.

# Ensure All Namespaces Have Network Policies Defined

### More Info:

Namespaces without NetworkPolicy objects allow unrestricted pod-to-pod traffic. Every namespace holding user workloads should have at least one NetworkPolicy defined.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List namespaces missing NetworkPolicy objects**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
           | jq -rs '
             (.[0].items | map(.metadata.name)
              | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))) as $ns
             |
             ( (.[1].items // [])
               | sort_by(.metadata.namespace)
               | group_by(.metadata.namespace)
               | map({key: .[0].metadata.namespace, value: length})
               | from_entries
             ) as $np
             |
             [ $ns[] | select( ($np[.] // 0) == 0 ) ] as $missing
             |
             $missing[]
           '
           ```
           Save the output list of namespaces; you will create at least one NetworkPolicy in each.

        2. **For a selected namespace, create a baseline “default deny ingress” NetworkPolicy**\
           Run on: any machine with kubectl access\
           Replace `TARGET_NAMESPACE` with the namespace you are fixing (for each namespace, repeat with its name):
           ```bash theme={null}
           cat > default-deny-ingress-TARGET_NAMESPACE.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: default-deny-ingress
             namespace: TARGET_NAMESPACE
           spec:
             podSelector: {}
             policyTypes:
               - Ingress
           EOF

           sed -i 's/TARGET_NAMESPACE/your-namespace-name/g' default-deny-ingress-your-namespace-name.yaml
           kubectl apply -f default-deny-ingress-your-namespace-name.yaml
           ```

        3. **(Optional but recommended) Add a default deny egress policy for the namespace**\
           Run on: any machine with kubectl access\
           Replace `TARGET_NAMESPACE` with the namespace name:
           ```bash theme={null}
           cat > default-deny-egress-TARGET_NAMESPACE.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: default-deny-egress
             namespace: TARGET_NAMESPACE
           spec:
             podSelector: {}
             policyTypes:
               - Egress
           EOF

           sed -i 's/TARGET_NAMESPACE/your-namespace-name/g' default-deny-egress-your-namespace-name.yaml
           kubectl apply -f default-deny-egress-your-namespace-name.yaml
           ```

        4. **(Optional) Create explicit allow policies to restore required traffic**\
           Run on: any machine with kubectl access\
           Example: allow all pods in the same namespace to talk to each other (adapt as needed per application):
           ```bash theme={null}
           cat > allow-same-namespace-TARGET_NAMESPACE.yaml << 'EOF'
           apiVersion: networking.k8s.io/v1
           kind: NetworkPolicy
           metadata:
             name: allow-same-namespace
             namespace: TARGET_NAMESPACE
           spec:
             podSelector: {}
             ingress:
               - from:
                   - podSelector: {}
             policyTypes:
               - Ingress
           EOF

           sed -i 's/TARGET_NAMESPACE/your-namespace-name/g' allow-same-namespace-your-namespace-name.yaml
           kubectl apply -f allow-same-namespace-your-namespace-name.yaml
           ```

        5. **Repeat for all namespaces that were missing NetworkPolicies**\
           Run on: any machine with kubectl access\
           For each namespace identified in step 1, create at least one NetworkPolicy (for example, the default deny policies plus any needed allow rules) by repeating steps 2–4 with the appropriate namespace name.

        6. **Verify all namespaces now have at least one NetworkPolicy**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
           | jq -rs '
             (.[0].items | map(.metadata.name)
              | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))) as $ns
             |
             ( (.[1].items // [])
               | sort_by(.metadata.namespace)
               | group_by(.metadata.namespace)
               | map({key: .[0].metadata.namespace, value: length})
               | from_entries
             ) as $np
             |
             [ $ns[] | select( ($np[.] // 0) == 0 ) ] as $missing
             |
             if ($missing|length)>0
             then ($missing[] | "FOUND_NAMESPACE_WITHOUT_NETWORKPOLICY:"+.)
             else "ALL_NAMESPACES_HAVE_NETWORK_POLICIES"
             end
           '
           ```
           The check is remediated when the command prints `ALL_NAMESPACES_HAVE_NETWORK_POLICIES`.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1. Identify namespaces missing NetworkPolicies
        # Run on: any machine with kubectl access
        (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
        | jq -rs '
          (.[0].items | map(.metadata.name)
           | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))) as $ns
          |
          ( (.[1].items // [])
            | sort_by(.metadata.namespace)
            | group_by(.metadata.namespace)
            | map({key: .[0].metadata.namespace, value: length})
            | from_entries
          ) as $np
          |
          [ $ns[] | select( ($np[.] // 0) == 0 ) ] as $missing
          |
          if ($missing|length)>0
          then ($missing[] | .)
          else empty
          end
        '

        # Suppose the above prints a list like:
        # default
        # dev
        # prod
        # Replace this list explicitly in the manifest below.
        ```

        Create a baseline, **deny-all-ingress / allow-all-egress** NetworkPolicy for each workload namespace:

        ```bash theme={null}
        # 2. Create a manifest with one NetworkPolicy per affected namespace
        # Run on: any machine with kubectl access
        cat > baseline-namespace-networkpolicies.yaml << 'EOF'
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: default
        spec:
          podSelector: {}        # select all Pods in this namespace
          policyTypes:
            - Ingress
          ingress: []            # deny all ingress

        ---
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: dev
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
          ingress: []

        ---
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-ingress
          namespace: prod
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
          ingress: []
        EOF
        ```

        Apply the NetworkPolicies:

        ```bash theme={null}
        # 3. Apply the NetworkPolicy resources
        # Run on: any machine with kubectl access
        kubectl apply -f baseline-namespace-networkpolicies.yaml
        ```

        Verification (rerun the benchmark audit logic):

        ```bash theme={null}
        # 4. Verify all non-system namespaces now have at least one NetworkPolicy
        # Run on: any machine with kubectl access
        (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
        | jq -rs '
          (.[0].items | map(.metadata.name)
           | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))) as $ns
          |
          ( (.[1].items // [])
            | sort_by(.metadata.namespace)
            | group_by(.metadata.namespace)
            | map({key: .[0].metadata.namespace, value: length})
            | from_entries
          ) as $np
          |
          [ $ns[] | select( ($np[.] // 0) == 0 ) ] as $missing
          |
          if ($missing|length)>0
          then ($missing[] | "FOUND_NAMESPACE_WITHOUT_NETWORKPOLICY:"+.)
          else "ALL_NAMESPACES_HAVE_NETWORK_POLICIES"
          end
        '
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # Automation for CIS GKE 4.3.2:
        # Ensure each non-system namespace has at least one NetworkPolicy.
        # Runs from: any machine with kubectl access and jq installed.

        # CONFIG: label selector for namespaces to manage
        NS_SELECTOR='!name in (kube-system,kube-public,kube-node-lease)'

        # 1. Discover namespaces that currently have zero NetworkPolicies
        echo "[INFO] Discovering namespaces without NetworkPolicy objects..."

        MISSING_NS=$(
          (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
          | jq -rs '
              (.[0].items
               | map(.metadata.name)
               | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))
              ) as $ns
              |
              ( (.[1].items // [])
                | sort_by(.metadata.namespace)
                | group_by(.metadata.namespace)
                | map({key: .[0].metadata.namespace, value: length})
                | from_entries
              ) as $np
              |
              [ $ns[] | select( ($np[.] // 0) == 0 ) ][]'
        )

        if [[ -z "${MISSING_NS}" ]]; then
          echo "[INFO] ALL_NAMESPACES_HAVE_NETWORK_POLICIES (excluding kube-system, kube-public, kube-node-lease)"
          exit 0
        fi

        echo "[INFO] Namespaces without NetworkPolicy:"
        printf '  - %s\n' ${MISSING_NS}

        # 2. For each missing namespace, create a baseline NetworkPolicy if none exists.
        #    This example creates a default-deny-all policy. Review before use.
        #    You can customize per namespace by editing the manifest generation below.

        for NS in ${MISSING_NS}; do
          echo "[INFO] Processing namespace: ${NS}"

          # Double-check idempotency: skip if any NetworkPolicy now exists (race-safe).
          NP_COUNT=$(kubectl get networkpolicy -n "${NS}" --no-headers 2>/dev/null | wc -l || true)
          if [[ "${NP_COUNT}" -gt 0 ]]; then
            echo "[INFO] Namespace ${NS} already has NetworkPolicy objects; skipping creation."
            continue
          fi

          echo "[INFO] Creating baseline default-deny-all NetworkPolicy in namespace ${NS}"

          # Apply a default-deny policy using kubectl apply (idempotent).
          # Policy name is deterministic so re-runs are safe.
          cat <<EOF | kubectl apply -f -
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        metadata:
          name: default-deny-all
          namespace: ${NS}
        spec:
          podSelector: {}
          policyTypes:
            - Ingress
            - Egress
        EOF

        done

        # 3. Verification using the authoritative audit logic
        echo "[INFO] Verifying that all non-system namespaces now have at least one NetworkPolicy..."

        (kubectl get ns -o json; kubectl get networkpolicy -A -o json) \
        | jq -rs '
          (.[0].items | map(.metadata.name)
           | map(select(.!="kube-system" and .!="kube-public" and .!="kube-node-lease"))) as $ns
          |
          ( (.[1].items // [])
            | sort_by(.metadata.namespace)
            | group_by(.metadata.namespace)
            | map({key: .[0].metadata.namespace, value: length})
            | from_entries
          ) as $np
          |
          [ $ns[] | select( ($np[.] // 0) == 0 ) ] as $missing
          |
          if ($missing|length)>0
          then ($missing[] | "FOUND_NAMESPACE_WITHOUT_NETWORKPOLICY:"+.)
          else "ALL_NAMESPACES_HAVE_NETWORK_POLICIES"
          end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
