Minimize Access To Create Pods
More Info:
The ability to create pods in a namespace can provide a number of opportunities for privilege escalation, such as assigning privileged service accounts to these pods or mounting hostPaths with access to sensitive data (unless Pod Security Policies are implemented to restrict this access)
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify which subjects can create pods
- Run on any machine with kubectl access:
kubectl get clusterrole,role -A -o wide | grep -i podkubectl get clusterrole -o yaml | grep -nA5 "resources:.*pods"kubectl get role -A -o yaml | grep -nA5 "resources:.*pods"
- Run on any machine with kubectl access:
-
Inspect the exact permissions granting
createon pods- Run on any machine with kubectl access:
kubectl get clusterrole -o yaml > /tmp/clusterroles.yamlkubectl get role -A -o yaml > /tmp/roles.yaml
- Open
/tmp/clusterroles.yamland/tmp/roles.yamland search for rules like:- apiGroups: [""]resources: ["pods"]verbs: ["create", "update", "delete", ...]
- Open
- Run on any machine with kubectl access:
-
Decide which roles should keep
createon pods- For each role/clusterrole you found, decide:
- Is pod creation truly required for this role’s function?
- Can the ability be restricted to specific namespaces (use Role instead of ClusterRole)?
- Can pod creation be delegated to a dedicated automation account instead of broad groups like
system:authenticatedorsystem:authenticated:oauth?
- Document which Role/ClusterRole objects must be tightened and which subjects (users/groups/serviceaccounts) should retain pod-creation rights.
- For each role/clusterrole you found, decide:
-
Remove or narrow
createpermissions on pods in roles/clusterroles- To edit a ClusterRole:
kubectl edit clusterrole <clusterrole-name>
- To edit a namespaced Role:
kubectl edit role <role-name> -n <namespace>
- In the opened manifest, locate the rules containing
resources: ["pods"]and then:- Remove
"create"from theverbslist, or - If the entire rule is only for pod creation, delete that rule block.
- Remove
- Save and exit to apply the change.
- To edit a ClusterRole:
-
Adjust bindings so only intended subjects can create pods
- List bindings:
kubectl get clusterrolebinding,rolebinding -A -o wide
- Edit any binding that grants a pod-creating role to overly broad subjects:
kubectl edit clusterrolebinding <binding-name>kubectl edit rolebinding <binding-name> -n <namespace>
- Under
subjects:, remove or replace broad subjects (for examplesystem:authenticated, large groups) with only those users/groups/serviceaccounts that should still be able to create pods.
- List bindings:
-
Verification
- Confirm that generic authenticated users can no longer create pods:
echo "canCreatePodsAsSystemAuthenticated: $(kubectl auth can-i create pods --all-namespaces --as=system:authenticated)"
- The output should be
canCreatePodsAsSystemAuthenticated: noafter remediation.
- Confirm that generic authenticated users can no longer create pods:
Using kubectl
On any machine with kubectl access:
- Identify which RBAC bindings currently allow authenticated users to create pods
kubectl get clusterrole,role -A -o yaml \
| grep -E "^(kind: (ClusterRole|Role)| name: | verbs:| resources:)" -n
kubectl get clusterrole,role -A -o yaml \
| awk '
/kind: (ClusterRole|Role)/{k=$2}
/name: /{n=$2}
/resources:/{
if ($2 ~ /pods/) pods=1
}
/verbs:/{
if (pods && $0 ~ /create/) {
print k":"n" allows create on pods"
}
pods=0
}
'
Then for each ClusterRole/Role you decide should not be able to create pods:
- Remove
createfrom theverbslist onpods(declarative edit)
Example: for a ClusterRole named developer that currently has create on pods, first export it:
kubectl get clusterrole developer -o yaml > developer-clusterrole.yaml
Edit developer-clusterrole.yaml and in the relevant rule(s) adjust verbs so create is removed, for example change:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
to:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "update", "delete"]
Apply the change:
kubectl apply -f developer-clusterrole.yaml
Repeat this export/edit/apply pattern for each Role/ClusterRole where you want to remove pod creation.
- Optionally, break unnecessary subject bindings that grant pod creation
If a specific binding should no longer grant whatever ClusterRole/Role still has pod creation, delete that binding:
# ClusterRoleBinding example
kubectl delete clusterrolebinding developer-binding
# Namespaced RoleBinding example
kubectl delete rolebinding developer-binding -n example-namespace
Or edit bindings declaratively:
kubectl get rolebinding developer-binding -n example-namespace -o yaml > rb.yaml
# edit subjects: to remove users/groups that should not create pods
kubectl apply -f rb.yaml
- Verification
Run the audit command again from any machine with kubectl access:
echo "canCreatePodsAsSystemAuthenticated: $(kubectl auth can-i create pods --all-namespaces --as=system:authenticated)"
Automation
#!/usr/bin/env bash
#
# Purpose: Minimize access to "create pods" for system:authenticated
# Scope: Runs from any machine with kubectl access and cluster-admin privileges.
# Impact: May break workloads or users that rely on creating Pods directly.
# Review RBAC changes before applying in production.
#
# Behavior:
# - Detects all Roles/ClusterRoles that grant "create" on "pods".
# - For each, removes the "create" verb from pods while leaving all other rules intact.
# - Idempotent: safe to re-run; if "create" is already removed, nothing changes.
# - Verifies that system:authenticated cannot create pods cluster‑wide.
set -euo pipefail
echo "=== Checking current ability for system:authenticated to create pods ==="
kubectl auth can-i create pods --all-namespaces --as=system:authenticated || true
echo
# Temporary work directory
WORKDIR="$(mktemp -d)"
cleanup() {
rm -rf "${WORKDIR}"
}
trap cleanup EXIT
edit_role_manifest() {
local input="$1"
local output="$2"
# Use yq if available for safer YAML editing; otherwise fall back to jq+python.
if command -v yq >/dev/null 2>&1; then
yq '
(.rules // []) |=
map(
if (.resources // [] | index("pods")) then
.verbs |= map(select(. != "create"))
else
.
end
)
' "${input}" > "${output}"
else
# Minimal python YAML editor to remove "create" from verbs where resources include "pods"
python3 - "$input" "$output" << 'PYEOF'
import sys, copy
import yaml
src, dst = sys.argv[1], sys.argv[2]
with open(src) as f:
doc = yaml.safe_load(f)
rules = doc.get("rules") or []
for rule in rules:
resources = rule.get("resources") or []
if "pods" in resources:
verbs = rule.get("verbs") or []
rule["verbs"] = [v for v in verbs if v != "create"]
doc["rules"] = rules
with open(dst, "w") as f:
yaml.safe_dump(doc, f, default_flow_style=False)
PYEOF
fi
}
echo "=== Processing ClusterRoles that grant create on pods ==="
kubectl get clusterroles -o json | jq -r '
.items[]
| select(.rules != null)
| select(
[.rules[]
| select(.resources != null and (.resources|index("pods") != null))
| .verbs[]
] | index("create")
)
| .metadata.name
' | sort -u | while read -r CR; do
[ -z "$CR" ] && continue
echo "-> Evaluating ClusterRole: ${CR}"
orig="${WORKDIR}/clusterrole-${CR}.yaml"
mod="${WORKDIR}/clusterrole-${CR}-mod.yaml"
kubectl get clusterrole "${CR}" -o yaml > "${orig}"
edit_role_manifest "${orig}" "${mod}"
if cmp -s "${orig}" "${mod}"; then
echo " No change required (create already absent for pods)."
else
echo " Patching ClusterRole to remove create on pods..."
kubectl apply -f "${mod}"
fi
done
echo
echo "=== Processing Namespaced Roles that grant create on pods ==="
kubectl get roles --all-namespaces -o json | jq -r '
.items[]
| select(.rules != null)
| select(
[.rules[]
| select(.resources != null and (.resources|index("pods") != null))
| .verbs[]
] | index("create")
)
| [.metadata.namespace, .metadata.name]
| @tsv
' | sort -u | while IFS=$'\t' read -r NS R; do
[ -z "$NS" ] && continue
echo "-> Evaluating Role: ${NS}/${R}"
orig="${WORKDIR}/role-${NS}-${R}.yaml"
mod="${WORKDIR}/role-${NS}-${R}-mod.yaml"
kubectl get role "${R}" -n "${NS}" -o yaml > "${orig}"
edit_role_manifest "${orig}" "${mod}"
if cmp -s "${orig}" "${mod}"; then
echo " No change required (create already absent for pods)."
else
echo " Patching Role to remove create on pods..."
kubectl apply -f "${mod}"
fi
done
echo
echo "=== Verification: can system:authenticated still create pods? ==="
RESULT="$(kubectl auth can-i create pods --all-namespaces --as=system:authenticated 2>/dev/null || true)"
echo "canCreatePodsAsSystemAuthenticated: ${RESULT}"
if [ "${RESULT}" != "no" ]; then
echo
echo "WARNING: system:authenticated can still create pods somewhere in the cluster."
echo "Investigate remaining RBAC (e.g., aggregated roles, impersonation, or wildcard rules)."
else
echo
echo "SUCCESS: system:authenticated no longer has create permission on pods (per cluster-wide check)."
fi