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

# Ensure Default Service Accounts Are Not Actively Used

### More Info:

Default service accounts should not be granted permissions or actively used by workloads. Create explicit service accounts and disable token automounting on default accounts.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS OKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. From any machine with kubectl access, list all namespaces and identify which have a `default` service account using tokens:
           ```bash theme={null}
           kubectl get sa --all-namespaces
           kubectl get sa default --all-namespaces -o yaml | grep -E 'name: default$|automountServiceAccountToken'
           ```

        2. For each namespace, identify workloads that are implicitly or explicitly using the `default` service account:
           ```bash theme={null}
           kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\n"}{end}' | sort
           ```
           Review pods that show an empty `serviceAccountName` (implicitly default) or `serviceAccountName: default` to determine whether they truly need API access.

        3. For pods using the default service account, inspect their specs for explicit token mounting or inherited defaults:
           ```bash theme={null}
           # Example for one pod
           kubectl -n <namespace> get pod <pod-name> -o yaml | grep -A3 serviceAccount
           kubectl -n <namespace> get pod <pod-name> -o yaml | grep -i automountServiceAccountToken -n
           ```
           Decide whether each workload needs Kubernetes API access and, if so, what minimum permissions it needs.

        4. Where workloads require API access, design explicit, least-privilege service accounts and RBAC:
           ```bash theme={null}
           # Example skeleton to adapt per app
           kubectl -n <namespace> create serviceaccount <sa-name>
           # Then bind minimal roles as appropriate (example only):
           kubectl -n <namespace> create role <role-name> --verb=get,list,watch --resource=pods
           kubectl -n <namespace> create rolebinding <rb-name> --role=<role-name> --serviceaccount=<namespace>:<sa-name>
           ```
           Update the corresponding Deployment/StatefulSet/Job manifests to set `spec.template.spec.serviceAccountName: <sa-name>` and, if needed, `automountServiceAccountToken: true` there instead of relying on defaults.

        5. After migrating workloads off the default service account in a namespace, disable token automount on that default account:
           ```bash theme={null}
           kubectl -n <namespace> patch serviceaccount default -p $'automountServiceAccountToken: false'
           ```
           If using GitOps/manifests, ensure the same setting is defined in the ServiceAccount manifest rather than patching only live state.

        6. Verify that:
           * No workloads are using the `default` service account except where consciously accepted, and
           * All default service accounts have token automount disabled:
           ```bash theme={null}
           kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\n"}{end}' | sort | grep ' default$' || echo "No pods using default SA"
           kubectl get sa default --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.automountServiceAccountToken}{"\n"}{end}' | sort
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1. List all namespaces and see which ones have a default ServiceAccount
        # Run on: any machine with kubectl access
        kubectl get serviceaccount default --all-namespaces -o wide
        ```

        Problem indication:

        * Every namespace will have a `default` ServiceAccount; that alone is not an issue.
        * Note any namespaces where workloads exist and you expect them to use dedicated service accounts instead of `default`.

        ***

        ```bash theme={null}
        # 2. Inspect whether default ServiceAccounts auto-mount tokens
        # Run on: any machine with kubectl access
        kubectl get serviceaccount default --all-namespaces -o yaml
        ```

        Problem indication:

        * `automountServiceAccountToken: true` (explicit) on a default ServiceAccount is a concern.
        * Missing `automountServiceAccountToken` means it inherits from pod spec / cluster defaults; treat as needing review.
        * Tokens listed under `secrets:` confirm token creation, but not necessarily active use.

        ***

        ```bash theme={null}
        # 3. Find pods that are using the default ServiceAccount
        # Run on: any machine with kubectl access
        kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\n"}{end}' \
          | sort
        ```

        Problem indication:

        * Any pod where the third column is `default` is actively using the default ServiceAccount.
        * Focus on namespaces with sensitive workloads or where API access should be tightly scoped.

        ***

        ```bash theme={null}
        # 4. For pods using default SA, check if tokens are being auto-mounted
        # Example for all pods, filtering to those with default SA
        # Run on: any machine with kubectl access
        kubectl get pods --all-namespaces -o json \
          | jq -r '.items[]
            | select(.spec.serviceAccountName=="default")
            | "\(.metadata.namespace)\t\(.metadata.name)\t\(.spec.automountServiceAccountToken)"'
        ```

        Problem indication:

        * `true` means the pod is set to mount a token.
        * `null` means it may inherit from the ServiceAccount (or cluster default); requires manual review of both pod and SA.

        If `jq` is not available, inspect specific pods:

        ```bash theme={null}
        # Inspect a specific pod using default SA
        # Run on: any machine with kubectl access
        kubectl get pod <pod-name> -n <namespace> -o yaml
        ```

        Problem indication in pod YAML:

        * `spec.serviceAccountName: default` AND
        * `spec.automountServiceAccountToken: true` (or absent when SA/cluster default is true) AND
        * A projected service account token volume in `spec.volumes` or a token under `/var/run/secrets/kubernetes.io/serviceaccount`.

        ***

        ```bash theme={null}
        # 5. Review access granted via default ServiceAccounts (ClusterRoleBinding/RoleBinding)
        # Run on: any machine with kubectl access
        kubectl get rolebinding,clusterrolebinding --all-namespaces -o yaml \
          | grep -A5 -n "kind: ServiceAccount" | grep -B2 "name: default"
        ```

        Problem indication:

        * Any `RoleBinding` or `ClusterRoleBinding` whose `subjects` include:
          * `kind: ServiceAccount`
          * `name: default`
          * plus a `namespace:` value
        * Especially concerning if bound to powerful `Role`/`ClusterRole` (e.g., `cluster-admin`, broad `*` verbs/resources).

        ***

        ```bash theme={null}
        # 6. (Optional) Summarize which namespaces have default SA bound to roles
        # Run on: any machine with kubectl access
        kubectl get rolebinding --all-namespaces -o json \
          | jq -r '.items[]
            | . as $rb
            | .subjects[]
            | select(.kind=="ServiceAccount" and .name=="default")
            | "\($rb.metadata.namespace)\t\($rb.metadata.name)\t\($rb.roleRef.kind)\t\($rb.roleRef.name)"'

        kubectl get clusterrolebinding -o json \
          | jq -r '.items[]
            | . as $crb
            | .subjects[]
            | select(.kind=="ServiceAccount" and .name=="default")
            | "CLUSTER\t\($crb.metadata.name)\t\($crb.roleRef.kind)\t\($crb.roleRef.name)\tNS:\(.namespace)"'
        ```

        Problem indication:

        * Any line returned indicates a default ServiceAccount is granted explicit RBAC permissions.
        * The more privileged the referenced `Role`/`ClusterRole`, the higher the concern.

        Use these outputs to decide:

        * Where new, explicit ServiceAccounts should be created.
        * Where to stop using `default` in pod specs.
        * Where `automountServiceAccountToken: false` should be set on default ServiceAccounts and/or pods.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report use and configuration of default service accounts across the cluster.
        # Run on: any machine with kubectl access and current-context pointing to the target cluster.

        set -o errexit
        set -o nounset
        set -o pipefail

        echo "=== 1) Default ServiceAccount configuration in all namespaces ==="
        echo "Namespace,SA,automountServiceAccountToken"
        kubectl get sa --all-namespaces -o json \
          | jq -r '
            .items[]
            | select(.metadata.name=="default")
            | [
                .metadata.namespace,
                .metadata.name,
                (if .automountServiceAccountToken==true then "true"
                 elif .automountServiceAccountToken==false then "false"
                 else "null(inherited)" end)
              ]
            | @csv
          '

        cat <<'EOF'

        Interpretation:
        - default SA with "true"      => RISK: explicitly enabled token automount.
        - default SA with "null(...)" => RISK: inherits behavior; confirm namespace/pod-level automount.
        - default SA with "false"     => Preferred: token automount disabled at SA level.

        EOF

        echo "=== 2) Pods currently using the default ServiceAccount ==="
        echo "Namespace,Pod,ServiceAccount,SA_automount,pod.spec.automountServiceAccountToken"
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | select(.spec.serviceAccountName=="default" or .spec.serviceAccount==null)
            | . as $pod
            | ($pod.spec.serviceAccountName // "default") as $sa
            | $pod.metadata.namespace as $ns
            | (
                ([
                  .items[]
                  | select(.kind=="ServiceAccount")? # safeguard, usually not present in pod list
                ] | length) as $dummy # no-op
              ) // empty
            ' >/dev/null 2>&1 || true

        # We need SA data; fetch separately and join via jq.
        pods_json="$(kubectl get pods --all-namespaces -o json)"
        sas_json="$(kubectl get sa --all-namespaces -o json)"

        jq -rn --argfile pods <(printf '%s\n' "$pods_json") --argfile sas <(printf '%s\n' "$sas_json") '
          $pods.items[]
          | select(.spec.serviceAccountName=="default" or (.spec.serviceAccountName==null and .spec.serviceAccount==null))
          | . as $p
          | ($p.spec.serviceAccountName // "default") as $sa
          | ($sas.items[]
             | select(.metadata.namespace==$p.metadata.namespace and .metadata.name==$sa)
             | .automountServiceAccountToken) as $sa_auto
          | [
              $p.metadata.namespace,
              $p.metadata.name,
              $sa,
              (if $sa_auto==true then "true"
               elif $sa_auto==false then "false"
               else "null(inherited)" end),
              (if $p.spec.automountServiceAccountToken==true then "true"
               elif $p.spec.automountServiceAccountToken==false then "false"
               else "null(unset)" end)
            ]
          | @csv
        '

        cat <<'EOF'

        Interpretation (Pods):
        - Any row listed here means a pod is using the "default" ServiceAccount.
        - Risk increases when:
          - SA_automount == "true", or
          - SA_automount == "null(inherited)" and pod/spec defaults to automounting, or
          - pod.spec.automountServiceAccountToken == "true".
        - Review these workloads and migrate them to explicit ServiceAccounts with least-privilege RBAC.

        EOF

        echo "=== 3) Namespaces that still bind RBAC directly to the default ServiceAccount ==="
        echo "Namespace,RoleBinding,Kind,SubjectKind,SubjectName"
        kubectl get rolebindings,clusterrolebindings --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $rb
            | ($rb.subjects // [])[]
            | select(.kind=="ServiceAccount" and .name=="default")
            | [
                ($rb.metadata.namespace // "cluster-scope"),
                $rb.metadata.name,
                $rb.kind,
                .kind,
                .name
              ]
            | @csv
          '

        cat <<'EOF'

        Interpretation (RBAC):
        - Any line here indicates the "default" ServiceAccount is explicitly granted roles.
        - These are high-priority for remediation:
          - Create dedicated ServiceAccounts.
          - Update bindings to reference those instead of "default".
          - Optionally set automountServiceAccountToken: false on default SAs.

        EOF

        echo "=== 4) Quick summary indicators ==="
        echo "- Count of namespaces where default SA does NOT have automountServiceAccountToken=false:"
        kubectl get sa --all-namespaces -o json \
          | jq -r '
            [ .items[]
              | select(.metadata.name=="default")
              | select(.automountServiceAccountToken!=false)
              | .metadata.namespace
            ] | unique | length
          '

        echo "- Count of pods using the default ServiceAccount:"
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            [ .items[]
              | select(.spec.serviceAccountName=="default" or (.spec.serviceAccountName==null and .spec.serviceAccount==null))
            ] | length
          '

        cat <<'EOF'

        Cluster is closer to compliant when:
        - All default ServiceAccounts show automountServiceAccountToken = false.
        - The count of pods using the default ServiceAccount is 0 (or only known, accepted exceptions).
        - No RoleBinding/ClusterRoleBinding subjects the default ServiceAccount.

        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
