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

# No Workloads Should Run In The default Namespace

### More Info:

Verifies the default namespace has no workloads so RBAC, quotas and NetworkPolicies can be scoped per tenant.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List all workloads in the `default` namespace (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get all -n default
           ```

        2. For each workload type in `default`, export its manifests so you can recreate them in a new namespace (replace NEWNAMESPACE with your chosen name, created beforehand if needed):
           ```bash theme={null}
           kubectl get deploy,sts,ds,job,cronjob -n default -o yaml > /tmp/default-workloads.yaml
           sed -i 's/namespace: default/namespace: NEWNAMESPACE/g' /tmp/default-workloads.yaml
           ```

        3. Create the target namespace if it does not already exist:
           ```bash theme={null}
           kubectl create namespace NEWNAMESPACE
           ```

        4. Apply the modified manifests into the new namespace (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl apply -f /tmp/default-workloads.yaml
           ```

        5. After confirming the workloads are running correctly in `NEWNAMESPACE`, delete the old workloads from `default` (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl delete deploy,sts,ds,job,cronjob -n default --all
           ```

        6. Verification (run on any machine with kubectl access):
           ```bash theme={null}
           { kubectl get pods -n default -o json
             kubectl get namespace default -o json
           } | jq -rs '
             .[0] as $pods | .[1] |
             .metadata as $m
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | (($pods.items // []) | length) as $count
             | "kind=Namespace name=default uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $labels == "" then "" else " labels=\($labels)" end)
               + " podCount=\($count)"
               + " is_compliant=\(if $count == 0 then "true" else "false" end)"'
           ```
      </Accordion>

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

        1. Identify workloads running in the `default` namespace

        ```bash theme={null}
        kubectl get all -n default
        ```

        2. For each workload type, export its manifest, modify the namespace, and re‑create it. Examples:

        * Deployments:

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

        Edit `default-deployments.yaml`:

        * Remove `status:` sections.
        * For every object, set `metadata.namespace: <new-namespace-name>` (for example `team-a`).

        Then apply and delete originals:

        ```bash theme={null}
        kubectl apply -f default-deployments.yaml
        kubectl delete deploy -n default --all
        ```

        * StatefulSets:

        ```bash theme={null}
        kubectl get statefulset -n default -o yaml > default-statefulsets.yaml
        # edit as above: remove status, change metadata.namespace
        kubectl apply -f default-statefulsets.yaml
        kubectl delete statefulset -n default --all
        ```

        * DaemonSets:

        ```bash theme={null}
        kubectl get daemonset -n default -o yaml > default-daemonsets.yaml
        # edit as above
        kubectl apply -f default-daemonsets.yaml
        kubectl delete daemonset -n default --all
        ```

        * Jobs/CronJobs:

        ```bash theme={null}
        kubectl get job -n default -o yaml > default-jobs.yaml || true
        kubectl get cronjob -n default -o yaml > default-cronjobs.yaml || true
        # edit as above
        kubectl apply -f default-jobs.yaml default-cronjobs.yaml
        kubectl delete job -n default --all
        kubectl delete cronjob -n default --all
        ```

        * Services and related objects (to keep networking functioning):

        ```bash theme={null}
        kubectl get svc,endpoints,ingress,configmap,secret,serviceaccount -n default -o yaml > default-services-and-support.yaml || true
        # edit as above
        kubectl apply -f default-services-and-support.yaml
        kubectl delete svc,endpoints,ingress,configmap,secret,serviceaccount -n default --all
        ```

        3. If needed, create the new namespace first:

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

        4. Verification

        ```bash theme={null}
        kubectl get pods -n default
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Remediate CBP C3.2: ensure no workloads run in the default namespace.
        # Runs from any machine with kubectl access.

        set -euo pipefail

        echo "=== Checking kubectl context ==="
        kubectl cluster-info >/dev/null

        # 1. List all Pod-owning controllers in default
        echo "=== Discovering controllers in 'default' namespace ==="
        deploys=$(kubectl get deploy -n default -o name || true)
        sts=$(kubectl get statefulset -n default -o name || true)
        daemonsets=$(kubectl get daemonset -n default -o name || true)
        jobs=$(kubectl get job -n default -o name || true)
        cronjobs=$(kubectl get cronjob -n default -o name || true)
        replicasets=$(kubectl get rs -n default -o name || true)
        replicationcontrollers=$(kubectl get rc -n default -o name || true)

        controllers=()
        for c in $deploys $sts $daemonsets $jobs $cronjobs $replicasets $replicationcontrollers; do
          controllers+=("$c")
        done

        if [ ${#controllers[@]} -eq 0 ]; then
          echo "No controllers found in 'default' namespace."
        else
          echo "Found controllers in 'default':"
          printf '  %s\n' "${controllers[@]}"
        fi

        # 2. Determine target namespace
        TARGET_NS="${TARGET_NAMESPACE:-workloads}"
        if [ -z "${TARGET_NS}" ]; then
          echo "TARGET_NAMESPACE is empty; refusing to continue." >&2
          exit 1
        fi

        # 3. Create target namespace if not present
        if ! kubectl get namespace "${TARGET_NS}" >/dev/null 2>&1; then
          echo "=== Creating namespace '${TARGET_NS}' ==="
          kubectl create namespace "${TARGET_NS}"
        else
          echo "Namespace '${TARGET_NS}' already exists."
        fi

        # 4. Move controllers from default to target namespace
        #    This deletes the object in default and recreates it in TARGET_NS
        #    while preserving spec via export-like behavior.
        if [ ${#controllers[@]} -gt 0 ]; then
          echo "=== Moving controllers from 'default' to '${TARGET_NS}' ==="
        fi

        for c in "${controllers[@]}"; do
          kind=${c%%/*}
          name=${c##*/}
          echo "Processing ${kind}/${name}"

          # Export resource YAML without cluster-scoped metadata
          tmpfile=$(mktemp)
          kubectl get "${kind}" "${name}" -n default -o json \
          | jq '
              del(
                .metadata.namespace,
                .metadata.uid,
                .metadata.resourceVersion,
                .metadata.selfLink,
                .metadata.creationTimestamp,
                .metadata.generation,
                .metadata.managedFields,
                .metadata.ownerReferences,
                .status
              )
              | .metadata.annotations |= ( . // {} | del(."kubectl.kubernetes.io/last-applied-configuration") )
            ' \
          | kubectl neat 2>/dev/null || true > "${tmpfile}" || {
            # fallback if kubectl-neat is not installed
            kubectl get "${kind}" "${name}" -n default -o yaml \
            | sed -e '/^  resourceVersion:/d' \
                  -e '/^  uid:/d' \
                  -e '/^  selfLink:/d' \
                  -e '/^  creationTimestamp:/d' \
                  -e '/^  generation:/d' \
                  -e '/^  managedFields:/,/^[^ ]/d' \
                  -e '/^status:/,/^[^ ]/d' \
            > "${tmpfile}"
          }

          # Ensure namespace is set to TARGET_NS
          if ! grep -q '^  namespace:' "${tmpfile}"; then
            # Insert namespace under metadata:
            awk -v ns="${TARGET_NS}" '
              /^metadata:/ { print; print "  namespace: " ns; next }
              { print }
            ' "${tmpfile}" > "${tmpfile}.ns" && mv "${tmpfile}.ns" "${tmpfile}"
          else
            sed -i "s/^  namespace: .*/  namespace: ${TARGET_NS}/" "${tmpfile}"
          fi

          echo "  Applying ${kind}/${name} to namespace '${TARGET_NS}'"
          kubectl apply -n "${TARGET_NS}" -f "${tmpfile}"

          echo "  Deleting original ${kind}/${name} from 'default'"
          kubectl delete "${kind}" "${name}" -n default --ignore-not-found=true

          rm -f "${tmpfile}"
        done

        # 5. Handle any remaining naked Pods in default
        echo "=== Handling standalone Pods in 'default' namespace ==="
        pods_json=$(kubectl get pods -n default -o json || echo '{"items":[]}')
        pod_count=$(echo "${pods_json}" | jq '.items | length')
        if [ "${pod_count}" -gt 0 ]; then
          echo "Found ${pod_count} standalone Pod(s) in 'default'. Recreating in '${TARGET_NS}'."
          echo "${pods_json}" | jq -c '.items[]' | while read -r pod; do
            name=$(echo "${pod}" | jq -r '.metadata.name')
            tmpfile=$(mktemp)

            echo "${pod}" \
            | jq '
                del(
                  .metadata.namespace,
                  .metadata.uid,
                  .metadata.resourceVersion,
                  .metadata.selfLink,
                  .metadata.creationTimestamp,
                  .metadata.generation,
                  .metadata.managedFields,
                  .metadata.ownerReferences,
                  .status
                )
                | .metadata.annotations |= ( . // {} | del(."kubectl.kubernetes.io/last-applied-configuration") )
              ' > "${tmpfile}"

            # Set namespace to TARGET_NS
            if ! grep -q '^  namespace:' "${tmpfile}"; then
              awk -v ns="${TARGET_NS}" '
                /^metadata:/ { print; print "  namespace: " ns; next }
                { print }
              ' "${tmpfile}" > "${tmpfile}.ns" && mv "${tmpfile}.ns" "${tmpfile}"
            else
              sed -i "s/^  namespace: .*/  namespace: ${TARGET_NS}/" "${tmpfile}"
            fi

            echo "  Recreating Pod/${name} in '${TARGET_NS}'"
            # Best-effort delete and recreate
            kubectl delete pod "${name}" -n default --ignore-not-found=true --grace-period=0 --force || true
            kubectl apply -n "${TARGET_NS}" -f "${tmpfile}" || {
              echo "    Warning: failed to recreate Pod/${name} in '${TARGET_NS}'."
            }
            rm -f "${tmpfile}"
          done
        else
          echo "No standalone Pods found in 'default'."
        fi

        # 6. Verification (adapted from audit command)
        echo "=== Verification: ensuring no workloads in 'default' namespace ==="
        { kubectl get pods -n default -o json
          kubectl get namespace default -o json
        } | jq -rs '
          .[0] as $pods | .[1] |
          .metadata as $m
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | (($pods.items // []) | length) as $count
          | "kind=Namespace name=default uid=\($m.uid) apiVersion=v1"
            + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
            + (if $labels == "" then "" else " labels=\($labels)" end)
            + " podCount=\($count)"
            + " is_compliant=\(if $count == 0 then "true" else "false" end)"'
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
