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
- 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
-
List all Roles and ClusterRoles that can create pods
- Run on: any machine with kubectl access
# Roles (namespaced)kubectl get roles --all-namespaces -o json \| jq -r '.items[]| select(.rules[]| select((.resources // []) | index("pods"))| select((.verbs // []) | index("create")))| "\(.metadata.namespace)\t\(.metadata.name)"' | sort# ClusterRoles (cluster-wide)kubectl get clusterroles -o json \| jq -r '.items[]| select(.rules[]| select((.resources // []) | index("pods"))| select((.verbs // []) | index("create")))| .metadata.name' | sort -
Identify who is bound to these Roles/ClusterRoles
- Run on: any machine with kubectl access
# ClusterRoleBindingskubectl get clusterrolebindings -o wide# RoleBindings in all namespaceskubectl get rolebindings --all-namespaces -o wide- Manually correlate
roleRef.namewith the Roles/ClusterRoles from step 1 and note thesubjects(users, groups, service accounts) receiving pod-create permissions.
-
Evaluate business/technical necessity of each binding
- For each subject-role pair identified:
- Determine what workload or team uses it (via namespace, service account name, or label conventions).
- Confirm whether that subject truly needs to create pods (e.g., operators, CI/CD systems) or only needs lower privileges (e.g., manage existing pods but not create new ones).
- Document cases where pod creation is not strictly required.
- For each subject-role pair identified:
-
Remove or tighten unnecessary pod-create permissions
- Run on: any machine with kubectl access
- For a Role that should no longer be able to create pods, edit and remove
createfromverbsor the entire pods rule if not needed:
kubectl edit role -n <namespace> <role-name>- For a ClusterRole:
kubectl edit clusterrole <clusterrole-name>- In the opened editor, find rules like:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "list", "watch", "create", "delete"]- Remove
create(anddeleteif not required), then save:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "list", "watch"] -
Re-scope overly broad bindings to least privilege
- If a ClusterRole must retain pod-create for a narrow use case:
- Prefer binding it only to specific service accounts instead of user/group wildcards.
- Consider replacing a broad ClusterRole with a more restrictive Role in a specific namespace:
# Example: create a namespaced Role with limited pod accesskubectl create role pod-creator -n <namespace> \--verb=create --resource=pods# Bind it only to the intended service accountkubectl create rolebinding pod-creator-binding -n <namespace> \--role=pod-creator \--serviceaccount=<namespace>:<service-account-name> - Remove or update old RoleBindings/ClusterRoleBindings that granted wider access than needed:
kubectl delete rolebinding -n <namespace> <binding-name>kubectl delete clusterrolebinding <binding-name> - If a ClusterRole must retain pod-create for a narrow use case:
-
Verify the reduced pod-create surface
- Run on: any machine with kubectl access
# Re-run evidence collectionkubectl get roles --all-namespaces -o json \| jq -r '.items[]| select(.rules[]| select((.resources // []) | index("pods"))| select((.verbs // []) | index("create")))| "\(.metadata.namespace)\t\(.metadata.name)"' | sortkubectl get clusterroles -o json \| jq -r '.items[]| select(.rules[]| select((.resources // []) | index("pods"))| select((.verbs // []) | index("create")))| .metadata.name' | sort- Confirm that only justified roles/clusterroles retain
createonpodsand that their bindings are limited to the minimum necessary subjects.
Using kubectl
# 1) List all Roles that can create pods (any machine with kubectl access)
kubectl get roles -A -o json \
| jq -r '
.items[]
| select(
.rules[]
| (.verbs[]? | IN("create")) and
(.resources[]? | IN("pods"))
)
| [.metadata.namespace, .metadata.name] | @tsv
' | sort
Output indicates potential risk: any line is a Role (namespace and name) that grants pod creation. Each must be manually reviewed for necessity and scope.
# 2) Show full definitions of those Roles for review
# (replace <namespace> and <role> values from previous output)
kubectl get role -n <namespace> <role> -o yaml
Concerning patterns in rules:
verbs: ["*"]or includescreateresources: ["*"]or includespods- Very broad
apiGroups: ["*"]
# 3) List all ClusterRoles that can create pods
kubectl get clusterroles -o json \
| jq -r '
.items[]
| select(
.rules[]
| (.verbs[]? | IN("create")) and
(.resources[]? | IN("pods"))
)
| .metadata.name
' | sort
Any name in the output is a ClusterRole that can create pods anywhere in the cluster and must be reviewed.
# 4) Show full ClusterRole definitions for review
kubectl get clusterrole <clusterrole-name> -o yaml
Problematic indicators in rules are the same: verbs including create (or "*"), and resources including pods (or "*"), especially on generic or widely used roles.
# 5) See which subjects are bound to each risky Role / ClusterRole
# 5a) For a namespace Role
kubectl get rolebinding -n <namespace> -o wide
kubectl get rolebinding -n <namespace> -o yaml
# 5b) For a ClusterRole
kubectl get clusterrolebinding -o wide
kubectl get clusterrolebinding -o yaml
Concerning patterns in bindings:
subjectsthat are broad (e.g.,kind: Groupwith many users,system:authenticated)- Bindings in many namespaces to the same powerful ClusterRole
- ServiceAccounts that do not clearly need pod-creation but are bound to such roles.
These commands only surface the current state. Deciding whether to remove or narrow create on pods and adjusting bindings requires human review of each role’s actual use.
Automation
#!/usr/bin/env bash
#
# Report all Roles and ClusterRoles that can create pods,
# and which subjects (users/groups/serviceaccounts) are bound to them.
#
# Run on: any machine with kubectl access and appropriate RBAC to list roles/bindings.
set -euo pipefail
echo "=== ClusterRoles with 'create' on 'pods' and their ClusterRoleBindings ==="
echo
# 1) ClusterRoles with create on pods
kubectl get clusterroles -o json \
| jq -r '
.items[]
| select(
.rules[]
| select(
((.resources // []) | index("pods"))
and
((.verbs // []) | index("create"))
)
)
| .metadata.name
' | sort -u | while read -r cr; do
[[ -z "$cr" ]] && continue
echo "ClusterRole: ${cr}"
echo " Rules:"
kubectl get clusterrole "$cr" -o json \
| jq -r '
.rules[]
| select(
((.resources // []) | index("pods"))
and
((.verbs // []) | index("create"))
)
' | sed 's/^/ /'
echo " Bound via ClusterRoleBindings:"
kubectl get clusterrolebindings -o json \
| jq -r --arg CR "$cr" '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name==$CR)
| " CRB: \(.metadata.name)\n" +
( .subjects // [] | map(" subject: \(.kind) \(.namespace // "-")/\(.name)") | join("\n") )
' | sed 's/^/ /'
echo
done
echo
echo "=== Namespaced Roles with 'create' on 'pods' and their RoleBindings ==="
echo
# 2) Namespaced Roles with create on pods, per namespace
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort); do
echo "Namespace: ${ns}"
# Roles
roles_with_create_pods=$(kubectl get roles -n "$ns" -o json \
| jq -r '
.items[]
| select(
.rules[]
| select(
((.resources // []) | index("pods"))
and
((.verbs // []) | index("create"))
)
)
| .metadata.name
' | sort -u)
if [[ -z "${roles_with_create_pods}" ]]; then
echo " (no Roles with create on pods)"
echo
continue
fi
while read -r role; do
[[ -z "$role" ]] && continue
echo " Role: ${role}"
echo " Rules:"
kubectl get role "$role" -n "$ns" -o json \
| jq -r '
.rules[]
| select(
((.resources // []) | index("pods"))
and
((.verbs // []) | index("create"))
)
' | sed 's/^/ /'
echo " Bound via RoleBindings:"
kubectl get rolebindings -n "$ns" -o json \
| jq -r --arg ROLE "$role" '
.items[]
| select(.roleRef.kind=="Role" and .roleRef.name==$ROLE)
| " RB: \(.metadata.name)\n" +
( .subjects // [] | map(" subject: \(.kind) \(.namespace // "-")/\(.name)") | join("\n") )
' | sed 's/^/ /'
echo
done <<< "$roles_with_create_pods"
echo
done
Explanation of output indicating a problem:
- Focus on Roles/ClusterRoles that:
- Grant
verbsincludingcreateonresourcesincludingpods.
- Grant
- Potentially problematic patterns to review manually:
- Broad roles like
*verbs or*resources that include pod creation. - Roles/ClusterRoles bound to:
system:authenticated,system:unauthenticated, or large user groups.- Service accounts in namespaces that should not be able to create pods.
- Human users who don’t need pod-creation privileges.
- Broad roles like
- For any such role/subject combination, decide whether:
- Pod creation rights are truly required; if not, remove the binding or the rule.
- Pod creation rights should be limited to a narrower set of service accounts or namespaces.
Use the names shown (Role/ClusterRole and RoleBinding/ClusterRoleBinding plus subjects) as inputs to manual review and RBAC edits (kubectl edit role, kubectl edit clusterrole, kubectl edit rolebinding, kubectl edit clusterrolebinding) following least privilege.