Skip to main content

Create Administrative Boundaries Between Resources Using

More Info:

Namespaces provide administrative and security boundaries for segregating cluster resources. Objects should be organized into dedicated namespaces rather than sharing a single namespace.

Risk Level

Low

Address

Security

Compliance Standards

  • CIS GKE

Triage and Remediation

Remediation

Manual Steps
  1. Inventory current namespaces and workloads
    Run on any machine with kubectl access:

    kubectl get namespaces
    kubectl get all --all-namespaces

    Review which namespaces exist, which are system/managed (e.g., kube-system, gke-system, istio-system, gatekeeper-system), and where your application workloads currently run.

  2. Identify workloads running in inappropriate or shared namespaces
    Focus on default, kube-system, and any “catch‑all” namespaces:

    kubectl get all -n default
    kubectl get all -n kube-system

    Decide which applications, environments (dev/test/prod), or teams are mixed together and should be separated (e.g., multiple apps sharing default, non-system apps in kube-system).

  3. Design a namespace structure aligned to admin and security boundaries
    On a planning machine (no commands):

    • Define namespaces per application, per environment, or per tenant/team (e.g., app1-prod, app1-dev, payments-prod, analytics-dev).
    • Decide which namespaces require stronger controls (e.g., separate namespace for internet-facing workloads, sensitive data, or admin tooling).
      Document the desired namespace layout and which workloads should live where.
  4. Create or update namespace definitions
    Run on any machine with kubectl access:

    • To create missing namespaces:
      kubectl create namespace app1-prod
      kubectl create namespace app1-dev
    • Or define them declaratively in a manifest file (example):
      apiVersion: v1
      kind: Namespace
      metadata:
      name: app1-prod
      ---
      apiVersion: v1
      kind: Namespace
      metadata:
      name: app1-dev
      Apply with:
      kubectl apply -f namespaces.yaml
  5. Relocate workloads into the appropriate namespaces
    For each workload that should move (Deployments, Services, Jobs, etc.):

    • Export its manifest and edit the metadata.namespace (and any namespace-qualified references such as ConfigMaps, Secrets, ServiceAccounts):
      kubectl get deploy my-app -n default -o yaml > my-app.yaml
      Edit my-app.yaml to set:
      metadata:
      namespace: app1-prod
    • Delete the old object and recreate it in the new namespace (ensure you understand the downtime impact):
      kubectl delete deploy my-app -n default
      kubectl apply -f my-app.yaml

    Repeat for Services, ConfigMaps, Secrets, etc., ensuring all required dependencies exist in the target namespace.

  6. Verify namespace boundaries are in place
    Run on any machine with kubectl access:

    kubectl get namespaces
    kubectl get all -n app1-prod
    kubectl get all -n app1-dev
    kubectl get all -n default

    Confirm that:

    • Application workloads are no longer concentrated in default or mixed with system components.
    • Workloads are organized according to the designed boundaries (per app/environment/team) and system namespaces contain only system components.
Using kubectl
# 1) List all namespaces and their age
# Run on: any machine with kubectl access
kubectl get namespaces --show-labels

Review guidance:

  • Potential problems if:
    • Almost all workloads are in default, kube-system, or kube-public.
    • Many namespaces exist but have no clear purpose or labels (e.g., missing env=, team=, app= style labels).
    • System namespaces (kube-system, kube-public, kube-node-lease, gke-*) are used for custom application workloads.
# 2) See which namespaces actually contain workloads
kubectl get all --all-namespaces

Review guidance:

  • Potential problems if:
    • Most Deployment, StatefulSet, DaemonSet, Job, or Pod objects are in a single shared namespace like default.
    • Unrelated applications or teams share the same namespace with no separation.
# 3) Summarize workload kinds per namespace
kubectl get pods,deploy,sts,ds,job,cronjob -A \
-o custom-columns='NAMESPACE:.metadata.namespace,KIND:.kind,NAME:.metadata.name' \
| sort -u

Review guidance:

  • Potential problems if:
    • You see many unrelated applications (by name) co-located in the same namespace.
    • There is no visible pattern (e.g., per-team, per-environment, or per-application grouping).
# 4) Inspect labels/annotations on a specific busy namespace (example: default)
kubectl describe namespace default

Review guidance:

  • Potential problems if:
    • The namespace lacks labels that indicate ownership, environment, or purpose.
    • The namespace mixes “shared” or “misc” workloads with no clear boundary.
# 5) Identify which namespaces are used for user workloads vs system
kubectl get ns \
-o custom-columns='NAME:.metadata.name,AGE:.metadata.creationTimestamp,LABELS:.metadata.labels'

Review guidance:

  • Potential problems if:
    • User workloads appear in system namespaces (names beginning with kube- or gke-).
    • There is no clear distinction between system and application namespaces.
# 6) For one or two key namespaces, list owners via labels
# Replace <namespace> as needed
kubectl get deploy,sts,ds,svc,ingress -n <namespace> \
-o custom-columns='KIND:.kind,NAME:.metadata.name,TEAM:.metadata.labels.team,APP:.metadata.labels.app,ENV:.metadata.labels.env'

Review guidance:

  • Potential problems if:
    • Multiple teams (TEAM label) or environments (ENV label) share the same namespace.
    • No labels are present to show who owns resources or what boundary they belong to.

Interpreting issues for this control:

  • You likely fail the intent of CISGKE 4.6.1 if:
    • Most or all application workloads run in default.
    • Different applications, teams, or environments are not separated into distinct namespaces.
    • System and application workloads are mixed in the same namespaces.
  • A healthy pattern usually shows:
    • Dedicated namespaces per application, team, or environment.
    • System namespaces used only for system components.
