Minimize Access To Create Pods
More Info:
The ability to create pods can be abused to run privileged workloads or escalate privileges. This permission should be restricted to only required service accounts.
Risk Level
High
Address
Security
Compliance Standards
- CIS AKS
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all Roles/ClusterRoles that can create pods
Run on any machine with kubectl access:kubectl get clusterrole -o json \| jq -r '.items[]| select(.rules[]?| any(.apiGroups[]? == "" and .resources[]? == "pods" and .verbs[]? == "create"))| .metadata.name'kubectl get role --all-namespaces -o json \| jq -r '.items[]| select(.rules[]?| any(.apiGroups[]? == "" and .resources[]? == "pods" and .verbs[]? == "create"))| (.metadata.namespace + " " + .metadata.name)' -
Review each identified Role/ClusterRole’s scope and necessity
For each name from step 1, inspect full rules and annotations:kubectl get clusterrole <clusterrole-name> -o yamlkubectl get role -n <namespace> <role-name> -o yamlDecide whether the subjects using this role truly need to create pods, or if they could use higher‑level abstractions (Deployments/Jobs) or narrower permissions instead.
-
Identify who is bound to these Roles/ClusterRoles
For each Role/ClusterRole discovered, list RoleBindings/ClusterRoleBindings:# ClusterRole bindingskubectl get clusterrolebindings -o json \| jq -r '.items[]| select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<clusterrole-name>")| .metadata.name'# Role bindings in all namespaceskubectl get rolebindings --all-namespaces -o json \| jq -r '.items[]| select(.roleRef.kind=="Role" and .roleRef.name=="<role-name>" and .metadata.namespace=="<namespace>")| (.metadata.namespace + " " + .metadata.name)'Then inspect each binding to see which users/groups/serviceaccounts are granted pod creation:
kubectl get clusterrolebinding <binding-name> -o yamlkubectl get rolebinding -n <namespace> <binding-name> -o yaml -
Decide and implement least-privilege changes
For each combination of Role/ClusterRole and binding:- If pod creation is not required: remove
createonpodsfrom the role rules.In the editor, deletekubectl edit clusterrole <clusterrole-name>kubectl edit role -n <namespace> <role-name>createfrom theverbslist for thepodsresource, or remove the rule stanza entirely if no longer needed. - If some but not all subjects need this permission: create a new, narrowly scoped Role/ClusterRole just for those subjects, and update bindings so only those specific serviceaccounts/users/groups are bound to it.
- If pod creation is not required: remove
-
Tighten or remove unnecessary bindings
Where overly broad subjects are found (e.g., groups likesystem:authenticatedor wildcard-like coverage):- Replace broad bindings with bindings to specific service accounts or users that actually require pod creation.
- Remove RoleBindings/ClusterRoleBindings that are no longer needed:
kubectl delete clusterrolebinding <binding-name>kubectl delete rolebinding -n <namespace> <binding-name>
-
Verify that pod creation access is minimized
Re-run the evidence commands to confirm only the intended Roles/ClusterRoles retain pod creation:kubectl get clusterrole -o json | jq -r '.items[]| select(.rules[]?| any(.apiGroups[]? == "" and .resources[]? == "pods" and .verbs[]? == "create"))| .metadata.name'kubectl get role --all-namespaces -o json | jq -r '.items[]| select(.rules[]?| any(.apiGroups[]? == "" and .resources[]? == "pods" and .verbs[]? == "create"))| (.metadata.namespace + " " + .metadata.name)'Confirm that each remaining role with
createonpodsis intentionally required and bound only to the minimal set of subjects.
Using kubectl
Using kubectl
Run the following from any machine with kubectl access.
- List all Roles/ClusterRoles that can create pods
kubectl get clusterrole -o json \
| jq -r '.items[]
| select(.rules[]?
| (.verbs[]? | contains("create"))
and (.resources[]? | contains("pods")))
| .metadata.name' \
| sort -u
kubectl get role --all-namespaces -o json \
| jq -r '.items[]
| select(.rules[]?
| (.verbs[]? | contains("create"))
and (.resources[]? | contains("pods")))
| "\(.metadata.namespace)/\(.metadata.name)"' \
| sort -u
Problem indication: Any role/clusterrole appears here that is not clearly intended to create pods (for example, broad “admin”-style roles granted to many subjects, or generic application roles).
- Inspect detailed rules for each identified role
For ClusterRoles (replace <clusterrole-name> with each name from step 1):
kubectl get clusterrole <clusterrole-name> -o yaml
For Roles (replace <namespace> and <role-name>):
kubectl get role -n <namespace> <role-name> -o yaml
In the rules section, look for:
resources: ["pods"](or includingpods)verbs: ["create"](or includingcreateor*)
Problem indication:
Rules that allow create on pods (directly, via * verbs, or via * resources) tied to functions that do not strictly require pod creation, or overly broad rules (e.g., verbs: ["*"] or resources: ["*"]).
- See who is bound to these Roles/ClusterRoles
For each ClusterRole:
kubectl get clusterrolebinding -o yaml \
| yq '.items[]
| select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<clusterrole-name>")'
For each namespaced Role:
kubectl get rolebinding -n <namespace> -o yaml \
| yq '.items[]
| select(.roleRef.kind == "Role" and .roleRef.name == "<role-name>")'
Problem indication:
Bindings that grant these permissions to:
system:authenticated,system:unauthenticated, or other large groups.- Generic groups like “developers” or many service accounts that do not need to create pods.
- User/service account identities where pod creation is not part of their function.
- Quick check for obviously over‑broad bindings
kubectl get clusterrolebinding -o json \
| jq -r '.items[]
| select(.subjects[]?
| (.name == "system:authenticated" or .name == "system:unauthenticated"))
| .metadata.name' \
| sort -u
kubectl get clusterrolebinding -o yaml | grep -E "system:authenticated|system:unauthenticated" -n
Problem indication:
Any of these broad subjects bound to roles that have create on pods from step 1.
- Verification after manual adjustments
After you manually edit Roles/ClusterRoles/Bindings (with kubectl edit or manifests), re-run:
kubectl get clusterrole -o json | jq -r '.items[]
| select(.rules[]?
| (.verbs[]? | contains("create"))
and (.resources[]? | contains("pods")))
| .metadata.name' | sort -u
kubectl get role --all-namespaces -o json | jq -r '.items[]
| select(.rules[]?
| (.verbs[]? | contains("create"))
and (.resources[]? | contains("pods")))
| "\(.metadata.namespace)/\(.metadata.name)"' | sort -u
Then re-check bindings for any remaining roles that still have pod create and confirm they are restricted only to the specific service accounts/users that truly require this capability.
Automation
#!/usr/bin/env bash
set -euo pipefail
# This script inspects Roles and ClusterRoles that can create pods.
# Run on any machine with kubectl access and a context pointing to the target cluster.
echo "=== ClusterRoles with 'create' on pods ==="
kubectl get clusterroles -o json \
| jq -r '
.items[]
| . as $cr
| [
$cr.metadata.name,
(
[
.rules[]
| select(
(.resources // []) | index("pods")
and
(.verbs // []) | index("create")
)
] | length
)
]
| select(.[1] > 0)
| .[0]
' | sort | uniq \
| while read -r cr; do
echo "ClusterRole: $cr"
kubectl get clusterrole "$cr" -o yaml
echo "-----"
done
echo
echo "=== Roles with 'create' on pods (all namespaces) ==="
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| . as $r
| [
$r.metadata.namespace,
$r.metadata.name,
(
[
.rules[]
| select(
(.resources // []) | index("pods")
and
(.verbs // []) | index("create")
)
] | length
)
]
| select(.[2] > 0)
| .[0] + " " + .[1]
' | sort \
| while read -r ns name; do
echo "Role: $name (namespace: $ns)"
kubectl get role "$name" -n "$ns" -o yaml
echo "-----"
done
echo
echo "=== RoleBindings and ClusterRoleBindings referencing those roles ==="
echo "# ClusterRoleBindings using ClusterRoles that can create pods"
kubectl get clusterrolebindings -o json \
| jq -r '
.items[]
| select(.roleRef.kind == "ClusterRole")
| . as $rb
| $rb.roleRef.name as $crName
| $rb.metadata.name + " " + $crName
' | while read -r rb cr; do
# Check if this ClusterRole is in the risky set (can create pods)
if kubectl get clusterrole "$cr" -o json 2>/dev/null \
| jq -e '
[
.rules[]
| select(
(.resources // []) | index("pods")
and
(.verbs // []) | index("create")
)
] | length > 0
' >/dev/null
then
echo "ClusterRoleBinding: $rb -> ClusterRole: $cr"
kubectl get clusterrolebinding "$rb" -o yaml
echo "-----"
fi
done
echo
echo "# RoleBindings using Roles that can create pods"
kubectl get rolebindings --all-namespaces -o json \
| jq -r '
.items[]
| select(.roleRef.kind == "Role")
| .metadata.namespace + " " + .metadata.name + " " + .roleRef.name
' | while read -r ns rb role; do
if kubectl get role "$role" -n "$ns" -o json 2>/dev/null \
| jq -e '
[
.rules[]
| select(
(.resources // []) | index("pods")
and
(.verbs // []) | index("create")
)
] | length > 0
' >/dev/null
then
echo "RoleBinding: $rb (namespace: $ns) -> Role: $role"
kubectl get rolebinding "$rb" -n "$ns" -o yaml
echo "-----"
fi
done
cat <<'EOF'
How to interpret this output:
1. Any ClusterRole or Role shown has the ability to create pods somewhere in the cluster.
2. For each such Role/ClusterRole, review:
- rules: ensure "resources: [pods]" with "verbs: [create]" is truly required.
- scope: wide-scoped roles (e.g., in kube-system, default, or custom infra namespaces) deserve extra scrutiny.
3. For each associated RoleBinding/ClusterRoleBinding:
- Check the `subjects` section (users, groups, service accounts).
- Investigate whether each subject actually needs to create pods.
- Service accounts that do not run controllers, operators, or deployment tools typically should NOT need pod creation rights.
Potential problem indicators:
- Generic or broad roles (e.g., "admin", "edit", custom "dev-*") that grant create on pods and are bound to many users or groups.
- ClusterRoles with create on pods bound via ClusterRoleBinding to:
- `system:authenticated`, `system:unauthenticated`, or large identity groups (e.g., "Developers", "Everyone").
- Service accounts in application namespaces that are not part of a deployment/orchestration component but still have create on pods.
Use `kubectl edit role -n <namespace> <role>` and
`kubectl edit clusterrole <name>` to manually apply least privilege,
removing "create" on "pods" where it is not strictly required.
EOF