Skip to main content

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​

Manual Steps
  1. Identify which subjects can create pods

    • Run on any machine with kubectl access:
      kubectl get clusterrole,role -A -o wide | grep -i pod
      kubectl get clusterrole -o yaml | grep -nA5 "resources:.*pods"
      kubectl get role -A -o yaml | grep -nA5 "resources:.*pods"
  2. Inspect the exact permissions granting create on pods

    • Run on any machine with kubectl access:
      kubectl get clusterrole -o yaml > /tmp/clusterroles.yaml
      kubectl get role -A -o yaml > /tmp/roles.yaml
      • Open /tmp/clusterroles.yaml and /tmp/roles.yaml and search for rules like:
        - apiGroups: [""]
        resources: ["pods"]
        verbs: ["create", "update", "delete", ...]
  3. Decide which roles should keep create on 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:authenticated or system:authenticated:oauth?
    • Document which Role/ClusterRole objects must be tightened and which subjects (users/groups/serviceaccounts) should retain pod-creation rights.
  4. Remove or narrow create permissions 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 the verbs list, or
      • If the entire rule is only for pod creation, delete that rule block.
    • Save and exit to apply the change.
  5. 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 example system:authenticated, large groups) with only those users/groups/serviceaccounts that should still be able to create pods.
  6. 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: no after remediation.
Using kubectl

On any machine with kubectl access:

  1. 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:

  1. Remove create from the verbs list on pods (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.

  1. 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
  1. 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