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

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS GKE
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify default service accounts and workloads using them** (run on any machine with kubectl access)
           ```bash theme={null}
           kubectl get serviceaccounts --all-namespaces \
             -o jsonpath='{range .items[?(@.metadata.name=="default")]}{.metadata.namespace}{"\n"}{end}'

           kubectl get pods --all-namespaces \
             -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default")]}{@.metadata.namespace}{"\t"}{@.metadata.name}{"\n"}{end}'
           ```

        2. **Create explicit service accounts to replace `default` where needed** (run on any machine with kubectl access; repeat per namespace)
           ```bash theme={null}
           # Example: create a dedicated service account for a workload in namespace my-namespace
           kubectl create serviceaccount app-sa -n my-namespace

           # If workloads need specific RBAC, bind roles to the new service account, e.g.:
           kubectl create rolebinding app-sa-view \
             --clusterrole=view \
             --serviceaccount=my-namespace:app-sa \
             -n my-namespace
           ```

        3. **Update pods/workloads to stop using the `default` ServiceAccount** (run on any machine with kubectl access; repeat per workload)
           * For Deployments, StatefulSets, DaemonSets, Jobs, etc., edit the manifest and set `spec.template.spec.serviceAccountName`:
           ```bash theme={null}
           # Example for a Deployment
           kubectl -n my-namespace edit deployment my-deployment
           ```
           * In the editor, under `spec.template.spec`, add or change:
           ```yaml theme={null}
           serviceAccountName: app-sa
           ```
           * Save and exit to trigger a rollout using the new service account.

        4. **Disable token automount on each `default` ServiceAccount** (run on any machine with kubectl access; repeat per namespace that has an active default SA)
           ```bash theme={null}
           # Example for namespace my-namespace
           kubectl -n my-namespace patch serviceaccount default \
             -p '{"automountServiceAccountToken": false}'
           ```

        5. **Optionally enforce pod-level override for any remaining pods** (run on any machine with kubectl access; repeat where needed)
           * For any pod spec that must explicitly ensure no token automount (and still uses `default` or no SA set), edit and set:
           ```bash theme={null}
           kubectl -n my-namespace edit deployment my-deployment
           ```
           * Under `spec.template.spec`, add:
           ```yaml theme={null}
           automountServiceAccountToken: false
           ```

        6. **Verify remediation** (run on any machine with kubectl access)
           ```bash theme={null}
           echo "🔹 Default Service Accounts with automountServiceAccountToken enabled:"
           default_sa_count=$(kubectl get serviceaccounts --all-namespaces -o json | jq '
             [.items[] | select(.metadata.name == "default" and (.automountServiceAccountToken != false))] | length')
           if [ "$default_sa_count" -gt 0 ]; then
             echo "default_sa_not_auto_mounted"
           else
             echo "OK: all default serviceaccounts have automountServiceAccountToken=false"
           fi

           echo "\n🔹 Pods using default ServiceAccount:"
           pods_using_default_sa=$(kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.serviceAccountName == "default")] | length')
           if [ "$pods_using_default_sa" -gt 0 ]; then
             echo "default_sa_used_in_pods"
           else
             echo "OK: no pods are using the default serviceaccount"
           fi
           ```
      </Accordion>

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

        1. Identify default ServiceAccounts with token automount enabled\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get serviceaccounts --all-namespaces -o json \
           | jq -r '.items[]
             | select(.metadata.name=="default" and (.automountServiceAccountToken != false))
             | "\(.metadata.namespace)"' \
           | sort -u
           ```

        2. Disable token automount on each default ServiceAccount\
           Replace `<NAMESPACE>` with each namespace from the previous command.\
           Run on: any machine with kubectl access

           ```bash theme={null}
           kubectl patch serviceaccount default \
             -n <NAMESPACE> \
             --type merge \
             -p '{"automountServiceAccountToken": false}'
           ```

           To apply this for all current namespaces in one go (requires bash + jq):

           ```bash theme={null}
           for ns in $(kubectl get serviceaccounts --all-namespaces -o json \
             | jq -r '.items[]
               | select(.metadata.name=="default" and (.automountServiceAccountToken != false))
               | .metadata.namespace' | sort -u); do
             kubectl patch serviceaccount default \
               -n "$ns" \
               --type merge \
               -p '{"automountServiceAccountToken": false}'
           done
           ```

        3. Ensure workloads do not use the default ServiceAccount\
           For each deployment/statefulset/cronjob/etc. that currently uses `serviceAccountName: default`, update its manifest to use an explicit ServiceAccount, for example:

           Example ServiceAccount manifest (apply per namespace as needed):

           ```yaml theme={null}
           apiVersion: v1
           kind: ServiceAccount
           metadata:
             name: my-app-sa
             namespace: my-namespace
           automountServiceAccountToken: true
           ```

           Example Deployment manifest snippet:

           ```yaml theme={null}
           apiVersion: apps/v1
           kind: Deployment
           metadata:
             name: my-app
             namespace: my-namespace
           spec:
             template:
               spec:
                 serviceAccountName: my-app-sa
           ```

           Apply:

           ```bash theme={null}
           kubectl apply -f my-app-serviceaccount.yaml
           kubectl apply -f my-app-deployment.yaml
           ```

        4. Verification\
           Run on: any machine with kubectl access

           ```bash theme={null}
           echo "🔹 Default Service Accounts with automountServiceAccountToken enabled:"
           default_sa_count=$(kubectl get serviceaccounts --all-namespaces -o json | jq '
             [.items[] | select(.metadata.name == "default" and (.automountServiceAccountToken != false))] | length')
           if [ "$default_sa_count" -gt 0 ]; then
             echo "default_sa_not_auto_mounted"
           else
             echo "OK: all default ServiceAccounts have automountServiceAccountToken=false"
           fi

           echo
           echo "🔹 Pods using default ServiceAccount:"
           pods_using_default_sa=$(kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.serviceAccountName == "default")] | length')
           if [ "$pods_using_default_sa" -gt 0 ]; then
             echo "default_sa_used_in_pods"
           else
             echo "OK: no pods are using the default ServiceAccount"
           fi
           ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # This script:
        # 1. Ensures all *default* ServiceAccounts have automountServiceAccountToken: false
        # 2. Identifies Pods still using the default ServiceAccount (for follow-up)
        #
        # Run on: any machine with kubectl access and jq installed.

        # Fail fast if required tools are missing
        for cmd in kubectl jq; do
          if ! command -v "$cmd" >/dev/null 2>&1; then
            echo "ERROR: $cmd not found in PATH" >&2
            exit 1
          fi
        done

        echo "🔧 Disabling automountServiceAccountToken on all default ServiceAccounts..."

        # Get all namespaces
        namespaces=$(kubectl get ns -o jsonpath='{.items[*].metadata.name}')

        for ns in $namespaces; do
          # Check if a default SA exists in this namespace
          if ! kubectl get sa default -n "$ns" >/dev/null 2>&1; then
            continue
          fi

          # Patch to ensure automountServiceAccountToken: false (idempotent)
          kubectl patch sa default -n "$ns" \
            --type merge \
            -p '{"automountServiceAccountToken": false}' >/dev/null

          echo "  - Patched default ServiceAccount in namespace: $ns"
        done

        echo
        echo "✅ Verification: checking default ServiceAccounts' automountServiceAccountToken..."

        default_sa_count=$(kubectl get serviceaccounts --all-namespaces -o json | jq '
          [.items[]
           | select(.metadata.name == "default" and (.automountServiceAccountToken != false))
          ] | length')

        if [ "$default_sa_count" -gt 0 ]; then
          echo "❌ Some default ServiceAccounts still have automountServiceAccountToken enabled:"
          kubectl get serviceaccounts --all-namespaces -o json | jq -r '
            .items[]
            | select(.metadata.name == "default" and (.automountServiceAccountToken != false))
            | "\(.metadata.namespace)/\(.metadata.name): automountServiceAccountToken=\(.automountServiceAccountToken)"'
          exit 1
        else
          echo "✅ All default ServiceAccounts now have automountServiceAccountToken: false"
        fi

        echo
        echo "🔎 Pods currently using the default ServiceAccount (for manual review/migration):"

        pods_using_default_sa=$(kubectl get pods --all-namespaces -o json | jq '
          [.items[] | select(.spec.serviceAccountName == "default")]')

        pods_count=$(echo "$pods_using_default_sa" | jq 'length')

        if [ "$pods_count" -gt 0 ]; then
          echo "⚠️  Found $pods_count Pod(s) using the default ServiceAccount:"
          echo "$pods_using_default_sa" | jq -r '.[] | "\(.metadata.namespace)/\(.metadata.name)"'
          echo
          echo "NOTE:"
          echo "- Create explicit ServiceAccounts per workload with the required permissions."
          echo "- Update each Pod/Deployment/etc. spec to set spec.serviceAccountName to the new account."
        else
          echo "✅ No Pods are currently using the default ServiceAccount."
        fi
        ```
      </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/)
