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 AKS
- CIS Critical Security Controls v8
- 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 current namespaces and workloads
- Run on: any machine with kubectl access
- Command:
kubectl get namespaceskubectl get all --all-namespaceskubectl get crd
- Review whether most application workloads are concentrated in
defaultor other shared namespaces without a clear purpose (e.g., mixing dev/test/prod in one namespace).
-
Map applications, teams, and environments to desired namespaces
- Run on: any machine with kubectl access
- Command (gather current labels/ownership hints):
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.metadata.labels}{"\n"}{end}'
- Decide an intended namespace model, for example:
- Environment-based:
dev,test,stage,prod - Team-based:
team-a,team-b - App-based:
payments,search
- Environment-based:
- Document which workloads should live in which namespaces.
-
Define or update namespaces to match the model
- Run on: any machine with kubectl access
- Create any missing namespaces (example names; adapt to your model):
kubectl create namespace devkubectl create namespace prod
- Or with manifests (recommended for GitOps):
cat << 'EOF' | kubectl apply -f -apiVersion: v1kind: Namespacemetadata:name: dev---apiVersion: v1kind: Namespacemetadata:name: prodEOF
-
Plan and, if acceptable, migrate workloads into dedicated namespaces
- Run on: any machine with kubectl access
- For each deployment/statefulset/etc., decide the target namespace and update manifests accordingly. Example (moving an app from
defaulttodev):# Export existing manifestkubectl get deployment my-app -n default -o yaml > my-app.yaml# Edit my-app.yaml: change# namespace: default# to# namespace: dev# (or add metadata.namespace: dev if absent)# Apply into the new namespacekubectl apply -f my-app.yaml# Optionally delete old objects once verifiedkubectl delete deployment my-app -n default - Check for namespace-specific dependencies (ConfigMaps, Secrets, Services, RBAC) and duplicate or adjust them in the target namespace as needed.
-
Align RBAC and policies with the namespace boundaries
- Run on: any machine with kubectl access
- Gather RBAC scoped to or spanning multiple namespaces:
kubectl get role,rolebinding --all-namespaceskubectl get clusterrole,clusterrolebinding
- Adjust or create
Role/RoleBindingobjects so that:- Access for a team or app is granted only in its dedicated namespace(s).
- Broad
ClusterRoleBindinggrants are replaced with namespace-scoped bindings where appropriate.
- If you use NetworkPolicies, PodSecurity admission, or ResourceQuotas, ensure they are defined per namespace according to your boundaries.
-
Verify that administrative boundaries exist and are enforced
- Run on: any machine with kubectl access
- Confirm workloads are distributed and not all in
defaultor a single shared namespace:kubectl get pods --all-namespaces - Validate that a representative user/service account cannot access out-of-scope namespaces (example using a kubeconfig/context for that identity):
# List pods in allowed namespacekubectl --context=<limited-context> get pods -n dev# Attempt to list pods in a disallowed namespace; this should be forbiddenkubectl --context=<limited-context> get pods -n prod
- If workloads and RBAC now reflect clear, intentional namespace-based separation, this control can be considered satisfied.
Using kubectl
Using kubectl
Run these commands from any machine with kubectl access.
1. List all namespaces and their basic metadata
kubectl get namespaces -o wide
Review the output for:
- Almost everything running in
default,kube-system, or other built‑in namespaces. - Only one or two namespaces total in a non-trivial cluster.
This suggests poor separation of environments/teams/apps.
2. See which namespaces your workloads actually use
kubectl get all --all-namespaces
Look for:
- Multiple unrelated applications or teams using the same namespace.
- All custom workloads in
defaultinstead of app/team/environment‑specific namespaces.
This indicates weak administrative boundaries.
3. Group workloads by label across namespaces
If you use labels for apps/environments:
kubectl get pods --all-namespaces -L app,environment,team
Red flags:
- Same
apporteamlabel spread across many unrelated namespaces without a clear reason. - Mixed
environmentvalues (e.g.,prod,dev,test) inside the same namespace.
This may indicate namespaces are not aligned with your intended boundaries.
4. Inspect RBAC bindings per namespace
kubectl get rolebindings,roles -A
Look for:
- Very broad roles (e.g.,
*verbs or resources) reused in many namespaces. - Many subjects (users/groups/serviceaccounts) sharing the same namespace unintentionally.
This can show that namespaces are not providing the intended isolation.
5. Identify objects in the default namespace
kubectl get all -n default
If you see:
- Critical or production workloads,
- Multiple unrelated applications,
- Shared infrastructure components mixed with app workloads,
then your default namespace is being overused instead of having dedicated namespaces.
6. Drill into a specific namespace
Replace my-namespace with a candidate namespace that looks overloaded:
kubectl get all -n my-namespace
kubectl describe namespace my-namespace
Indicators of a problem:
- Many unrelated apps/teams/environments mixed in one namespace.
- No annotations/labels explaining ownership or purpose.
These observations should drive a human decision on whether to introduce or adjust namespaces to create clearer administrative boundaries.
Automation
#!/usr/bin/env bash
# Report namespace usage and potential multi-tenant / boundary issues
set -euo pipefail
echo "=== 1) Namespace list with labels and resource counts ==="
kubectl get ns -o json \
| jq -r '
.items[]
| {
name: .metadata.name,
labels: .metadata.labels,
pods: ( .metadata.name as $ns
| ( input // empty | .items[] | select(.metadata.namespace==$ns) ) ),
roles: (""), rolebindings: (""), clusterrolebindings: ("")
}' \
--slurpfile pods <(kubectl get pods -A -o json) \
> /tmp/ns_raw.json
# Summarize: name, labels, pod count
jq -r '
( "NAMESPACE\tLABELS\tPOD_COUNT" ),
( .[] |
.name as $n |
.labels as $l |
$n,
($l // {} | to_entries | map("\(.key)=\(.value)") | join(",")),
0
)' /tmp/ns_raw.json | paste - - - \
| column -t -s $'\t'
echo
echo "=== 2) Namespaces containing workloads by logical app (from labels) ==="
echo "Heuristic: shows how many distinct app labels exist per namespace."
kubectl get pods -A -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
app: (
.metadata.labels.app
// .metadata.labels."app.kubernetes.io/name"
// "UNLABELED"
)
}' \
| jq -sr '
group_by(.ns)
| map({
namespace: .[0].ns,
apps: (map(.app) | unique)
})
| .[]
| "\(.namespace)\t\(.apps | length)\t\(.apps | join(","))"
' \
| awk 'BEGIN {print "NAMESPACE\tDISTINCT_APPS\tAPPS"}1' \
| column -t -s $'\t'
echo
echo "=== 3) Workloads running in kube-system and default namespaces ==="
echo "Review any non-core or tenant workloads here; they should usually be moved."
echo "--- Pods in kube-system ---"
kubectl get pods -n kube-system -o wide || true
echo
echo "--- Pods in default ---"
kubectl get pods -n default -o wide || true
echo
echo "=== 4) Namespaces without any ResourceQuota or LimitRange ==="
echo "These namespaces have no basic resource boundaries."
echo "--- Namespaces with NO ResourceQuota ---"
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
if ! kubectl get resourcequota -n "$ns" >/dev/null 2>&1; then
echo "$ns"
fi
done
echo
echo "--- Namespaces with NO LimitRange ---"
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
if ! kubectl get limitrange -n "$ns" >/dev/null 2>&1; then
echo "$ns"
fi
done
echo
echo "=== 5) RBAC scope: RoleBindings vs ClusterRoleBindings per namespace ==="
echo "Multiple tenants sharing a namespace + broad ClusterRoleBindings is a risk."
echo "--- ClusterRoleBindings (cluster-wide) ---"
kubectl get clusterrolebindings.rbac.authorization.k8s.io -o wide
echo
echo "--- RoleBindings per namespace (who can do what inside each namespace) ---"
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo
echo "Namespace: $ns"
kubectl get rolebindings.rbac.authorization.k8s.io -n "$ns" -o wide || true
done
echo
echo "=== 6) ServiceAccounts shared across namespaces (unusual) ==="
echo "ServiceAccounts should be namespace-scoped; same name across many namespaces may indicate shared operational boundary."
kubectl get sa -A -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name}
' \
| jq -sr '
group_by(.name)
| map(select(length > 1))
| .[]
| "\(.[0].name)\t\(.|map(.ns)|join(","))"
' \
| awk 'BEGIN {print "SERVICEACCOUNT\tNAMESPACES"}1' \
| column -t -s $'\t'
echo
echo "=== 7) Summary: possible issues to review ==="
echo "1) Namespaces with many distinct apps (from section 2) may mix unrelated workloads."
echo "2) Workloads in 'default' or 'kube-system' (section 3) often indicate missing namespaces."
echo "3) Namespaces listed in section 4 lack quotas/limits and may need stronger boundaries."
echo "4) Broad ClusterRoleBindings (section 5) + shared namespaces weaken administrative separation."
echo "5) ServiceAccounts reused across many namespaces (section 6) may indicate blurred boundaries."
echo
echo "Review the above and decide where new namespaces or stricter policies are needed; remediation remains a manual design decision."
How to interpret problematic output
- Many unrelated apps in the same namespace (section 2:
DISTINCT_APPSis high, orAPPSis a long mixed list) → boundaries between teams/apps are not enforced. - Non-core or tenant workloads in
defaultorkube-system(section 3) → those objects should usually be moved into dedicated namespaces. - Namespaces listed as having no
ResourceQuotaor noLimitRange(section 4) → no basic resource governance; may not meet your boundary requirements. - ClusterRoleBindings granting broad permissions to many subjects who all work in shared namespaces (section 5) → weak administrative isolation.
- ServiceAccounts showing up in many namespaces (section 6) → may indicate shared operational boundaries instead of clear namespace-based separation.