Skip to main content

Create Administrative Boundaries Between Resources

More Info:

Use namespaces to isolate your Kubernetes objects.

Risk Level

Low

Address

Security

Compliance Standards

  • CIS Kubernetes

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
    kubectl get deploy,sts,ds,job,cronjob,pod,svc,ingress -A

    Review whether application, platform, and system components are clearly separated (for example: kube-system, monitoring, logging, team-a, team-b, etc.).

  2. Map workloads to teams/environments and desired boundaries
    Run on: any machine with kubectl access

    kubectl get deploy,sts,ds,job,cronjob -A -o wide

    For each workload, decide which administrative boundary it should belong to (per team, per environment like dev/stage/prod, per application, or per data classification). Document the target namespace layout (e.g., team-a-dev, team-a-prod, shared-infra).

  3. Identify objects in inappropriate or overly shared namespaces
    Run on: any machine with kubectl access

    # Example: list non-system workloads in the default namespace
    kubectl get all -n default
    kubectl get configmap,secret,svc,ingress,pvc -n default

    Flag any non-system workloads running in default or in a namespace that does not match the intended boundary from step 2.

  4. Define or create the required namespaces
    Run on: any machine with kubectl access
    For each desired namespace that does not yet exist:

    kubectl get namespace <target-namespace> || kubectl create namespace <target-namespace>

    Optionally prepare namespace manifests for GitOps/IaC:

    apiVersion: v1
    kind: Namespace
    metadata:
    name: <target-namespace>

    Apply with:

    kubectl apply -f <namespace-manifest>.yaml
  5. Plan and execute workload relocation into proper namespaces
    Run on: any machine with kubectl access
    For each object identified in step 3, update its manifest to set metadata.namespace: <target-namespace> and re-apply:

    # Export current manifest (example for a deployment in default)
    kubectl get deploy <name> -n default -o yaml > <name>.yaml
    # Edit metadata.namespace in the file to the desired namespace
    sed -i 's/namespace: default/namespace: <target-namespace>/' <name>.yaml
    # Apply to new namespace
    kubectl apply -f <name>.yaml
    # Then delete from old namespace after confirming new instance is healthy
    kubectl delete deploy <name> -n default

    Repeat similarly for services, configmaps, secrets, ingresses, and other namespaced resources, ensuring references (service names, configMapRefs, secretRefs, PVCs) remain valid in the new namespace.

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

    kubectl get namespaces
    kubectl get all -A

    Confirm that:

    • default contains no long-lived application workloads unless explicitly intended.
    • Workloads are grouped into namespaces that reflect the documented administrative boundaries (teams, environments, or applications) and that cross-team/environment sharing is limited to explicitly designated shared namespaces.
Using kubectl

Using kubectl

1. List all namespaces and their basic metadata

Run on: any machine with kubectl access

kubectl get namespaces -o wide

Review for:

  • Only default plus system namespaces (kube-system, kube-public, kube-node-lease, any cloud-provider system namespaces) in a busy cluster.
  • Many unrelated apps or teams apparently all using default.

Both suggest missing administrative boundaries.

2. See what is running in each namespace

Run on: any machine with kubectl access

kubectl get pods --all-namespaces -o wide

Look for:

  • Multiple unrelated applications (different teams, environments, or tenants) mixed in the same non-system namespace.
  • Business-critical workloads running in default.

This can indicate insufficient isolation between applications or tenants.

3. Inventory higher-level objects by namespace

Run on: any machine with kubectl access

Workloads:

kubectl get deploy,sts,ds,job,cronjob --all-namespaces

Services, ingresses, and configs:

kubectl get svc,ingress,cm,secret --all-namespaces

Indicators of a problem:

  • Namespaces that act as “junk drawers” for many unrelated workloads/configs.
  • Shared namespace holding both production and non-production resources.
  • Shared namespace used by multiple teams/tenants (you’ll identify this by naming conventions or labels from your environment).

4. Check for labeling that reflects ownership or environment

Run on: any machine with kubectl access

kubectl get namespaces --show-labels

You may also want:

kubectl get ns -L team -L environment -L tenant

Potential issues:

  • No labels reflecting owner/team, environment (prod, dev, test), or tenant where that separation is expected in your organization.
  • Single namespace apparently serving multiple environments or tenants based on object names inside it (e.g., prod-* and dev-* resources mixed together).

5. Review access control by namespace (for context)

While this check is about namespaces themselves, RBAC use can show whether namespaces are being used as an administrative boundary.

Run on: any machine with kubectl access

kubectl get rolebindings,clusterrolebindings --all-namespaces -o wide

What may indicate a problem:

  • Heavy use of ClusterRoleBinding to grant broad access, instead of RoleBinding scoped to specific namespaces, suggesting that namespaces are not being used as boundaries.
  • Same service account or user bound to roles across many unrelated namespaces without a clear reason.

6. Focus review on the default namespace

Run on: any machine with kubectl access

kubectl get all -n default
kubectl get cm,secret,sa,role,rolebinding -n default

Red flags:

  • Application workloads from multiple teams or environments all live in default.
  • Critical workloads live in default instead of a clearly named, dedicated namespace.