Automation
#!/usr/bin/env bash
# Report namespace usage and potential issues for CIS GKE 4.6.1
# Run on: any machine with kubectl access and appropriate RBAC

set -euo pipefail

echo "=== Cluster-wide Namespace Overview ==="
kubectl get namespaces -o wide

echo
echo "=== Namespace Annotations & Labels (for admin boundaries) ==="
kubectl get ns -o json \
| jq -r '
.items[]
| {
name: .metadata.name,
labels: .metadata.labels,
annotations: .metadata.annotations
}' \
| jq .

echo
echo "=== Workloads per Namespace (pods, deployments, statefulsets, daemonsets, jobs, cronjobs) ==="
# Summarize main workload objects per namespace
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| while read -r ns; do
echo "--- Namespace: ${ns} ---"
kubectl get pods,deployments,statefulsets,daemonsets,jobs,cronjobs -n "${ns}" --ignore-not-found
echo
done

echo
echo "=== Namespaces with Mixed 'types' of Workloads (heuristic) ==="
echo "Note: This heuristic flags namespaces that mix system, infra, and app workloads by label patterns."
echo "You must manually review and decide if separation is required."

# Heuristic: classify workloads by label keys commonly used to denote ownership/type
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
name: .metadata.name,
labels: (.metadata.labels // {}),
owner: (
if .metadata.labels["app.kubernetes.io/part-of"] then "app"
elif .metadata.labels["k8s-app"] then "system-or-infra"
elif .metadata.labels["app"] then "app"
else "unknown"
end
)
}' \
| jq -s '
group_by(.ns)
| map({
namespace: .[0].ns,
counts: (group_by(.owner) | map({(.[0].owner): length}) | add)
})' \
| jq -r '
.[]
| select((.counts["app"] != null and .counts["system-or-infra"] != null) or (.counts["unknown"] != null and (.counts["app"] != null or .counts["system-or-infra"] != null)))
'

echo
echo "=== Namespaces with Both System and Application-Looking Objects (by name pattern) ==="
echo "Patterns used: kube-*, istio-*, linkerd, logging, monitoring, prometheus, envoy, ingress"
echo "Review these for possible separation of system/infra from application workloads."

patterns='kube-|istio-|linkerd|logging|monitoring|prometheus|envoy|ingress'

kubectl get pods --all-namespaces -o wide \
| awk 'NR==1 {next} {print $1, $2}' \
| while read -r ns pod; do
if [[ "${pod}" =~ ${patterns} ]]; then
echo "${ns} SYSTEM_OR_INFRA_POD ${pod}"
else
echo "${ns} APP_OR_OTHER_POD ${pod}"
fi
done \
| awk '
{
ns=$1; type=$2
has[ns][type]=1
}
END {
for (n in has) {
if (has[n]["SYSTEM_OR_INFRA_POD"] && has[n]["APP_OR_OTHER_POD"]) {
print n ": has both system/infra-looking and app-looking pods"
}
}
}' \
| sort

echo
echo "=== Namespaces with No Clear Labeling for Ownership/Boundary (candidates for review) ==="
kubectl get ns -o json \
| jq -r '
.items[]
| {
name: .metadata.name,
labels: .metadata.labels
}
| select(.name != "kube-system" and .name != "kube-public" and .name != "kube-node-lease" and .name != "default")
| select(
(.labels["team"] == null)
and (.labels["owner"] == null)
and (.labels["app.kubernetes.io/part-of"] == null)
and (.labels["environment"] == null)
)
| .name' \
| sort

echo
echo "=== Objects in the 'default' Namespace (strong candidates for re-namespacing) ==="
echo "These commonly indicate missing administrative boundaries."
kubectl get all -n default --show-kind --ignore-not-found

echo
echo "=== Summary & Interpretation Guidance ==="
cat <<'EOF'
Review guidance (CIS GKE 4.6.1 - MANUAL):

Potential problems you should investigate:

1) Heavy use of the 'default' namespace:
- If many applications, services, or jobs are in 'default', they likely lack
clear administrative boundaries. Consider moving them into dedicated
namespaces per app, team, environment, or trust level.

2) Namespaces that mix system/infra and application workloads:
- The sections "Namespaces with Mixed 'types' of Workloads" and
"Namespaces with Both System and Application-Looking Objects" list
namespaces that appear to host both:
* cluster/system/infra components (e.g., kube-*, istio-*, logging/monitoring)
* regular application pods
- Consider separating system/infra components from business applications
into distinct namespaces.

3) Namespaces with no ownership/boundary labels:
- The "Namespaces with No Clear Labeling" section lists namespaces
that lack common labels to denote owner, team, or environment.
- While not a hard failure, unclear ownership often correlates with
weak administrative boundaries.

4) General organization:
- Review whether you have a namespace strategy (e.g. by team, by app,
by environment: dev/stage/prod, by sensitivity).
- For each multi-tenant/shared cluster, ensure tenants do not share
namespaces unless intentionally designed.

This script only reports; it does NOT change any resources.
You must decide, per finding, whether to create new namespaces and
move workloads, following your operational and security requirements.
EOF

What output indicates a problem (to be manually reviewed):

  • Many user workloads listed under === Objects in the 'default' Namespace ===.
  • Namespaces listed under:
    • === Namespaces with Mixed 'types' of Workloads (heuristic) ===
    • === Namespaces with Both System and Application-Looking Objects ===
  • Namespaces listed under === Namespaces with No Clear Labeling for Ownership/Boundary === in a multi-tenant or complex environment.