The Default Namespace Should Not Be Used
More Info:​
Using the default namespace for user workloads makes it harder to apply access controls and network policies. Place workloads in dedicated namespaces instead.
Risk Level​
Low
Address​
Security
Compliance Standards​
- CIS AKS
Triage and Remediation​
- Remediation
Remediation​
Manual Steps
-
List all user resources in the default namespace
- Run on: any machine with kubectl access
kubectl get all -n defaultkubectl get configmap,secret,ingress,priorityclass,networkpolicy,serviceaccount,role,rolebinding -n default -
Create one or more dedicated namespaces for your workloads (per app/team as needed)
- Run on: any machine with kubectl access
kubectl create namespace my-app-namespace# repeat with other namespace names as required -
Migrate workload controllers (Deployment/StatefulSet/DaemonSet/Job/CronJob) out of default
- Run on: any machine with kubectl access
- For each controller in
default, choose a target namespace and run:
# Example for a Deployment named my-appkubectl get deployment my-app -n default -o yaml \| sed 's/namespace: default/namespace: my-app-namespace/' \| kubectl apply -f -kubectl delete deployment my-app -n default- Use the same pattern for
statefulset,daemonset,job, andcronjobresources.
-
Migrate Services, Ingresses, and supporting objects (ConfigMaps, Secrets, ServiceAccounts, Roles, RoleBindings, NetworkPolicies)
- Run on: any machine with kubectl access
- For each resource in
default, re-apply into the target namespace and then delete fromdefault. Examples:
# Servicekubectl get service my-service -n default -o yaml \| sed 's/namespace: default/namespace: my-app-namespace/' \| kubectl apply -f -kubectl delete service my-service -n default# ConfigMapkubectl get configmap my-config -n default -o yaml \| sed 's/namespace: default/namespace: my-app-namespace/' \| kubectl apply -f -kubectl delete configmap my-config -n default# Secretkubectl get secret my-secret -n default -o yaml \| sed 's/namespace: default/namespace: my-app-namespace/' \| kubectl apply -f -kubectl delete secret my-secret -n default# Ingresskubectl get ingress my-ingress -n default -o yaml \| sed 's/namespace: default/namespace: my-app-namespace/' \| kubectl apply -f -kubectl delete ingress my-ingress -n default- Repeat for other names/resources until
kubectl get all -n defaultonly shows thekubernetesService.
-
Update clients/manifests to stop using the default namespace
- Run on: any machine with kubectl access
- Ensure your manifests declare the correct namespace:
metadata:name: my-appnamespace: my-app-namespace- If you use a kubeconfig context, set a non-default namespace:
kubectl config set-context --current --namespace=my-app-namespace -
Verification (default namespace has no user workloads)
- Run on: any machine with kubectl access
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
Using kubectl
On any machine with kubectl access:
-
Create replacement namespaces for workloads currently in
default
Example (adjust names as needed):kubectl create namespace app-frontendkubectl create namespace app-backendOr via manifest:
cat << 'EOF' | kubectl apply -f -apiVersion: v1kind: Namespacemetadata:name: app-frontend---apiVersion: v1kind: Namespacemetadata:name: app-backendEOF -
List all user resources in the
defaultnamespace (to plan migration):kubectl get all -n default -o wide -
For each user workload in
default, reapply it into a non-default namespace, then delete the original.
Example for a deployment:# Recreate in new namespacekubectl get deployment my-app -n default -o yaml \| sed 's/namespace: default/namespace: app-frontend/' \| kubectl apply -f -# Delete from default namespacekubectl delete deployment my-app -n defaultExample for a service:
kubectl get service my-app-svc -n default -o yaml \| sed 's/namespace: default/namespace: app-frontend/' \| kubectl apply -f -kubectl delete service my-app-svc -n defaultExample for a configmap:
kubectl get configmap my-config -n default -o yaml \| sed 's/namespace: default/namespace: app-frontend/' \| kubectl apply -f -kubectl delete configmap my-config -n default -
For resources that may not have an explicit
namespace:field (e.g., some autogenerated manifests), you can set it during reapply:kubectl get deployment my-other-app -n default -o yaml \| sed '/^ namespace: /d' \| sed 's/^metadata:$/metadata:\n namespace: app-backend/' \| kubectl apply -f -kubectl delete deployment my-other-app -n default -
Repeat step 3 for all user-defined objects in
default(deployments, statefulsets, daemonsets, jobs, cronjobs, services, ingresses, configmaps, secrets, PVCs, etc.), making sure interdependent resources are moved into the same new namespace. -
Verification (CIS-aligned):
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
Automation
#!/usr/bin/env bash
#
# Purpose:
# Ensure the "default" namespace is not used for user workloads by:
# - Creating a target namespace (if it does not exist)
# - Moving namespaced workloads out of "default"
# - Deleting the originals from "default"
# - Verifying no non-kubernetes service resources remain in "default"
#
# Requirements:
# - Run on any machine with kubectl access and appropriate RBAC.
# - kubectl must be configured (KUBECONFIG or in-cluster config).
#
# Usage:
# ./migrate-default-namespace.sh my-namespace
#
# Notes:
# - Idempotent: safe to re-run; resources already migrated will be skipped.
# - Only handles namespaced workload-style resources and services.
# - The script assumes that anything in "default" (except service/kubernetes)
# should be moved. Review before running in production.
set -euo pipefail
TARGET_NS="${1:-}"
if [ -z "$TARGET_NS" ]; then
echo "ERROR: target namespace argument is required."
echo "Usage: $0 <target-namespace>"
exit 1
fi
echo ">>> Ensuring target namespace '$TARGET_NS' exists"
if ! kubectl get namespace "$TARGET_NS" >/dev/null 2>&1; then
kubectl create namespace "$TARGET_NS"
else
echo "Namespace '$TARGET_NS' already exists; continuing."
fi
echo ">>> Detecting user-defined resources in 'default' namespace"
# Resource kinds to migrate; adjust as needed for your cluster
RESOURCE_KINDS=(
deployments
statefulsets
daemonsets
replicasets
jobs
cronjobs
pods
services
configmaps
secrets
serviceaccounts
ingresses
networkpolicies
roles
rolebindings
persistentvolumeclaims
)
# Build a list of "kind/name" in default excluding the built-in "kubernetes" service
mapfile -t RESOURCES_IN_DEFAULT < <(
for kind in "${RESOURCE_KINDS[@]}"; do
# Skip if kind is not supported by the API server
if ! kubectl api-resources --namespaced -o name 2>/dev/null | grep -qx "$kind"; then
continue
fi
kubectl get "$kind" -n default --no-headers 2>/dev/null | awk -v k="$kind" '
NF>=1 {
name=$1;
# Exclude core "kubernetes" service
if (!(k=="services" && name=="kubernetes")) {
print k "/" name;
}
}'
done
)
if [ "${#RESOURCES_IN_DEFAULT[@]}" -eq 0 ]; then
echo "No user-defined resources found in 'default' (other than service/kubernetes). Nothing to migrate."
else
echo "Found the following resources in 'default' to migrate to '$TARGET_NS':"
printf ' %s\n' "${RESOURCES_IN_DEFAULT[@]}"
echo ">>> Migrating resources from 'default' to '$TARGET_NS'"
for rn in "${RESOURCES_IN_DEFAULT[@]}"; do
kind="${rn%%/*}"
name="${rn##*/}"
echo "Processing $kind/$name ..."
# Check if the resource already exists in the target namespace with same name and kind
if kubectl get "$kind" "$name" -n "$TARGET_NS" >/dev/null 2>&1; then
echo " Skipping: $kind/$name already exists in namespace '$TARGET_NS'."
# Optionally, delete the source if desired. For safety, we leave it for manual review.
continue
fi
# Export YAML, rewrite namespace, apply to target, then delete from default
if ! kubectl get "$kind" "$name" -n default -o yaml >/dev/null 2>&1; then
echo " WARNING: $kind/$name no longer exists in 'default'; skipping."
continue
fi
echo " Migrating to '$TARGET_NS' ..."
kubectl get "$kind" "$name" -n default -o yaml \
| sed -E "s/^( )?namespace: default$/\1namespace: $TARGET_NS/" \
| kubectl apply -f -
echo " Deleting original from 'default' ..."
kubectl delete "$kind" "$name" -n default --ignore-not-found
done
fi
echo ">>> Verification: checking that 'default' namespace has no user workloads"
output="$(
kubectl get all -n default --no-headers 2>/dev/null \
| grep -v '^service[[:space:]]\+kubernetes[[:space:]]' || true
)"
if [ -z "$output" ]; then
echo "DEFAULT_NAMESPACE_UNUSED"
echo "Verification passed: default namespace has no user-defined workloads."
else
echo "DEFAULT_NAMESPACE_IN_USE"
echo "Verification FAILED: resources still exist in 'default' (excluding service/kubernetes):"
echo "$output"
echo "Review and migrate or delete these remaining resources manually."
exit 2
fi