Skip to main content

Minimize Access To Create Pods

More Info:

The ability to create pods can be abused to run privileged workloads or bypass admission controls. Restrict create access to pod objects to only the subjects that require it.

Risk Level

High

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. List all roles/clusterroles that can create pods

    • Run on: any machine with kubectl access
    • Command:
      kubectl get clusterrole,role -A -o json \
      | jq -r '.items[]
      | select(.rules[]?
      | any(.apiGroups[]? == "" and .resources[]? == "pods" and (.verbs[]? == "create" or .verbs[]? == "*")))
      | (.kind + "/" + .metadata.name + " (ns: " + (.metadata.namespace // "-cluster-") + ")")'
  2. Identify which subjects are bound to those roles

    • Run on: any machine with kubectl access
    • For each name from step 1, get the bindings:
      # Example for a ClusterRole
      kubectl get clusterrolebindings.rbac.authorization.k8s.io -o yaml \
      | yq '.items[] | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")'

      # Example for a namespaced Role
      kubectl get rolebindings.rbac.authorization.k8s.io -A -o yaml \
      | yq '.items[] | select(.roleRef.kind == "Role" and .roleRef.name == "<ROLE_NAME>")'
    • Record which users, groups, and service accounts have pod create access, and in which namespaces.
  3. Decide which subjects truly need pod creation capability

    • For each subject from step 2, review:
      • What application or team it belongs to.
      • Whether it must create pods (e.g., controllers, CI/CD, autoscalers) or only needs to manage higher‑level objects (Deployments, Jobs, etc.).
    • Document for each subject: “needs pod create” or “does not need pod create”.
  4. Remove unnecessary pod create verbs from roles

    • Run on: any machine with kubectl access
    • For each Role/ClusterRole where some or all subjects do not need pod creation:
      a) If no bound subjects need pod creation, remove the create (and * if present) verb for pods from the rule:
      kubectl edit clusterrole <CLUSTERROLE_NAME>
      # or
      kubectl edit role -n <NAMESPACE> <ROLE_NAME>
      • In the editor, locate rules with:
        apiGroups: [""]
        resources: ["pods"]
        verbs: ["create", ...] # or ["*"]
        and remove create (or replace * with the minimal required verbs excluding create).
        b) If some subjects still require pod creation but others do not, create a new limited role and rebind:
      kubectl create role <NEW_ROLE_NAME> \
      --verb=get,list,watch,update,patch,delete \
      --resource=pods \
      -n <NAMESPACE>

      kubectl create rolebinding <NEW_BINDING_NAME> \
      --role=<NEW_ROLE_NAME> \
      --serviceaccount=<NAMESPACE>:<SERVICEACCOUNT_NAME> \
      -n <NAMESPACE>
      • Then remove the unnecessary subjects from the original binding via:
        kubectl edit rolebinding -n <NAMESPACE> <OLD_BINDING_NAME>
  5. Revalidate effective permissions after changes

    • Run on: any machine with kubectl access
    • For each key subject, confirm whether it can still create pods:
      # For a user
      kubectl auth can-i create pods --as=<USER_NAME> -n <NAMESPACE>

      # For a service account
      kubectl auth can-i create pods \
      --as=system:serviceaccount:<NAMESPACE>:<SA_NAME> \
      -n <NAMESPACE>
    • Expect no for all subjects that do not require pod creation, and yes only for explicitly approved subjects.
  6. Periodic review and evidence collection

    • Run on: any machine with kubectl access
    • Capture current state for audit purposes and future reviews:
      kubectl get clusterrole,role -A -o yaml > pod-create-roles-snapshot.yaml
      kubectl get clusterrolebinding,rolebinding -A -o yaml > pod-create-bindings-snapshot.yaml
    • Schedule periodic re‑runs of steps 1–5 or integrate them into CI/CD or policy-as-code to ensure ongoing minimization of pod create access.
Using kubectl
# 1) List all ClusterRoles that can create pods
# Run on: any machine with kubectl access

kubectl get clusterroles -o json | \
jq -r '
.items[]
| select(
.rules[]
| select(
(.verbs | index("create"))
and
(.resources | index("pods"))
)
)
| .metadata.name
' | sort -u

Problem indication: Any ClusterRole listed here grants create on pods. Every such role must be reviewed to confirm it’s truly needed.


# 2) Show full definitions of those ClusterRoles for review
# Replace <ROLE_NAME> with each name from the previous command

kubectl get clusterrole <ROLE_NAME> -o yaml

What to look for in the output (problem indications):

  • resources: ["pods"] or resources: ["*"] combined with verbs including "create" or "*".
  • Broad use of apiGroups: ["*"] or resources: ["*"] where pod creation is not clearly necessary.
  • ClusterRoles with pod-create rights that are clearly generic (e.g. edit, admin, custom “developer” roles) rather than narrowly scoped operational roles.

# 3) Find which subjects are bound to those ClusterRoles
# Run for each ClusterRole identified

kubectl get clusterrolebindings -o json | \
jq -r '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<ROLE_NAME>")
| "ClusterRoleBinding: \(.metadata.name)\n Subjects: \(.subjects // [])"
'