kubectl cannot decide the correct namespace design for you. Use the above outputs to determine whether your current namespace layout reflects your organizational boundaries (teams, tenants, environments, or applications) and adjust your manifests and deployment processes accordingly.

Automation
#!/usr/bin/env bash
# Run on: any machine with kubectl access and appropriate RBAC
# Purpose: Summarize namespaces, what runs in them, and basic isolation indicators

set -euo pipefail

echo "=== Cluster-wide namespace and workload summary ==="
echo

# 1) High-level namespace list with age and labels (used to infer purpose/tenancy)
echo "[1] Namespaces (name, age, labels)"
kubectl get ns --show-labels
echo
echo "-> REVIEW:"
echo " - Namespaces that mix unrelated purposes (e.g., team=multiple, env=dev+prod)."
echo " - Namespaces clearly used for multiple tenants or critical+noncritical workloads."
echo

# 2) Workload density per namespace (pods, deployments, statefulsets, daemonsets, jobs, cronjobs)
echo "[2] Workload counts per namespace"
kubectl get ns -o json \
| jq -r '
.items[]
| .metadata.name as $ns
| "Namespace: \($ns)" ,
(
[ "pods","deploy","sts","ds","jobs","cj" ]
| map(
. as $kind
| " \($kind): " +
( try ([
"kubectl","-n",$ns,"get",$kind,"--no-headers"
] | @sh) catch "" )
) | .[]
)
' 2>/dev/null | while read -r line; do
case "$line" in
*"kubectl -n"*)
# Execute the embedded kubectl commands constructed by jq
eval "${line#*\"}" 2>/dev/null | wc -l | awk '{print " "prev $1}' prev="${line%%:*}: "
;;
*)
echo "$line"
;;
esac
done
echo
echo "-> REVIEW:"
echo " - Namespaces with a very high variety of workloads (many unrelated apps)."
echo " - Namespaces mixing system and application workloads."
echo

# 3) Identify namespaces with both system and non-system indicators
echo "[3] Possible mixing of system and application workloads"
echo "System-like namespaces (by prefix/known names):"
kubectl get ns | awk '$1 ~ /^(kube-|default$|kube-system$|kube-public$|kube-node-lease$)/ {print " " $1}'
echo
echo "Non-system namespaces:"
kubectl get ns | awk '$1 !~ /^(kube-|default$|kube-system$|kube-public$|kube-node-lease$)/ {print " " $1}'
echo
echo "-> REVIEW:"
echo " - Application pods deployed in kube-system or other system namespaces."
echo " - Critical shared services deployed only in default instead of a dedicated namespace."
echo

# 4) ServiceAccounts per namespace (indicates possible shared admin boundaries)
echo "[4] ServiceAccounts per namespace"
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "Namespace: $ns"
kubectl -n "$ns" get sa --no-headers 2>/dev/null || true
echo
done
echo "-> REVIEW:"
echo " - Single ServiceAccount reused by many unrelated workloads (broad admin boundary)."
echo " - 'default' ServiceAccount heavily used instead of specific, per-app accounts."
echo

# 5) NetworkPolicies per namespace (coarse indicator of network isolation)
echo "[5] NetworkPolicies per namespace"
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
count=$(kubectl -n "$ns" get networkpolicy --no-headers 2>/dev/null | wc -l | tr -d ' ')
echo "Namespace: $ns NetworkPolicies: $count"
done
echo
echo "-> REVIEW:"
echo " - Namespaces with many different apps but zero NetworkPolicies (likely flat network)."
echo

# 6) RBAC: ClusterRoles/ClusterRoleBindings that span multiple namespaces (coarse admin boundary)
echo "[6] ClusterRoleBindings (who has cluster-scoped powers)"
kubectl get clusterrolebinding -o wide
echo
echo "-> REVIEW:"
echo " - Subjects (users/groups/serviceaccounts) that administer many namespaces at once."
echo " - ServiceAccounts from application namespaces bound to powerful ClusterRoles."
echo

echo "=== Interpretation Guidelines ==="
echo "- A PROBLEM is indicated when:"
echo " * Multiple teams, tenants, or environments share a single namespace."
echo " * System and application workloads run in the same namespace."
echo " * Critical or sensitive apps share namespaces with unrelated, less-trusted apps."
echo " * Namespaces have many diverse workloads but no NetworkPolicies or fine-grained RBAC."
echo "- The remedy is design-driven: define clear per-team/per-app/per-env namespaces and"
echo " reorganize workloads; this cannot be safely auto-fixed and requires human decisions."

How to run

  • Run on any machine with kubectl and jq installed and access to the cluster:
    chmod +x namespace-boundaries-audit.sh
    ./namespace-boundaries-audit.sh

What output indicates a problem

  • Namespaces where:
    • Many unrelated apps and teams share the same namespace.
    • Application pods are present in kube-system or other system namespaces.
    • Critical shared services live only in default.
    • Only the default ServiceAccount is used for many workloads.
    • There are many workloads but zero NetworkPolicies.
    • ClusterRoleBindings grant broad privileges to subjects from many namespaces.

These patterns suggest weak administrative boundaries; decisions on new namespace layout and workload moves must be made manually.

Additional Reading: