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

The default service account should not be used to ensure that rights granted to applications can be more easily audited and reviewed.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List all default service accounts and their token mounting setting**\
           Run on: any machine with kubectl access
           ```sh theme={null}
           kubectl get serviceaccount --all-namespaces --field-selector metadata.name=default -o wide
           kubectl get serviceaccount --all-namespaces --field-selector metadata.name=default -o=json | jq -r '.items[] | "namespace: \(.metadata.namespace), automountServiceAccountToken: \(.automountServiceAccountToken // "notset")"'
           ```

        2. **Review workloads that currently use a default service account**\
           Run on: any machine with kubectl access\
           For each namespace, list pods and their service accounts:
           ```sh theme={null}
           for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
             echo "=== Namespace: $ns ==="
             kubectl get pods -n "$ns" -o custom-columns='NAME:.metadata.name,SERVICEACCOUNT:.spec.serviceAccountName' --no-headers 2>/dev/null | grep -E 'default$' || true
           done
           ```
           Decide which workloads must access the API; plan to move those to explicit service accounts.

        3. **Create explicit service accounts for workloads that need API access**\
           Run on: any machine with kubectl access\
           For each namespace and workload that needs API access, create a dedicated service account, then bind appropriate RBAC (example for namespace `my-namespace` and service account `app-sa`):
           ```sh theme={null}
           kubectl create serviceaccount app-sa -n my-namespace

           kubectl create role app-sa-role \
             --verb=get,list,watch \
             --resource=pods \
             -n my-namespace

           kubectl create rolebinding app-sa-rb \
             --role=app-sa-role \
             --serviceaccount=my-namespace:app-sa \
             -n my-namespace
           ```
           Adjust verbs/resources to your security requirements.

        4. **Update workloads to stop using the default service account**\
           Run on: any machine with kubectl access\
           For each deployment/statefulset/daemonset/etc. that should use a dedicated service account, patch the spec to set `serviceAccountName` explicitly (example for a deployment):
           ```sh theme={null}
           kubectl patch deployment my-deployment -n my-namespace \
             --type merge \
             -p '{"spec":{"template":{"spec":{"serviceAccountName":"app-sa"}}}}'
           ```
           Repeat for all workloads currently using the `default` service account that require API access.

        5. **Disable token auto-mounting on all default service accounts**\
           Run on: any machine with kubectl access\
           For each namespace that has a default service account, patch it to set `automountServiceAccountToken: false`:
           ```sh theme={null}
           for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
             if kubectl get serviceaccount default -n "$ns" >/dev/null 2>&1; then
               kubectl patch serviceaccount default -n "$ns" \
                 --type merge \
                 -p '{"automountServiceAccountToken":false}'
             fi
           done
           ```

        6. **Verify that default service accounts are not actively used and have token mounting disabled**\
           Run on: any machine with kubectl access\
           Confirm `automountServiceAccountToken` is false on all default service accounts:
           ```sh theme={null}
           kubectl get serviceaccount --all-namespaces --field-selector metadata.name=default -o=json | \
           jq -r '.items[] | "namespace: \(.metadata.namespace), kind: \(.kind), name: \(.metadata.name), automountServiceAccountToken: \(.automountServiceAccountToken // "notset")"'
           ```
           Confirm no pods are using `default` where that is not an intentional decision:
           ```sh theme={null}
           for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
             echo "=== Namespace: $ns ==="
             kubectl get pods -n "$ns" -o custom-columns='NAME:.metadata.name,SERVICEACCOUNT:.spec.serviceAccountName' --no-headers 2>/dev/null | grep -E 'default$' || true
           done
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Review current usage of default service accounts
        # Run on: any machine with kubectl access

        # List all default serviceaccounts and their automountServiceAccountToken setting
        kubectl get serviceaccount --all-namespaces \
          --field-selector metadata.name=default -o=json | \
          jq -r '.items[] | "namespace: \(.metadata.namespace), kind: \(.kind), name: \(.metadata.name), automountServiceAccountToken: \(.automountServiceAccountToken | if . == null then "notset" else . end )"' | \
          xargs -L 1

        # List workloads that currently use the default service account (per namespace)
        # Example for one namespace; repeat per namespace as needed
        NAMESPACE=default
        kubectl get pods -n "$NAMESPACE" -o json | \
          jq -r '.items[] | select(.spec.serviceAccountName == null or .spec.serviceAccountName == "default") |
            "pod: \(.metadata.name), sa: \(.spec.serviceAccountName // "default")"'


        # 2) Create explicit service accounts for workloads currently using "default"
        # Run on: any machine with kubectl access

        # Example: create a dedicated service account in a specific namespace
        NAMESPACE=default
        NEW_SA=my-app-sa

        kubectl create serviceaccount "$NEW_SA" -n "$NAMESPACE"

        # Patch a specific deployment (or other controller) to use the new service account
        # Adjust kind/name/namespace as needed
        kubectl patch deployment my-app-deployment -n "$NAMESPACE" \
          --type merge \
          -p "{\"spec\":{\"template\":{\"spec\":{\"serviceAccountName\":\"$NEW_SA\"}}}}"

        # Repeat for all workloads that should NOT use the namespace's default service account.


        # 3) Disable token automount on each default service account
        # Run on: any machine with kubectl access

        # Patch a single namespace's default service account
        NAMESPACE=default
        kubectl patch serviceaccount default -n "$NAMESPACE" \
          --type merge \
          -p '{"automountServiceAccountToken": false}'

        # Optionally, disable automount at the pod level for extra safety
        # Example for a deployment
        kubectl patch deployment my-app-deployment -n "$NAMESPACE" \
          --type merge \
          -p '{"spec":{"template":{"spec":{"automountServiceAccountToken": false}}}}'

        # Bulk patch: all namespaces' default service accounts
        # (Be cautious; ensure workloads have explicit service accounts first.)
        for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
          kubectl patch serviceaccount default -n "$ns" \
            --type merge \
            -p '{"automountServiceAccountToken": false}' || echo "skip ns=$ns"
        done


        # 4) Declarative manifest approach (example for one namespace)
        # Run on: any machine with kubectl access

        # Export the default serviceaccount manifest, edit, and apply
        NAMESPACE=default

        kubectl get serviceaccount default -n "$NAMESPACE" -o yaml > default-sa-$NAMESPACE.yaml

        # Edit default-sa-$NAMESPACE.yaml and ensure under "metadata:" / "spec:" you have:
        # ---
        # apiVersion: v1
        # kind: ServiceAccount
        # metadata:
        #   name: default
        #   namespace: <your-namespace>
        # automountServiceAccountToken: false
        # ---

        kubectl apply -f default-sa-$NAMESPACE.yaml


        # 5) Verification
        # Run on: any machine with kubectl access

        kubectl get serviceaccount --all-namespaces \
          --field-selector metadata.name=default -o=json | \
          jq -r '.items[] | "namespace: \(.metadata.namespace), kind: \(.kind), name: \(.metadata.name), automountServiceAccountToken: \(.automountServiceAccountToken | if . == null then "notset" else . end )"' | \
          xargs -L 1
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Automation for: Ensure Default Service Accounts Are Not Actively Used (CIS Kubernetes 5.1.5)
        # Run on: any machine with kubectl access and jq installed

        set -euo pipefail

        echo "==> Checking connectivity and prerequisites"
        kubectl version --short >/dev/null 2>&1
        jq --version >/dev/null 2>&1

        echo "==> Discovering all default service accounts"
        DEFAULT_SAS_JSON=$(kubectl get serviceaccount --all-namespaces \
          --field-selector metadata.name=default -o json)

        COUNT=$(echo "${DEFAULT_SAS_JSON}" | jq '.items | length')
        echo "Found ${COUNT} default service account(s)"

        if [ "${COUNT}" -eq 0 ]; then
          echo "No default service accounts found. Nothing to change."
          exit 0
        fi

        echo "==> Patching default service accounts to set automountServiceAccountToken=false"
        # Idempotent patch; safe to re-run
        kubectl get serviceaccount --all-namespaces \
          --field-selector metadata.name=default -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \
          | while read -r NAMESPACE NAME; do
              if [ -z "${NAMESPACE}" ] || [ -z "${NAME}" ]; then
                continue
              fi
              echo "Patching serviceaccount '${NAME}' in namespace '${NAMESPACE}'"
              kubectl patch serviceaccount "${NAME}" -n "${NAMESPACE}" \
                --type=merge \
                -p '{"automountServiceAccountToken": false}' >/dev/null
            done

        echo "==> Verification: listing default service accounts and automountServiceAccountToken"
        kubectl get serviceaccount --all-namespaces \
          --field-selector metadata.name=default -o=json \
          | jq -r '.items[]
            | "namespace: \(.metadata.namespace), kind: \(.kind), name: \(.metadata.name), automountServiceAccountToken: \(.automountServiceAccountToken | if . == null then "notset" else . end )"' \
          | xargs -L 1

        echo "==> Check that all reported values for automountServiceAccountToken are 'false'"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)
