> ## 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 used for workloads and should not automount tokens. Use dedicated service accounts scoped to only the permissions each workload needs.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify namespaces using the default service account**
           * Run on: any machine with kubectl access
           * Command (lists Pods that rely on the `default` ServiceAccount):
             ```bash theme={null}
             kubectl get pods --all-namespaces -o json \
               | jq -r '.items[]
                 | select(.spec.serviceAccountName == null or .spec.serviceAccountName == "default")
                 | [.metadata.namespace, .metadata.name, (.spec.serviceAccountName // "default")] | @tsv'
             ```

        2. **Review RBAC permissions granted to each namespace’s default ServiceAccount**
           * Run on: any machine with kubectl access
           * Commands:
             ```bash theme={null}
             # List all RoleBindings and ClusterRoleBindings that reference 'default' ServiceAccounts
             kubectl get rolebindings,clusterrolebindings --all-namespaces -o yaml \
               | yq '.items[]
                 | select(.subjects[]? | select(.kind == "ServiceAccount" and .name == "default"))
                 | {kind, metadata: {name: .metadata.name, namespace: .metadata.namespace}, roleRef, subjects}'
             ```
           * Manually decide per namespace whether the default SA’s permissions are broader than needed for the Pods you found in step 1.

        3. **For each workload using a default ServiceAccount, design a dedicated ServiceAccount and RBAC**
           * For each `(namespace, pod)` from step 1, decide:
             * What minimal API access (if any) the workload truly needs.
             * Whether some Pods need no API access at all.
           * Plan either:
             * A new ServiceAccount with no extra permissions (`Role`/`ClusterRole` & binding only if needed), or
             * The Pod running with `automountServiceAccountToken: false` if it doesn’t need any Kubernetes API access.

        4. **Create dedicated ServiceAccounts and RBAC objects**
           * Run on: any machine with kubectl access
           * Example template (adjust `NAMESPACE`, names, and rules):
             ```bash theme={null}
             cat <<'EOF' | kubectl apply -f -
             apiVersion: v1
             kind: ServiceAccount
             metadata:
               name: app-sa
               namespace: NAMESPACE
             ---
             apiVersion: rbac.authorization.k8s.io/v1
             kind: Role
             metadata:
               name: app-sa-role
               namespace: NAMESPACE
             rules:
               # TODO: replace with minimal required rules
               - apiGroups: [""]
                 resources: ["pods"]
                 verbs: ["get", "list"]
             ---
             apiVersion: rbac.authorization.k8s.io/v1
             kind: RoleBinding
             metadata:
               name: app-sa-binding
               namespace: NAMESPACE
             subjects:
               - kind: ServiceAccount
                 name: app-sa
                 namespace: NAMESPACE
             roleRef:
               apiGroup: rbac.authorization.k8s.io
               kind: Role
               name: app-sa-role
             EOF
             ```
           * Update each workload manifest to set `spec.serviceAccountName: app-sa` and, where applicable, `automountServiceAccountToken: false` if no API access is needed.

        5. **Disable token automounting for all default ServiceAccounts**
           * Run on: any machine with kubectl access
           * Command:
             ```bash theme={null}
             for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
               kubectl patch serviceaccount default -n "$ns" \
                 -p '{"automountServiceAccountToken": false}' --type=merge || true
             done
             ```
           * Verify:
             ```bash theme={null}
             kubectl get sa default --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.automountServiceAccountToken}{"\n"}{end}'
             ```

        6. **Re-verify that no workloads rely on default ServiceAccounts and document exceptions**
           * Run on: any machine with kubectl access
           * Command:
             ```bash theme={null}
             kubectl get pods --all-namespaces -o json \
               | jq -r '.items[]
                 | select(.spec.serviceAccountName == null or .spec.serviceAccountName == "default")
                 | [.metadata.namespace, .metadata.name, (.spec.serviceAccountName // "default")] | @tsv'
             ```
           * Investigate any remaining Pods listed; either migrate them to dedicated ServiceAccounts or formally document and approve them as exceptions with a clear justification.
      </Accordion>

      <Accordion title="Using kubectl">
        ### Using kubectl

        Run these on any machine with `kubectl` access.

        #### 1. List all default service accounts and their token automount setting

        ```bash theme={null}
        kubectl get serviceaccount default --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.automountServiceAccountToken}{"\n"}{end}'
        ```

        Interpretation:

        * `true` (or blank/null, which means it inherits the namespace/pod default of `true`): the default SA in that namespace *may* be used by workloads and will get tokens by default. This is a risk and should be reviewed.
        * `false`: the default SA is configured *not* to automount tokens; this is the recommended baseline.

        To see the full object for a specific namespace:

        ```bash theme={null}
        kubectl get serviceaccount default -n <namespace> -o yaml
        ```

        Look for:

        ```yaml theme={null}
        automountServiceAccountToken: false
        ```

        If this field is missing or `true`, the default SA in that namespace is not hardened.

        #### 2. Identify pods that are using the default service account

        List all pods with their namespace and service account:

        ```bash theme={null}
        kubectl get pods --all-namespaces -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,SERVICEACCOUNT:.spec.serviceAccountName' | sort
        ```

        Interpretation:

        * Rows where `SERVICEACCOUNT` is `default` (or empty, which means it defaults to `default` SA) indicate workloads actively using the default service account. Each such pod should be reviewed to see if it should instead use a dedicated, least-privilege service account.

        For more detail in a specific namespace:

        ```bash theme={null}
        kubectl get pods -n <namespace> -o wide
        kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A5 'serviceAccount'
        ```

        Check:

        * `.spec.serviceAccountName` or `.spec.serviceAccount`:
          * `default` or omitted → using the default SA (needs review).
          * custom name → confirm that custom SA has only necessary permissions.

        #### 3. Check if pods using the default SA are actually mounting tokens

        For all pods using the default SA in a namespace:

        ```bash theme={null}
        kubectl get pods -n <namespace> \
          -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default" || !@.spec.serviceAccountName)]}{.metadata.name}{"\t"}{.spec.automountServiceAccountToken}{"\n"}{end}'
        ```

        Interpretation:

        * If the pod line shows `true` or is blank (and the namespace/SA defaults to `true`), the pod is getting a service account token mounted; combined with use of the default SA, this is a configuration needing human review.
        * If it shows `false`, the pod is *not* mounting a token despite using the default SA (lower risk, but still consider moving to a dedicated SA).

        To confirm token volume mounts on a specific pod:

        ```bash theme={null}
        kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A5 'serviceAccount'
        kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A5 'service-account-token'
        ```

        Presence of a `projected` or `secret` volume for a service account token indicates the pod is using a token.

        #### 4. Review RBAC permissions granted to the default service account

        For each namespace with pods using the default SA, inspect RBAC bindings:

        ```bash theme={null}
        # RoleBindings in namespace
        kubectl get rolebinding -n <namespace> -o wide

        # ClusterRoleBindings cluster-wide
        kubectl get clusterrolebinding -o wide
        ```

        Filter bindings that reference the default SA:

        ```bash theme={null}
        kubectl get rolebinding -n <namespace> -o json \
          | jq -r '.items[] | select(.subjects[]? | select(.kind=="ServiceAccount" and .name=="default" and .namespace=="<namespace>")) | .metadata.name'

        kubectl get clusterrolebinding -o json \
          | jq -r '.items[] | select(.subjects[]? | select(.kind=="ServiceAccount" and .name=="default")) | .metadata.name'
        ```

        Interpretation:

        * Any `RoleBinding` or `ClusterRoleBinding` that grants non-trivial permissions (e.g., `edit`, `admin`, custom roles with many verbs/resources) to `ServiceAccount/default` is a red flag.
        * Such bindings, combined with pods using the default SA, indicate the default SA is actively used with elevated privileges and should be redesigned to use dedicated service accounts.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Run on: any machine with kubectl access
        # Purpose: Report use of default service accounts and whether they automount tokens

        set -euo pipefail

        echo "=== 1) Default ServiceAccount automountServiceAccountToken settings ==="
        echo

        # List all default ServiceAccounts and their automountServiceAccountToken field
        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" end)
              ] | @tsv
          ' \
          | awk 'BEGIN {printf "%-32s %-16s %-10s\n", "NAMESPACE", "SERVICEACCOUNT", "AUTOMOUNT"}
                 {printf "%-32s %-16s %-10s\n", $1, $2, $3}'

        cat <<'EOF'

        Problem indication (automount):
        - Any line where:
            SERVICEACCOUNT = default
            AUTOMOUNT     = true or null
          means the namespace's default ServiceAccount may mount tokens by default.
          Remediation per benchmark: set automountServiceAccountToken: false on default SAs you do not intend to use.

        EOF

        echo "=== 2) Pods using the default ServiceAccount (current workloads) ==="
        echo

        # List all pods that are using the default ServiceAccount
        # (either explicitly serviceAccountName: default or implicitly by being empty)
        kubectl get pods --all-namespaces -o json \
          | jq -r '
            .items[]
            | . as $pod
            | .spec.serviceAccountName as $sa
            | .spec.serviceAccount as $legacy
            | ($sa // $legacy // "default") as $resolvedSA
            | select($resolvedSA=="default")
            | [
                $pod.metadata.namespace,
                $pod.metadata.name,
                $resolvedSA,
                (if $pod.spec.automountServiceAccountToken == true then "true"
                 elif $pod.spec.automountServiceAccountToken == false then "false"
                 else "null" end)
              ] | @tsv
          ' \
          | awk 'BEGIN {printf "%-32s %-40s %-16s %-10s\n", "NAMESPACE", "POD", "SERVICEACCOUNT", "POD_AUTOMOUNT"}
                 {printf "%-32s %-40s %-16s %-10s\n", $1, $2, $3, $4}'

        cat <<'EOF'

        Problem indication (pod usage):
        - Any line is a workload currently using the default ServiceAccount.
          Pay special attention when:
            POD_AUTOMOUNT = true or null
          because the pod may have access to a service account token.
        - For such pods, review:
            - Whether they truly need to use the default ServiceAccount.
            - Whether they can instead use a dedicated, least-privilege ServiceAccount.
            - Whether automountServiceAccountToken should be set to false at the pod/spec level.

        NOTE:
        - This script is only for visibility and review.
        - Because this control is MANUAL, you must decide case-by-case whether each use of the default ServiceAccount is acceptable and then:
            - Create and bind a dedicated ServiceAccount for the workload, and
            - Set automountServiceAccountToken: false on default ServiceAccounts you do not intend to use.

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