> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Minimize Access To The Service Account Token Creation

### More Info:

Access to create the token sub-resource of ServiceAccounts can be used to obtain persistent unauthorized access to the cluster. It should be limited to trusted administrators only.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On any machine with kubectl access, list all Roles/ClusterRoles that can create service account tokens (directly or via wildcards):
           ```sh theme={null}
           kubectl get clusterroles -o json \
             | jq -r '.items[]
               | select(.rules[]?
                 | select(
                     (.apiGroups[]? == "") and
                     (.resources[]? | test("^serviceaccounts(/token)?$")) and
                     (.verbs[]? | test("^(create|\\*)$"))
                   )
               )
               | .metadata.name' | sort -u

           kubectl get roles --all-namespaces -o json \
             | jq -r '.items[]
               | select(.rules[]?
                 | select(
                     (.apiGroups[]? == "") and
                     (.resources[]? | test("^serviceaccounts(/token)?$")) and
                     (.verbs[]? | test("^(create|\\*)$"))
                   )
               )
               | [.metadata.namespace, .metadata.name] | @tsv' | sort
           ```

        2. For each identified Role/ClusterRole, review the exact rules to confirm whether they include `serviceaccounts/token` or overly broad patterns:
           ```sh theme={null}
           # ClusterRole example
           kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml

           # Role example
           kubectl get role <ROLE_NAME> -n <NAMESPACE> -o yaml
           ```
           Assess whether `create` on `serviceaccounts/token`, `serviceaccounts`, or `*` is strictly required for that role’s purpose.

        3. Identify who is actually getting this permission by listing RoleBindings/ClusterRoleBindings that reference each Role/ClusterRole:
           ```sh theme={null}
           kubectl get rolebindings --all-namespaces -o json \
             | jq -r --arg ROLE "<ROLE_NAME>" '
               .items[]
               | select(.roleRef.kind=="Role" and .roleRef.name==$ROLE)
               | [.metadata.namespace, .metadata.name, .subjects[]?.kind, .subjects[]?.name] | @tsv' | sort

           kubectl get clusterrolebindings -o json \
             | jq -r --arg CR "<CLUSTERROLE_NAME>" '
               .items[]
               | select(.roleRef.kind=="ClusterRole" and .roleRef.name==$CR)
               | [.metadata.name, .subjects[]?.kind, .subjects[]?.namespace, .subjects[]?.name] | @tsv' | sort
           ```
           Decide whether each subject (user, group, or service account) is a trusted administrator that should retain this ability.

        4. For non-administrative or unnecessary subjects, remove or adjust bindings so they no longer inherit token creation:
           ```sh theme={null}
           # Remove an entire binding that only exists to grant this right
           kubectl delete rolebinding <BINDING_NAME> -n <NAMESPACE>
           kubectl delete clusterrolebinding <BINDING_NAME>

           # Or edit to point to a safer Role/ClusterRole without token creation
           kubectl edit rolebinding <BINDING_NAME> -n <NAMESPACE>
           kubectl edit clusterrolebinding <BINDING_NAME>
           ```
           When editing, ensure the referenced Role/ClusterRole does not include `serviceaccounts/token` or wildcard rules granting it.

        5. Where a Role/ClusterRole has broader permissions than needed (e.g., `resources: ["serviceaccounts", "serviceaccounts/token", "*"]` or `verbs: ["create", "*"]`), refine it:
           ```sh theme={null}
           kubectl edit clusterrole <CLUSTERROLE_NAME>
           kubectl edit role <ROLE_NAME> -n <NAMESPACE>
           ```
           Remove `serviceaccounts/token` and any unnecessary wildcards, preserving only the minimal set of verbs and resources truly required.

        6. Verify that only intended administrative roles can still create service account tokens:
           ```sh theme={null}
           # Re-run evidence collection
           kubectl get clusterroles -o json | jq -r '...same jq as in step 1...'
           kubectl get roles --all-namespaces -o json | jq -r '...same jq as in step 1...'
           ```
           Confirm that any remaining roles with `create` on `serviceaccounts/token` (or equivalent wildcard) are bound only to trusted administrator identities.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) List all ClusterRoles that can create serviceaccount tokens
        # Run on: any machine with kubectl access
        kubectl get clusterroles -o json \
          | jq -r '
            .items[]
            | select(
                .rules[]
                | select(
                    (.apiGroups // [""]) | index("")
                  )
                  | select(
                      (.resources // []) | index("serviceaccounts/token")
                    )
                  | select(
                      (.verbs // []) | index("create")
                    )
              )
            | .metadata.name
          ' | sort -u
        ```

        **Problem indication:** Any returned ClusterRole is capable of creating service account tokens. Every such role must be reviewed to ensure it is intended only for trusted administrators.

        ```bash theme={null}
        # 2) Inspect the detailed rules of each suspicious ClusterRole
        # Replace <clusterrole-name> with one from the previous command
        kubectl get clusterrole <clusterrole-name> -o yaml
        ```

        **What to look for as problematic:**

        * `resources:` includes `serviceaccounts/token` (or `serviceaccounts` with `*` that covers sub-resources)
        * `verbs:` includes `create` or `*`
        * Role name/description does not clearly indicate “admin” or privileged use
        * Rules are overly broad, e.g.:
          * `resources: ["*"]` or `["serviceaccounts", "serviceaccounts/token"]`
          * `verbs: ["*"]` or includes unrelated high-privilege verbs (`impersonate`, `bind`, `escalate`)

        ```bash theme={null}
        # 3) Find which ClusterRoleBindings/RoleBindings grant these ClusterRoles to subjects
        # Run once per suspicious ClusterRole
        kubectl get clusterrolebindings -o json \
          | jq -r '
            .items[]
            | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<clusterrole-name>")
            | .metadata.name
          ' | sort -u
        ```

        ```bash theme={null}
        # 4) Inspect each binding to see who actually gets this privilege
        kubectl get clusterrolebinding <binding-name> -o yaml
        ```

        **Problem indication:**

        * `subjects:` includes:
          * Broad groups like `system:authenticated`, `system:serviceaccounts`, `system:serviceaccounts:<namespace>`, or `system:masters`-equivalents where that group is not strictly controlled
          * Generic or many service accounts, instead of a single, well-known admin account
          * External identities (OIDC, AAD, etc.) mapped from large user groups

        ```bash theme={null}
        # 5) Check namespace-scoped Roles that may also allow token creation
        kubectl get roles --all-namespaces -o json \
          | jq -r '
            .items[]
            | select(
                .rules[]
                | select(
                    (.apiGroups // [""]) | index("")
                  )
                  | select(
                      (.resources // []) | index("serviceaccounts/token")
                    )
                  | select(
                      (.verbs // []) | index("create")
                    )
              )
            | "\(.metadata.namespace):\(.metadata.name)"
          ' | sort -u
        ```

        ```bash theme={null}
        # 6) Inspect each suspicious Role and its bindings
        kubectl get role -n <namespace> <role-name> -o yaml
        kubectl get rolebindings -n <namespace> -o json \
          | jq -r '
            .items[]
            | select(.roleRef.kind=="Role" and .roleRef.name=="<role-name>")
            | .metadata.name
          ' | sort -u

        kubectl get rolebinding -n <namespace> <binding-name> -o yaml
        ```

        **Problem indication (namespace Roles/RoleBindings):**

        * Any non-admin workload service account given `create` on `serviceaccounts/token`
        * Roles bound to many service accounts in an application namespace
        * Roles intended for application use (e.g., `app-*-role`) that include `serviceaccounts/token` with `create`

        ```bash theme={null}
        # 7) Verification after changes (re-run discovery)
        kubectl get clusterroles -o json \
          | jq -r '
            .items[]
            | select(
                .rules[]
                | select(
                    (.apiGroups // [""]) | index("")
                  )
                  | select(
                      (.resources // []) | index("serviceaccounts/token")
                    )
                  | select(
                      (.verbs // []) | index("create")
                    )
              )
            | .metadata.name
          ' | sort -u

        kubectl get roles --all-namespaces -o json \
          | jq -r '
            .items[]
            | select(
                .rules[]
                | select(
                    (.apiGroups // [""]) | index("")
                  )
                  | select(
                      (.resources // []) | index("serviceaccounts/token")
                    )
                  | select(
                      (.verbs // []) | index("create")
                    )
              )
            | "\(.metadata.namespace):\(.metadata.name)"
          ' | sort -u
        ```

        **Healthy state:** Only tightly controlled, clearly administrative roles (and their bindings) appear in this output. Any role used by regular workloads or broad groups should not have `create` on `serviceaccounts/token`.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Run on: any machine with kubectl access and appropriate permissions
        # Purpose: Report Roles/ClusterRoles that can create the `token` sub-resource on ServiceAccounts

        set -euo pipefail

        echo "=== ClusterRoles with access to create serviceaccount 'token' sub-resource ==="
        kubectl get clusterroles -o json \
          | jq -r '
            .items[]
            | {
                name: .metadata.name,
                rules: (
                  .rules // []
                  | map(
                      select(
                        ((.apiGroups // []) | index("")). // core API group
                        and
                        ((.resources // []) | index("serviceaccounts/token")) and
                        ((.verbs // []) | index("create"))
                      )
                    )
                )
              }
            | select(.rules | length > 0)
            | "- ClusterRole: \(.name)\n  Rules:\n" +
              ( .rules[]
                | "    apiGroups: \((.apiGroups // []) | join(\",\"))\n" +
                  "    resources: \((.resources // []) | join(\",\"))\n" +
                  "    verbs: \((.verbs // []) | join(\",\"))\n"
              )
          '

        echo
        echo "=== Namespaced Roles with access to create serviceaccount 'token' sub-resource ==="
        kubectl get roles --all-namespaces -o json \
          | jq -r '
            .items[]
            | {
                name: .metadata.name,
                namespace: .metadata.namespace,
                rules: (
                  .rules // []
                  | map(
                      select(
                        ((.apiGroups // []) | index("")). // core API group
                        and
                        ((.resources // []) | index("serviceaccounts/token")) and
                        ((.verbs // []) | index("create"))
                      )
                    )
                )
              }
            | select(.rules | length > 0)
            | "- Role: \(.name)\n  Namespace: \(.namespace)\n  Rules:\n" +
              ( .rules[]
                | "    apiGroups: \((.apiGroups // []) | join(\",\"))\n" +
                  "    resources: \((.resources // []) | join(\",\"))\n" +
                  "    verbs: \((.verbs // []) | join(\",\"))\n"
              )
          '

        echo
        echo "=== Bindings that grant these permissions (by subject) ==="

        # Helper: list all ClusterRoleBindings and RoleBindings in a compact form
        echo "--- ClusterRoleBindings ---"
        kubectl get clusterrolebindings -o json \
          | jq -r '
            .items[]
            | "- ClusterRoleBinding: \(.metadata.name)\n" +
              "  ClusterRole: \(.roleRef.kind)/\(.roleRef.name)\n" +
              "  Subjects:\n" +
              ( (.subjects // [])
                | map("    kind=\(.kind) name=\(.name) namespace=\(.namespace // \"-\")")
                | join("\n")
              )
          '

        echo
        echo "--- RoleBindings ---"
        kubectl get rolebindings --all-namespaces -o json \
          | jq -r '
            .items[]
            | "- RoleBinding: \(.metadata.name)\n" +
              "  Namespace: \(.metadata.namespace)\n" +
              "  Role: \(.roleRef.kind)/\(.roleRef.name)\n" +
              "  Subjects:\n" +
              ( (.subjects // [])
                | map("    kind=\(.kind) name=\(.name) namespace=\(.namespace // \"-\")")
                | join("\n")
              )
          '

        cat <<'EOF'

        INTERPRETING THE OUTPUT
        -----------------------
        1) Any ClusterRole or Role listed in the first two sections has the ability to create the
           'token' sub-resource on ServiceAccounts. These are sensitive permissions.

           Potential problems include:
           - Generic or broad names suggesting non-admin use, e.g.:
             - "edit", "view", "developer", "ci", "automation", "default", "system:*"
           - Roles intended for applications, service accounts, or non-privileged users.

        2) Use the bindings sections to see *who* actually receives these permissions:
           - For each sensitive Role/ClusterRole identified above, find corresponding
             ClusterRoleBindings/RoleBindings where roleRef.name matches that role name.
           - Problematic situations include:
             - Bindings granting these permissions to:
               - service accounts used by applications
               - groups representing many users (e.g., "developers", "all-users")
               - unauthenticated/authenticated built-in groups
               - generic or shared service accounts

        3) Remediation is manual by design:
           - For any non-admin subject that does not truly need this capability, update or
             remove the binding, or refactor the Role/ClusterRole to remove
             "serviceaccounts/token" with "create".
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
