Create Administrative Boundaries Between Resources Using
More Info:
Use namespaces to isolate your Kubernetes objects.
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)
- 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
- Remediation
Remediation
Manual Steps
-
Inventory existing namespaces and workloads
- Run (on any machine with kubectl access):
kubectl get namespaceskubectl get all --all-namespaces
- Identify which applications, teams, and environments (dev/test/stage/prod) currently share a namespace (especially
default).
- Run (on any machine with kubectl access):
-
Identify isolation requirements and desired boundaries
- With your application/ops teams, decide how you want to separate:
- By environment: e.g.
dev,stage,prod - By team or business unit: e.g.
payments,analytics - By application: e.g.
web-frontend,orders-service
- By environment: e.g.
- Note which existing workloads in
defaultor other shared namespaces should move into their own dedicated namespace(s).
- With your application/ops teams, decide how you want to separate:
-
Check for objects incorrectly living in shared/default namespaces
- List objects in
defaultand any “catch-all” namespaces:kubectl get all -n defaultkubectl get all -n kube-system - Flag any non-platform, business workloads in
kube-system(they should usually be moved) and any critical production workloads indefault(they typically deserve dedicated namespaces).
- List objects in
-
Design and create the required namespaces
- Define the namespaces you need (from step 2), including labels/annotations for ownership and environment.
- Create them:
kubectl create namespace prod-paymentskubectl create namespace prod-frontendkubectl label namespace prod-payments env=prod team=paymentskubectl label namespace prod-frontend env=prod team=frontend
- Adjust names and labels to match your chosen scheme.
-
Plan and migrate workloads into appropriate namespaces
- For each workload identified in step 3, update its manifests to set
metadata.namespaceto the new target namespace and adjust any in-namespace references (ConfigMaps, Secrets, Services, RoleBindings, NetworkPolicies, etc.). - Apply the updated manifests:
kubectl apply -f updated-manifests/
- Decommission the old objects from the previous namespace once the new ones are verified:
kubectl delete -f old-manifests/
- For each workload identified in step 3, update its manifests to set
-
Verify namespace-based boundaries are in place
- Confirm namespaces and workload placement:
kubectl get namespaceskubectl get all -n prod-paymentskubectl get all -n prod-frontend
- Ensure that the
defaultnamespace no longer hosts critical or multi-tenant workloads and that each major application/team/environment has a clearly defined namespace boundary.
- Confirm namespaces and workload placement:
Using kubectl
# 1. List all namespaces and their age
# Run on: any machine with kubectl access
kubectl get namespaces -o wide
What to look for (possible problems)
- Only
default,kube-system,kube-public, andkube-node-leaseexist, but many applications/workloads are running → suggests everything is indefaultwith no boundaries. - A single custom namespace (e.g.,
prod) containing all non-system workloads for different teams/environments → coarse boundary, little separation.
# 2. See which namespaces are actually used by workload objects
kubectl get all --all-namespaces
What to look for (possible problems)
- Most or all Deployments/Pods/Services are in the
defaultnamespace. - Critical system-like components or third-party platforms (logging, monitoring, CI agents) running in
defaultrather than a dedicated namespace. - Mixed environments (dev, test, prod) or mixed teams using the same namespace.
# 3. Show which namespaces have RoleBindings/ClusterRoleBindings
kubectl get rolebindings,clusterrolebindings --all-namespaces
What to look for (possible problems)
- Broad, powerful RoleBindings (e.g., binding
cluster-adminor wide-scoped roles) applied in a namespace that mixes unrelated workloads. - Lack of any RoleBindings in non-system namespaces when multiple teams share the cluster, suggesting no real separation of administrative duties.
# 4. Inspect a specific high-usage namespace (example: default)
kubectl get all -n default
kubectl get rolebindings -n default
kubectl describe namespace default
What to look for (possible problems)
- Many unrelated applications, teams, or environments all running in
default. - No labels/annotations that indicate intended ownership, environment, or purpose, making it hard to enforce policies and boundaries.
# 5. Correlate namespaces to application ownership using labels
kubectl get namespaces --show-labels
What to look for (possible problems)
- No labeling strategy (e.g., no
team=...,env=...,app=...), making it unlikely namespaces are being used as deliberate administrative boundaries. - One namespace with labels suggesting it serves multiple distinct environments or teams (e.g.,
env=multior a genericshared=truefor many unrelated workloads).
Use the above outputs to answer, manually:
- Are applications grouped into namespaces by environment, team, or function?
- Are high-privilege permissions granted in namespaces that carry mixed or unrelated workloads?
- Are there workloads still running in
defaultthat should be isolated into their own namespaces?
Automation
#!/usr/bin/env bash
# Report namespace usage and isolation signals across the cluster.
# Run on: any machine with kubectl access and current context set to target cluster.
set -euo pipefail
echo "== Cluster namespaces =="
kubectl get namespaces -o wide
echo
echo "== Namespaces by label (team/app/environment) =="
# Shows whether namespaces are tagged for ownership and purpose
kubectl get ns \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.team:="(no-team)"}{"\t"}{.metadata.labels.app:="(no-app)"}{"\t"}{.metadata.labels.environment:="(no-env)"}{"\n"}' \
| column -t
echo
echo "== Workloads per namespace (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs, Pods) =="
for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}'); do
echo
echo "--- Namespace: ${ns} ---"
kubectl get deploy,sts,ds,job,cronjob,pod -n "${ns}" --ignore-not-found
done
echo
echo "== ClusterRoles and ClusterRoleBindings (cluster-wide permissions) =="
kubectl get clusterrole,clusterrolebinding -o wide
echo
echo "== RoleBindings that bind to ClusterRoles (potential cross-namespace power) =="
kubectl get rolebinding --all-namespaces -o json \
| jq -r '
.items[]
| .metadata.namespace as $ns
| .metadata.name as $rb
| .subjects[]? as $s
| .roleRef
| select(.kind=="ClusterRole")
| [$ns, $rb, .name]
| @tsv' 2>/dev/null \
| awk 'BEGIN {print "NAMESPACE\tROLEBINDING\tCLUSTERROLE"} {print}' \
| column -t
echo
echo "== ServiceAccounts used by Pods (by namespace) =="
for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}'); do
echo
echo "--- Namespace: ${ns} ---"
kubectl get pod -n "${ns}" -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\n"}' 2>/dev/null \
| awk 'BEGIN {print "POD\tSERVICEACCOUNT"} {print}' \
| column -t || true
done
echo
echo "== NetworkPolicies per namespace (is there traffic isolation?) =="
for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}'); do
echo
echo "--- Namespace: ${ns} ---"
kubectl get networkpolicy -n "${ns}" --ignore-not-found
done
echo
echo "== Namespaces without any NetworkPolicy (potentially fully open) =="
all_ns=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}')
np_ns=$(kubectl get networkpolicy --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\n"}' | sort -u || true)
echo "${all_ns}" | while read -r ns; do
if ! echo "${np_ns}" | grep -qx "${ns}"; then
echo "${ns}"
fi
done
Explanation of what output may indicate a problem (to review manually):
Cluster namespaces:- Only
default,kube-system,kube-public,kube-node-leaseplus all workloads running indefaultmay indicate missing administrative boundaries.
- Only
Namespaces by label:- Namespaces with
(no-team)/(no-env)suggest lack of ownership and unclear separation.
- Namespaces with
Workloads per namespace:- Many unrelated applications co-located in the same namespace (especially
default) indicate weak isolation.
- Many unrelated applications co-located in the same namespace (especially
ClusterRoles and ClusterRoleBindings:- Very broad cluster-wide roles (e.g., custom
*admin*roles) bound to many subjects reduce the effectiveness of namespace boundaries.
- Very broad cluster-wide roles (e.g., custom
RoleBindings that bind to ClusterRoles:- Numerous rolebindings to powerful ClusterRoles in many namespaces show that namespace boundaries are being bypassed by cluster-scoped permissions.
ServiceAccounts used by Pods:- Heavy reuse of the same high-privilege ServiceAccount across multiple namespaces/apps weakens separation.
NetworkPolicies per namespaceandNamespaces without any NetworkPolicy:- Critical or multi-tenant namespaces with no NetworkPolicies likely have no network-level isolation between tenants or apps.