Problem indication: Highly privileged or generic subjects (e.g. broad groups like system:authenticated, developers, or many service accounts across namespaces) bound to ClusterRoles that can create pods.


# 4) Find RoleBindings in namespaces that reference ClusterRoles granting pod create
# Replace <ROLE_NAME> with each name from step 1

kubectl get rolebindings --all-namespaces -o json | \
jq -r '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<ROLE_NAME>")
| "Namespace: \(.metadata.namespace)\n RoleBinding: \(.metadata.name)\n Subjects: \(.subjects // [])"
'

Problem indication: Namespaced RoleBindings exposing pod-create rights via ClusterRoles to many users or generic groups across multiple namespaces.


# 5) Check namespace-scoped Roles that can create pods
kubectl get roles --all-namespaces -o json | \
jq -r '
.items[]
| select(
.rules[]
| select(
(.verbs | index("create"))
and
(.resources | index("pods"))
)
)
| "Namespace: \(.metadata.namespace) Role: \(.metadata.name)"
' | sort

Problem indication: Roles in many namespaces granting pod create to non-operational subjects or generic “developer”/“default” subjects, indicating pod creation is widely available.


Interpretation guidance (manual decision):

  • Acceptable: tightly scoped Roles/ClusterRoles used by:
    • CI/CD or controllers that must create pods.
    • Operational teams in specific namespaces where pod creation is required.
  • Concerning:
    • Global or semi-global roles bound to large groups (system:authenticated, all developers).
    • Roles where resources: ["*"] and verbs: ["*"] or "create" are present without a clear operational justification.
    • Service accounts in many namespaces that can create pods despite not being controllers.
Automation
#!/usr/bin/env bash
#
# Report subjects that can create pods, cluster-wide and per-namespace.
# Run from: any machine with kubectl access and correct context.
# Requirements: bash, kubectl, jq

set -euo pipefail

echo "=== Cluster-wide (ClusterRole/ClusterRoleBinding) pod CREATE permissions ==="
echo

# 1) All ClusterRoles that grant create on pods
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null
and any(.rules[]?;
(.apiGroups // []) | index("") != null
and (.resources // []) | index("pods") != null
and (.verbs // []) | index("create") != null
)
)
| .name
' | sort -u | while read -r cr; do
echo "ClusterRole: ${cr}"
# Show exact rules that allow pod create
kubectl get clusterrole "${cr}" -o json \
| jq -r '
.rules[]
| select(
(.apiGroups // []) | index("") != null
and (.resources // []) | index("pods") != null
and (.verbs // []) | index("create") != null
)
' | jq .
echo

echo " Bound via ClusterRoleBindings to:"
kubectl get clusterrolebindings -o json \
| jq -r --arg CR "${cr}" '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name==$CR)
| .metadata.name as $crb
| .subjects[]?
| "\($crb)\t\(.kind)\t\(.namespace // "-")\t\(.name)"
' 2>/dev/null | sort -u || true
echo
echo "-------------------------------------------------------------------"
echo
done

echo
echo "=== Namespace-scoped (Role/RoleBinding) pod CREATE permissions ==="
echo

# 2) All Roles that grant create on pods, per-namespace
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null
and any(.rules[]?;
(.apiGroups // []) | index("") != null
and (.resources // []) | index("pods") != null
and (.verbs // []) | index("create") != null
)
)
| "\(.ns)\t\(.name)"
' | sort -u | while IFS=$'\t' read -r ns role; do
echo "Role: ${role} (namespace: ${ns})"
# Show exact rules that allow pod create
kubectl get role "${role}" -n "${ns}" -o json \
| jq -r '
.rules[]
| select(
(.apiGroups // []) | index("") != null
and (.resources // []) | index("pods") != null
and (.verbs // []) | index("create") != null
)
' | jq .
echo

echo " Bound via RoleBindings to:"
kubectl get rolebindings -n "${ns}" -o json \
| jq -r --arg ROLE "${role}" '
.items[]
| select(.roleRef.kind=="Role" and .roleRef.name==$ROLE)
| .metadata.name as $rb
| .subjects[]?
| "\($rb)\t\(.kind)\t\(.namespace // "-")\t\(.name)"
' 2>/dev/null | sort -u || true
echo
echo "-------------------------------------------------------------------"
echo
done

cat <<'EOF'

How to interpret this report:

- Every listed ClusterRole or Role has rules allowing "create" on core "pods".
- For each such role, the script shows:
- The exact rule blocks that grant create on pods.
- Which users/groups/serviceaccounts (subjects) receive that permission via bindings.

Potential problems to investigate:

- Any subject that does not strictly need to create pods in production or sensitive namespaces.
- Broad subjects such as:
- "system:authenticated", "system:unauthenticated", or large identity groups.
- Wildcard subjects (e.g., many service accounts bound via a shared group).
- Bindings in critical namespaces (kube-system, kube-public, security-sensitive app namespaces)
where pod creation should be tightly controlled.

Use this report to decide, case by case, which roles/bindings should be narrowed or removed.
There is no safe one-size-fits-all automated removal for this permission; changes must follow
your change-management and application requirements review.

EOF