> ## 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 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 EKS
* 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. List all default service accounts and identify ones still auto-mounting tokens (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)"'
           ```

        2. Disable token auto-mount for the default service account in each affected namespace (run on any machine with kubectl access; repeat for each NAMESPACE from step 1):
           ```bash theme={null}
           NAMESPACE=default  # replace with each namespace name
           kubectl patch serviceaccount default -n "$NAMESPACE" --type merge -p \
           '{"automountServiceAccountToken": false}'
           ```

        3. Identify pods currently using the default service account (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             .items[]
             | select(.spec.serviceAccountName == "default")
             | "\(.metadata.namespace) \(.metadata.name)"'
           ```

        4. For each workload using the default service account, create a dedicated service account (run on any machine with kubectl access; repeat per namespace as needed):
           ```bash theme={null}
           NAMESPACE=default        # namespace of the workload
           SA_NAME=app-sa-example   # choose a name per application
           kubectl create serviceaccount "$SA_NAME" -n "$NAMESPACE"
           ```

        5. Update workloads (Deployments/StatefulSets/etc.) to use the new service account (run on any machine with kubectl access; repeat per workload):
           ```bash theme={null}
           NAMESPACE=default               # namespace of the workload
           WORKLOAD=your-deployment-name   # name of Deployment/StatefulSet/Job/etc.

           # Edit the object and set spec.template.spec.serviceAccountName to the new SA
           kubectl -n "$NAMESPACE" edit deployment "$WORKLOAD"
           # In the editor, under spec.template.spec, ensure:
           #   serviceAccountName: app-sa-example
           ```

        6. Verify that default service accounts are not auto-mounting tokens and not used by pods (run on any machine with kubectl access):
           ```bash theme={null}
           default_sa_count=$(kubectl get serviceaccounts --all-namespaces -o json | jq '
             [.items[] | select(.metadata.name == "default" and (.automountServiceAccountToken != false))] | length')
           pods_using_default_sa=$(kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.serviceAccountName == "default")] | length')

           echo "default_sa_count=$default_sa_count"
           echo "pods_using_default_sa=$pods_using_default_sa"
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Disable token automount on all existing default ServiceAccounts
        # Run on: any machine with kubectl access

        for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
          kubectl patch serviceaccount default \
            -n "$ns" \
            --type='merge' \
            -p '{"automountServiceAccountToken": false}'
        done


        # 2) Identify Pods currently using the default ServiceAccount
        # (for each such Pod/Deployment/Job/etc, update its spec to use a
        #  dedicated ServiceAccount you create for that workload)

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


        # Example manifest: create an explicit ServiceAccount and use it in a Deployment
        # Save as app-sa.yaml and apply with `kubectl apply -f app-sa.yaml`

        apiVersion: v1
        kind: ServiceAccount
        metadata:
          name: app-sa
          namespace: default
        automountServiceAccountToken: true
        ---
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: my-app
          namespace: default
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: my-app
          template:
            metadata:
              labels:
                app: my-app
            spec:
              serviceAccountName: app-sa
              containers:
              - name: my-app
                image: nginx:stable

        # Apply the manifest
        kubectl apply -f app-sa.yaml


        # 3) Verification
        # Run the same logic as the audit (no output means pass)

        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"
        fi
        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"
        fi
        ```
      </Accordion>

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

        # This script:
        # 1. Sets automountServiceAccountToken: false on all existing "default" ServiceAccounts.
        # 2. Identifies pods using the default ServiceAccount for manual follow‑up.
        # 3. Verifies the setting across the cluster.
        #
        # Run from any machine with kubectl access and a current context.

        echo "[*] Ensuring all 'default' ServiceAccounts have automountServiceAccountToken: false"

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

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

          # Check current value; may be null/absent/true/false
          current=$(kubectl get sa default -n "$ns" -o jsonpath='{.automountServiceAccountToken}' 2>/dev/null || echo "")

          if [ "$current" = "false" ]; then
            echo "[=] Namespace '$ns': default SA already has automountServiceAccountToken=false"
            continue
          fi

          echo "[+] Patching default ServiceAccount in namespace '$ns' to set automountServiceAccountToken=false"
          kubectl patch serviceaccount default -n "$ns" --type merge -p '{"automountServiceAccountToken": false}' >/dev/null
        done

        echo
        echo "[*] Listing pods that currently use the 'default' ServiceAccount (for manual remediation)"

        kubectl get pods --all-namespaces -o json | jq -r '
          .items[]
          | select(.spec.serviceAccountName == "default")
          | [.metadata.namespace, .metadata.name, .spec.serviceAccountName]
          | @tsv' | awk 'BEGIN{printf "%-30s %-40s %-20s\n","NAMESPACE","POD","SERVICEACCOUNT";print substr("--------------------------------------------------------------------------------------------------------------------------------",1,95)} {printf "%-30s %-40s %-20s\n",$1,$2,$3}' || true

        echo
        echo "[*] Verification: re-running benchmark-style checks"

        # Check for any default SAs that do NOT have automountServiceAccountToken=false
        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 "[!] VERIFICATION FAILED: Some 'default' ServiceAccounts still do not have automountServiceAccountToken=false"
          echo "    Count: $default_sa_count"
          echo "    Details:"
          kubectl get serviceaccounts --all-namespaces -o json | jq -r '
            .items[]
            | select(.metadata.name == "default" and (.automountServiceAccountToken != false))
            | [.metadata.namespace, .metadata.name, (.automountServiceAccountToken // "null")]
            | @tsv' | awk 'BEGIN{printf "%-30s %-20s %-10s\n","NAMESPACE","SERVICEACCOUNT","AUTO_MOUNT";print substr("------------------------------------------------------------",1,60)} {printf "%-30s %-20s %-10s\n",$1,$2,$3}'
          exit 1
        else
          echo "[+] VERIFICATION PASSED: All 'default' ServiceAccounts have automountServiceAccountToken=false"
        fi

        # Also echo the pod-usage condition per the audit logic
        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 "[!] There are still pods using the 'default' ServiceAccount: $pods_using_default_sa"
          echo "    Create explicit ServiceAccounts and update these workloads to use them."
        else
          echo "[+] No pods are 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/)
