> ## 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 GKE
* 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 resources currently in the `default` namespace** (any machine with kubectl access)
           ```bash theme={null}
           kubectl get all -n default
           kubectl get configmaps,secrets,ingresses,pvc,pv,networkpolicies,serviceaccounts,roles,rolebindings -n default
           ```

        2. **Decide target namespaces and create them if needed** (any machine with kubectl access)\
           Replace `team-a`, `team-b` with your chosen names.
           ```bash theme={null}
           kubectl create namespace team-a
           kubectl create namespace team-b
           ```
           Review and map each object from `default` to an appropriate namespace based on application/tenant/owner.

        3. **Export manifests of objects in `default` and edit to use the new namespace(s)** (any machine with kubectl access)\
           Example for all standard workload resources:
           ```bash theme={null}
           kubectl get deploy,sts,ds,svc,ingress,cm,secret,sa,role,rolebinding -n default -o yaml > /tmp/default-namespace-resources.yaml
           ```
           Open the file and for each object:
           * Change `metadata.namespace: default` to the desired namespace (e.g. `team-a`).
           * Confirm that any `RoleBinding` subjects or role references still make sense in the new namespace.

        4. **Recreate resources in the proper namespaces and delete them from `default`** (any machine with kubectl access)\
           Apply edited manifests:
           ```bash theme={null}
           kubectl apply -f /tmp/default-namespace-resources.yaml
           ```
           Once workloads are healthy in the new namespaces, delete resources from `default`:
           ```bash theme={null}
           kubectl delete deploy,sts,ds,svc,ingress,cm,secret,sa,role,rolebinding -n default --all
           ```
           Be careful not to delete the built‑in `kubernetes` service; the above command omits it because it is a cluster‑scoped service and not usually listed with `--all`, but verify before confirming any deletions.

        5. **Ensure new workloads are not created in `default` going forward** (any machine with kubectl access)
           * Update CI/CD pipelines and manifests to include `metadata.namespace: <target-namespace>` or use `--namespace` in kubectl/Helm commands.
           * Optionally create an `LimitRange`/`ResourceQuota` or an `AdmissionPolicy`/`ValidatingWebhook` (if available in your environment) that rejects new non‑system objects in the `default` namespace.

        6. **Verification** (any machine with kubectl access)
           ```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
           ```
           Confirm the output is:
           ```text theme={null}
           DEFAULT_NAMESPACE_UNUSED
           ```
      </Accordion>

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

        1. Identify what is using the default namespace

        ```bash theme={null}
        kubectl get all -n default
        kubectl get configmaps,secrets,serviceaccounts,roles,rolebindings -n default
        ```

        2. Create a dedicated namespace (example: `team-a`)

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

        3. Recreate workload resources in the new namespace\
           (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs, Services, Ingresses, etc.)

        Example for a Deployment:

        ```bash theme={null}
        kubectl get deployment <DEPLOYMENT_NAME> -n default -o yaml \
          | sed 's/namespace: default/namespace: team-a/' \
          | sed '/resourceVersion:/d' \
          | sed '/uid:/d' \
          | sed '/creationTimestamp:/d' \
          | sed '/selfLink:/d' \
          | sed '/managedFields:/,$d' \
          | kubectl apply -f -
        ```

        Example for a Service:

        ```bash theme={null}
        kubectl get service <SERVICE_NAME> -n default -o yaml \
          | sed 's/namespace: default/namespace: team-a/' \
          | sed '/resourceVersion:/d' \
          | sed '/uid:/d' \
          | sed '/creationTimestamp:/d' \
          | sed '/selfLink:/d' \
          | sed '/clusterIP:/!b;n;s/.*/  clusterIP: None/' \
          | kubectl apply -f -
        ```

        (For Services, review `clusterIP` handling manually; do not blindly apply to production without checking type/annotations.)

        Repeat for all non‑system resources currently in `default`. Update any references (e.g., RoleBindings, NetworkPolicies, Ingress host/rules, external clients) to point to the new namespace.

        4. Delete migrated resources from the default namespace\
           Run only after confirming workloads are healthy in the new namespace:

        ```bash theme={null}
        kubectl delete deployment,replicaset,pod,service,statefulset,daemonset,job,cronjob \
          --all -n default
        kubectl delete configmap,secret,serviceaccount,role,rolebinding \
          --all -n default
        ```

        5. (Optional) Apply a deny policy to prevent future use of the default namespace (Kubernetes with Gatekeeper example)

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: constraints.gatekeeper.sh/v1beta1
        kind: K8sNoDefaultNamespace
        metadata:
          name: forbid-default-namespace
        spec:
          match:
            namespaces:
            - default
            kinds:
            - apiGroups: [""]
              kinds: ["Pod","Service","ConfigMap","Secret","ServiceAccount"]
        EOF
        ```

        (Requires Gatekeeper and a matching ConstraintTemplate already installed; adjust to your admission controller or omit if not in use.)

        6. Verification (matches the audit logic)

        ```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
        #
        # Purpose:
        #   Help enforce “do not use the default namespace” by:
        #     - Identifying all non-system workloads in the default namespace
        #     - Optionally migrating them to a target namespace
        #     - Verifying that the default namespace contains no non-kubernetes service objects
        #
        # Scope:
        #   Run on any machine with kubectl access and appropriate RBAC.
        #
        # Notes:
        #   - This is a MANUAL benchmark control: there is no universally safe, fully
        #     automated fix. This script assists review and migration; you must confirm
        #     each move.
        #   - Changing namespaces requires delete+recreate of most objects; this script
        #     generates manifests for review and then applies them to the target namespace.
        #   - ClusterIP/LoadBalancer/Ingress and other dependencies may need manual
        #     adjustments. Review carefully before approving migrations.

        set -euo pipefail

        # --------- CONFIGURATION ---------
        # Target namespace to migrate workloads into, e.g. "apps" or "team-a".
        # Must be a non-empty string and not "default" or "kube-system".
        TARGET_NAMESPACE="${TARGET_NAMESPACE:-apps}"

        # Set to "yes" to actually apply the migration after review.
        # When "no", manifests are only exported for review.
        APPLY_MIGRATION="${APPLY_MIGRATION:-no}"

        # Directory to store exported manifests for review.
        EXPORT_DIR="${EXPORT_DIR:-./default-namespace-migration}"

        # --------- FUNCTIONS ---------

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

        validate_target_namespace() {
          if [[ -z "${TARGET_NAMESPACE}" ]]; then
            echo "ERROR: TARGET_NAMESPACE is empty. Set TARGET_NAMESPACE and re-run." >&2
            exit 1
          fi
          if [[ "${TARGET_NAMESPACE}" == "default" ]] || [[ "${TARGET_NAMESPACE}" == "kube-system" ]]; then
            echo "ERROR: TARGET_NAMESPACE must not be 'default' or 'kube-system'." >&2
            exit 1
          fi
        }

        ensure_target_namespace_exists() {
          if ! kubectl get namespace "${TARGET_NAMESPACE}" >/dev/null 2>&1; then
            echo "INFO: Creating namespace '${TARGET_NAMESPACE}'..."
            kubectl create namespace "${TARGET_NAMESPACE}"
          else
            echo "INFO: Namespace '${TARGET_NAMESPACE}' already exists."
          fi
        }

        export_default_namespace_objects() {
          mkdir -p "${EXPORT_DIR}"

          echo "INFO: Exporting non-kubernetes-service objects from 'default' namespace..."
          # Get all namespaced API resources that support 'list' and 'get'
          mapfile -t resources < <(
            kubectl api-resources --namespaced=true -o name 2>/dev/null | sort -u
          )

          for res in "${resources[@]}"; do
            # Skip events and ephemeral/system-like resources that usually shouldn't be migrated
            case "${res}" in
              events.events.k8s.io|events|leases.coordination.k8s.io)
                continue
                ;;
            esac

            # List objects in default namespace, excluding the built-in 'kubernetes' service
            objects=$(kubectl get "${res}" -n default --no-headers 2>/dev/null | awk '{print $1}' | grep -v '^kubernetes$' || true)
            if [[ -z "${objects}" ]]; then
              continue
            fi

            for obj in ${objects}; do
              # Export manifest without cluster-specific fields (server-side apply friendly)
              echo "INFO: Exporting ${res}/${obj}..."
              kubectl get "${res}" "${obj}" -n default -o yaml \
                | sed '/^\s*resourceVersion:/d' \
                | sed '/^\s*uid:/d' \
                | sed '/^\s*creationTimestamp:/d' \
                | sed '/^\s*managedFields:/,/^\s*[^ ]/d' \
                > "${EXPORT_DIR}/${res}__${obj}.yaml"
            done
          done

          echo "INFO: Exported manifests are in: ${EXPORT_DIR}"
        }

        update_manifests_namespace() {
          echo "INFO: Updating exported manifests to use namespace '${TARGET_NAMESPACE}'..."
          for file in "${EXPORT_DIR}"/*.yaml; do
            [[ -e "$file" ]] || continue
            # Ensure metadata.namespace is set to TARGET_NAMESPACE
            if grep -q '^\s*namespace:\s*default\s*$' "$file"; then
              sed -i "s/^\(\s*namespace:\s*\)default\s*$/\1${TARGET_NAMESPACE}/" "$file"
            elif ! grep -q '^\s*namespace:\s*' "$file"; then
              # Insert namespace under metadata if missing
              awk -v ns="${TARGET_NAMESPACE}" '
                /^metadata:\s*$/ && !seen {
                  print $0;
                  print "  namespace: " ns;
                  seen=1;
                  next
                }
                {print $0}
              ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
            fi
          done
        }

        apply_migration_manifests() {
          echo "INFO: Applying manifests into '${TARGET_NAMESPACE}'..."
          kubectl apply -n "${TARGET_NAMESPACE}" -f "${EXPORT_DIR}"
        }

        delete_objects_from_default() {
          echo "INFO: Deleting migrated objects from 'default' namespace..."

          # Derive original resource/kind and name from filenames
          for file in "${EXPORT_DIR}"/*.yaml; do
            [[ -e "$file" ]] || continue
            res=$(basename "$file" | sed 's/\.yaml$//' | awk -F'__' '{print $1}')
            name=$(basename "$file" | sed 's/\.yaml$//' | awk -F'__' '{print $2}')

            if [[ -n "${res}" && -n "${name}" ]]; then
              # Ensure we don't delete the built-in service even if present
              if [[ "${res}" == "services" || "${res}" == "service" ]]; then
                if [[ "${name}" == "kubernetes" ]]; then
                  continue
                fi
              fi
              echo "INFO: Deleting ${res}/${name} from 'default'..."
              kubectl delete "${res}" "${name}" -n default --ignore-not-found
            fi
          done
        }

        verify_default_namespace_unused() {
          echo "INFO: Verifying that the default namespace is unused (except for the 'kubernetes' service)..."
          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 "Remaining objects in 'default' namespace:"
            echo "${output}"
          fi
        }

        # --------- MAIN ---------

        require_kubectl
        validate_target_namespace
        ensure_target_namespace_exists
        export_default_namespace_objects
        update_manifests_namespace

        if [[ "${APPLY_MIGRATION}" == "yes" ]]; then
          echo "WARNING: You have set APPLY_MIGRATION=yes."
          echo "         This will:"
          echo "           - apply exported manifests into '${TARGET_NAMESPACE}'"
          echo "           - delete the corresponding objects from 'default'"
          read -r -p "Type 'migrate' to proceed, or anything else to abort: " confirm
          if [[ "${confirm}" == "migrate" ]]; then
            apply_migration_manifests
            delete_objects_from_default
          else
            echo "INFO: Migration aborted by user; manifests are available in ${EXPORT_DIR} for manual review."
          fi
        else
          echo "INFO: APPLY_MIGRATION is 'no'."
          echo "      Review manifests in ${EXPORT_DIR}, then re-run with APPLY_MIGRATION=yes to perform migration."
        fi

        verify_default_namespace_unused
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
