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

# The Default Namespace Should Not Be Used

### More Info:

Placing resources in the default namespace prevents applying tailored policies and RBAC boundaries. New resources should be created in specific, purpose-built namespaces.

### Risk Level

Low

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List all non-system workloads in the default namespace
           * Run on: any machine with kubectl access
           ```sh theme={null}
           kubectl get all -n default
           ```

        2. Decide target namespaces and create them if needed
           * Run on: any machine with kubectl access
           * Replace `team-a`, `team-b` with meaningful names for your org:
           ```sh theme={null}
           kubectl create namespace team-a
           kubectl create namespace team-b
           ```
           * Repeat as required for each logical application/team boundary.

        3. For each non-system resource in `default`, export its manifest and re‑create it in the correct namespace
           * Run on: any machine with kubectl access
           * Example for a deployment `myapp` you want in `team-a`:
           ```sh theme={null}
           kubectl get deployment myapp -n default -o yaml \
             | sed 's/namespace: default/namespace: team-a/' \
             | sed '/resourceVersion:/d;/uid:/d;/creationTimestamp:/d;/selfLink:/d;/managedFields:/d' \
             | kubectl apply -f -
           kubectl delete deployment myapp -n default
           ```
           * Use the same pattern for other types (e.g., `svc`, `statefulset`, `daemonset`, `job`, `cronjob`), adjusting the kind and name:
           ```sh theme={null}
           # example for a service
           kubectl get service myapp-svc -n default -o yaml \
             | sed 's/namespace: default/namespace: team-a/' \
             | sed '/resourceVersion:/d;/uid:/d;/creationTimestamp:/d;/selfLink:/d;/managedFields:/d' \
             | kubectl apply -f -
           kubectl delete service myapp-svc -n default
           ```

        4. For workloads that must remain cluster-scoped or in `kube-system`, do not move them
           * Run on: any machine with kubectl access
           * Before moving anything, confirm it is not a core component:
           ```sh theme={null}
           kubectl get all -A | grep -E 'kube-system|kube-public|kube-node-lease'
           ```
           * If you are unsure whether an object in `default` is application-specific or required by an addon, consult your platform documentation or application owners before moving it.

        5. Update CI/CD, Helm values, and manifests so new resources are not created in `default`
           * In all deployment manifests, ensure either:
             * `metadata.namespace: <desired-namespace>` is set, or
             * You deploy with an explicit namespace flag, for example:
               ```sh theme={null}
               kubectl apply -n team-a -f app.yaml
               ```
           * For Helm charts, set a non-default namespace:
             ```sh theme={null}
             helm install myapp ./chart-path --namespace team-a --create-namespace
             ```

        6. Verification: confirm the default namespace has no non-system resources
           * Run on: any machine with kubectl access
           ```sh theme={null}
           output=$(kubectl get all -n default --no-headers 2>/dev/null | grep -v '^service\s\+kubernetes\s' || true)
           if [ -z "$output" ]; then echo "DEFAULT_NAMESPACE_UNUSED"; else echo "DEFAULT_NAMESPACE_IN_USE"; fi
           ```
      </Accordion>

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

        1. List what is currently in the default namespace (for planning and decisions):

        ```bash theme={null}
        kubectl get all -n default
        kubectl get configmap,secret,sa,role,rolebinding,networkpolicy -n default
        ```

        2. Create purpose-specific namespaces (example: `team-a` and `platform`):

        ```bash theme={null}
        cat << 'EOF' > namespaces.yaml
        apiVersion: v1
        kind: Namespace
        metadata:
          name: team-a
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: platform
        EOF

        kubectl apply -f namespaces.yaml
        ```

        3. For each workload in `default`, re-create it in an appropriate namespace. Example for a deployment and service currently in default:

        Export manifests (edit to adjust `metadata.namespace` and any references before applying):

        ```bash theme={null}
        kubectl get deploy my-app -n default -o yaml > my-app-deploy.yaml
        kubectl get svc my-app -n default -o yaml > my-app-svc.yaml
        ```

        Edit both files:

        * Change `metadata.namespace: default` to `metadata.namespace: team-a`
        * Remove cluster-assigned fields (`status`, `metadata.resourceVersion`, `metadata.uid`, `metadata.creationTimestamp`, `metadata.managedFields`) and any `ownerReferences` that no longer apply.

        Then apply in the target namespace:

        ```bash theme={null}
        kubectl apply -f my-app-deploy.yaml
        kubectl apply -f my-app-svc.yaml
        ```

        4. After new workloads are running in non-default namespaces and you have validated functionality, delete objects from the default namespace (except the `kubernetes` service):

        ```bash theme={null}
        # Delete non-kubernetes services in default
        kubectl get svc -n default --no-headers | awk '$1 != "kubernetes" {print $1}' | \
          xargs -r kubectl delete svc -n default

        # Delete deployments, replicasets, pods, jobs, cronjobs, daemonsets, statefulsets
        kubectl delete deploy,rs,pod,job,cronjob,ds,sts --all -n default

        # Optionally clean up non-system configmaps/secrets/serviceaccounts, after review:
        kubectl delete configmap --all -n default
        kubectl delete secret --all -n default
        kubectl delete sa --all -n default
        kubectl delete role,rolebinding,networkpolicy --all -n default
        ```

        5. Update your workflows so new resources are not created in `default`, for example by always specifying `-n <namespace>` or `metadata.namespace` in manifests, and by configuring tooling defaults.

        6. Verification (same logic as the audit):

        ```bash theme={null}
        output=$(kubectl get all -n default --no-headers 2>/dev/null | grep -v '^service\s\+kubernetes\s' || true)
        if [ -z "$output" ]; then echo "DEFAULT_NAMESPACE_UNUSED"; else echo "DEFAULT_NAMESPACE_IN_USE"; fi
        ```
      </Accordion>

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

        # This script requires:
        # - kubectl configured and authorized
        # - jq and kubectl-neat (optional but recommended for cleaner manifests)

        # CONFIGURATION: map old namespace "default" -> new target namespaces by label selector
        # Each entry: "label_selector:new_namespace"
        # Example: move all pods with app=web to namespace web, etc.
        # Adjust to your environment and policies.
        MAPPINGS=(
          "app=web:web"
          "app=api:api"
        )

        # Helper: ensure a namespace exists
        ensure_namespace() {
          local ns="$1"
          if ! kubectl get namespace "${ns}" >/dev/null 2>&1; then
            kubectl create namespace "${ns}"
          fi
        }

        # Helper: move namespaced resources from default to a given namespace based on label selector
        migrate_resources() {
          local selector="$1"
          local target_ns="$2"

          ensure_namespace "${target_ns}"

          # List all resource types that are namespaced
          local types
          types=$(kubectl api-resources --namespaced=true --verbs=list -o name)

          for t in $types; do
            # Skip resources that shouldn't be moved generically
            case "$t" in
              events.k8s.io/*|events|leases.coordination.k8s.io|leases.coordination.k8s.io/*) continue ;;
            esac

            # Get resources in default matching selector
            local names
            names=$(kubectl get "$t" -n default -l "${selector}" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
            [ -z "$names" ] && continue

            for name in $names; do
              # Export resource manifest
              if command -v kubectl-neat >/dev/null 2>&1; then
                manifest=$(kubectl get "$t" "$name" -n default -o yaml | kubectl-neat)
              else
                manifest=$(kubectl get "$t" "$name" -n default -o yaml)
              fi

              # Patch namespace and remove fields that prevent re-create
              cleaned=$(printf '%s\n' "$manifest" \
                | sed -E '/^(status:|metadata:)/,/^[^ ]/!b' \
                | sed -E '/^  (creationTimestamp|resourceVersion|uid|selfLink|generation|managedFields|ownerReferences):/d' \
                | sed -E 's/namespace: default/namespace: '"${target_ns}"'/' )

              # Apply in target namespace and delete original
              printf '%s\n' "$cleaned" | kubectl apply -f -
              kubectl delete "$t" "$name" -n default --ignore-not-found
            done
          done
        }

        # MAIN

        # 1. Migrate resources from default namespace according to mappings
        for entry in "${MAPPINGS[@]}"; do
          IFS=":" read -r selector ns <<<"$entry"
          migrate_resources "$selector" "$ns"
        done

        # 2. Final verification: ensure default namespace has no workload resources
        output=$(kubectl get all -n default --no-headers 2>/dev/null | grep -v '^service\s\+kubernetes\s' || true)

        if [ -z "$output" ]; then
          echo "DEFAULT_NAMESPACE_UNUSED"
        else
          echo "DEFAULT_NAMESPACE_IN_USE"
          echo "The following resources remain in the default namespace:"
          echo "$output"
          echo "Review and decide manually where each should be moved, then re-run this script after updating MAPPINGS."
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
