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

Kubernetes provides a default namespace, where objects are placed if no namespace is specified for them. Placing objects in this namespace makes application of RBAC and other controls more difficult.

### Risk Level

Low

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS EKS
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List all user resources in the default namespace**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) \
             --ignore-not-found -n default
           ```

        2. **Decide target namespaces and create them if needed**\
           For each logical application/group of resources, pick or create a dedicated namespace.\
           Example (adjust names as needed):
           ```bash theme={null}
           kubectl create namespace app-frontend
           kubectl create namespace app-backend
           ```
           If a namespace already exists, you do not need to recreate it:
           ```bash theme={null}
           kubectl get namespace
           ```

        3. **Export manifests of resources currently in the default namespace**\
           Run once per resource type you want to move; redirect to files for review/edit.\
           Examples (adjust types as needed based on step 1 output):
           ```bash theme={null}
           kubectl get deploy,sts,ds,svc,ing,cm,secret,sa,job,cronjob -n default -o yaml > default-workloads.yaml
           kubectl get pvc -n default -o yaml > default-pvc.yaml
           ```
           Review these files in an editor and for each object:
           * Change `metadata.namespace: default` to the desired namespace.
           * Adjust names/labels/annotations if you need to separate apps into different namespaces.
           * For `ServiceAccountName`, `ConfigMap`, `Secret`, `RoleBinding`, etc., ensure referenced objects will also exist in the new namespace.

        4. **Recreate resources in their new namespaces**\
           After editing the exported files, apply them:
           ```bash theme={null}
           kubectl apply -f default-workloads.yaml
           kubectl apply -f default-pvc.yaml
           ```
           Confirm they exist in the new namespaces:
           ```bash theme={null}
           kubectl get all -n app-frontend
           kubectl get all -n app-backend
           ```

        5. **Delete migrated resources from the default namespace**\
           Only after confirming that workloads are running correctly in their new namespaces, delete the originals.\
           Example (adjust types/names as needed; you can use `--all` where appropriate):
           ```bash theme={null}
           kubectl delete deploy,sts,ds,svc,ing,cm,secret,sa,job,cronjob -n default --all
           kubectl delete pvc -n default --all
           ```
           Be careful not to delete any system-created objects; inspect with:
           ```bash theme={null}
           kubectl get all,cm,secret,sa,role,rolebinding,pvc -n default
           ```

        6. **Verification (no user resources left in default namespace)**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           output=$(kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) --ignore-not-found -n default 2>/dev/null | grep -v "^kubernetes ")
           if [ -z "$output" ]; then
             echo "NO_USER_RESOURCES_IN_DEFAULT"
           else
             echo "USER_RESOURCES_IN_DEFAULT_FOUND: $output"
           fi
           ```
      </Accordion>

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

        1. Identify all user resources in the default namespace

        ```bash theme={null}
        kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) \
          --ignore-not-found -n default \
          -o wide
        ```

        2. For each application, create a dedicated namespace (example: `my-app`)

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: v1
        kind: Namespace
        metadata:
          name: my-app
        EOF
        ```

        3. Export and re-apply namespaced resources into the new namespace\
           (adapt `my-app` and resource selectors as needed)

        ```bash theme={null}
        # Example: move deployments, services, configmaps, secrets for one app label
        kubectl get deploy,svc,configmap,secret \
          -n default -l app=my-app \
          -o yaml \
        | sed 's/namespace: default/namespace: my-app/g' \
        | sed '/^\s*uid:/d;/^\s*resourceVersion:/d;/^\s*creationTimestamp:/d;/^\s*selfLink:/d;/^\s*managedFields:/d' \
        | kubectl apply -f -
        ```

        4. Delete the old copies from the default namespace\
           (ensure the app is healthy in the new namespace first)

        ```bash theme={null}
        kubectl delete deploy,svc,configmap,secret \
          -n default -l app=my-app
        ```

        Repeat steps 2–4 for each application currently using the `default` namespace, choosing an appropriate namespace name and label selector.

        5. (Optional) Add a warning label/annotation to discourage use of default namespace

        ```bash theme={null}
        kubectl label namespace default usage=discouraged --overwrite
        kubectl annotate namespace default \
          "note=do-not-deploy-user-workloads-here" \
          --overwrite
        ```

        6. Verification

        ```bash theme={null}
        output=$(kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) --ignore-not-found -n default 2>/dev/null | grep -v "^kubernetes ")
        if [ -z "$output" ]; then
          echo "NO_USER_RESOURCES_IN_DEFAULT"
        else
          echo "USER_RESOURCES_IN_DEFAULT_FOUND: $output"
        fi
        ```
      </Accordion>

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

        # Automation for: "The Default Namespace Should Not Be Used"
        # Scope: run on any machine with kubectl access and correct context.
        #
        # Behavior:
        # - Detect all namespaced resources currently in the "default" namespace
        # - For each resource, interactively choose a non-default target namespace
        #   (creating it if necessary)
        # - Move the resource by exporting manifest, adjusting metadata.namespace
        #   and metadata.annotations, then re-creating in the target namespace
        #   and deleting the original
        # - Safe to re-run: already-moved resources will not be in "default"
        # - Final verification uses the benchmark's audit logic

        # --------------- helper functions ---------------

        require_kubectl() {
          if ! command -v kubectl >/dev/null 2>&1; then
            echo "ERROR: kubectl not found in PATH" >&2
            exit 1
          fi
        }

        prompt_namespace() {
          local current_ns="$1"
          local target_ns
          while true; do
            read -r -p "Enter target namespace for resources currently in '${current_ns}' (not 'default'): " target_ns
            target_ns="${target_ns:-}"
            if [[ -z "${target_ns}" ]]; then
              echo "Namespace cannot be empty."
              continue
            fi
            if [[ "${target_ns}" == "default" ]]; then
              echo "Target namespace must not be 'default'."
              continue
            fi
            echo "${target_ns}"
            return 0
          done
        }

        ensure_namespace_exists() {
          local ns="$1"
          if ! kubectl get namespace "${ns}" >/dev/null 2>&1; then
            echo "Creating namespace '${ns}'..."
            kubectl create namespace "${ns}"
          else
            echo "Namespace '${ns}' already exists."
          fi
        }

        move_resource() {
          local kind="$1"
          local name="$2"
          local src_ns="$3"
          local dst_ns="$4"

          echo "Moving ${kind}/${name} from namespace '${src_ns}' to '${dst_ns}'..."

          # Export the resource as YAML, strip status, cluster-specific fields,
          # and force target namespace.
          tmpfile="$(mktemp)"
          trap 'rm -f "${tmpfile}"' RETURN

          if ! kubectl get "${kind}" "${name}" -n "${src_ns}" -o yaml > "${tmpfile}"; then
            echo "  WARN: Failed to get ${kind}/${name} in namespace '${src_ns}', skipping."
            return 0
          fi

          # Clean up fields that prevent re-creation and adjust namespace
          # - remove status
          # - remove metadata fields that should not be re-applied
          # - set metadata.namespace to dst_ns
          # Using yq would be nicer but we assume only kubectl and core tools.
          # Do minimal, robust transforms with sed/awk.
          cleaned="$(mktemp)"
          trap 'rm -f "${tmpfile}" "${cleaned}"' RETURN

          awk '
            $1=="status:"{in_status=1}
            !in_status{print}
            in_status && NF==0{in_status=0}
          ' "${tmpfile}" > "${cleaned}"

          # Remove certain metadata fields (uid, resourceVersion, etc.)
          # This is a best-effort textual cleanup.
          sed -i '/^[[:space:]]*uid:/d' "${cleaned}"
          sed -i '/^[[:space:]]*resourceVersion:/d' "${cleaned}"
          sed -i '/^[[:space:]]*generation:/d' "${cleaned}"
          sed -i '/^[[:space:]]*creationTimestamp:/d' "${cleaned}"
          sed -i '/^[[:space:]]*managedFields:/,/^[^[:space:]]/d' "${cleaned}"

          # Set / override namespace in metadata
          if grep -q '^[[:space:]]*namespace:' "${cleaned}"; then
            sed -i "s/^\([[:space:]]*namespace:\).*/\1 ${dst_ns}/" "${cleaned}"
          else
            # Insert namespace under metadata:
            awk -v ns="${dst_ns}" '
              /^metadata:[[:space:]]*$/ && !added {
                print $0
                print "  namespace: " ns
                added=1
                next
              }
              {print}
            ' "${cleaned}" > "${cleaned}.ns" && mv "${cleaned}.ns" "${cleaned}"
          fi

          # Annotate that this was moved from default (best-effort)
          if ! grep -q 'annotations:' "${cleaned}"; then
            awk '
              /^metadata:[[:space:]]*$/ && !added {
                print $0
                print "  annotations:"
                print "    moved-from-default-namespace: \"true\""
                added=1
                next
              }
              {print}
            ' "${cleaned}" > "${cleaned}.ann" && mv "${cleaned}.ann" "${cleaned}"
          else
            awk '
              /^  annotations:[[:space:]]*$/ && !added {
                print $0
                print "    moved-from-default-namespace: \"true\""
                added=1
                next
              }
              {print}
            ' "${cleaned}" > "${cleaned}.ann" && mv "${cleaned}.ann" "${cleaned}"
          fi

          # Apply into target namespace
          if ! kubectl apply -f "${cleaned}" --namespace "${dst_ns}"; then
            echo "  ERROR: Failed to create ${kind}/${name} in namespace '${dst_ns}'. Original not deleted."
            return 1
          fi

          # Delete original
          kubectl delete "${kind}" "${name}" -n "${src_ns}" --ignore-not-found

          echo "  Moved ${kind}/${name} -> namespace '${dst_ns}'."
        }

        # --------------- main logic ---------------

        require_kubectl

        echo "Discovering namespaced resource types..."
        resource_types="$(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -)"

        if [[ -z "${resource_types}" ]]; then
          echo "No namespaced resource types discovered. Nothing to do."
          exit 0
        fi

        echo "Listing resources in the 'default' namespace..."
        # Skip the default "kubernetes" service as per audit command
        output_raw="$(kubectl get ${resource_types} --ignore-not-found -n default 2>/dev/null | grep -v '^kubernetes ' || true)"

        if [[ -z "${output_raw}" ]]; then
          echo "No user-defined resources found in the 'default' namespace."
          exit 0
        fi

        echo "User-defined resources currently in 'default' namespace:"
        echo "${output_raw}"
        echo

        target_ns="$(prompt_namespace "default")"
        ensure_namespace_exists "${target_ns}"

        echo
        echo "Moving resources from 'default' to '${target_ns}'..."

        # For each resource type, list names in default and move
        IFS=',' read -r -a kinds <<< "${resource_types}"

        for kind in "${kinds[@]}"; do
          # Get "kind/name" list; skip no-resources error
          mapfile -t lines < <(kubectl get "${kind}" -n default --ignore-not-found -o name 2>/dev/null || true)
          if [[ "${#lines[@]}" -eq 0 ]]; then
            continue
          fi
          for full in "${lines[@]}"; do
            # full is of form kind/name
            res_name="${full#*/}"
            move_resource "${kind}" "${res_name}" "default" "${target_ns}"
          done
        done

        echo
        echo "Verifying that no user-defined resources remain in the 'default' namespace..."

        verification_output="$(
          output=$(kubectl get $(kubectl api-resources --verbs=list --namespaced=true -o name | paste -sd, -) --ignore-not-found -n default 2>/dev/null | grep -v "^kubernetes " || true)
          if [ -z "$output" ]; then
            echo "NO_USER_RESOURCES_IN_DEFAULT"
          else
            echo "USER_RESOURCES_IN_DEFAULT_FOUND: $output"
          fi
        )"

        echo "Verification result: ${verification_output}"

        if [[ "${verification_output}" == "NO_USER_RESOURCES_IN_DEFAULT" ]]; then
          echo "Success: default namespace no longer contains user-defined resources."
          exit 0
        else
          echo "WARNING: Some resources remain in the default namespace. Review output above."
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
