> ## 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 Service Account Tokens Are Only Mounted Where Necessary

### More Info:

Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server

### 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 pods and service accounts that may not need API access (run on any machine with kubectl access):
           ```bash theme={null}
           # Pods that currently auto-mount a token (candidate review set)
           kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.automountServiceAccountToken != false)] |
             [.[] | {ns:.metadata.namespace, pod:.metadata.name, sa:(.spec.serviceAccountName // "default")}]'

           # ServiceAccounts that might be used by those pods
           kubectl get sa --all-namespaces -o json | jq '
             [.items[] | {ns:.metadata.namespace, sa:.metadata.name,
                          automount:(.automountServiceAccountToken // "unset")}]'
           ```

        2. For each pod, determine if it really needs API server access (manual review):
           * Inspect the container images and commands:
             ```bash theme={null}
             kubectl -n <namespace> describe pod <pod-name>
             ```
           * Look for:
             * Use of `kubectl`, client SDKs, or API calls to Kubernetes
             * RBAC permissions or config mounting kubeconfig/service-account token
             * Controllers/operators, admission webhooks, or in-cluster automation
           * If you are unsure, consult the application owner before disabling token mounting.

        3. For workloads that do NOT need API access, set `automountServiceAccountToken: false` at the pod/workload level (preferred; run on any machine with kubectl access):
           * For a Deployment (similar for StatefulSet/DaemonSet/Job/CronJob):
             ```bash theme={null}
             kubectl -n <namespace> get deploy <deploy-name> -o yaml > /tmp/deploy.yaml
             ```
             Edit `/tmp/deploy.yaml` and under `spec.template.spec` add:
             ```yaml theme={null}
             automountServiceAccountToken: false
             ```
             Then apply:
             ```bash theme={null}
             kubectl apply -f /tmp/deploy.yaml
             ```
           * For a standalone Pod manifest, add the same field under `spec` and re-create the pod if needed.

        4. Optionally harden ServiceAccounts that should never mount tokens by default (run on any machine with kubectl access):
           * For each such ServiceAccount:
             ```bash theme={null}
             kubectl -n <namespace> get sa <sa-name> -o yaml > /tmp/sa.yaml
             ```
             Edit `/tmp/sa.yaml` to include:
             ```yaml theme={null}
             automountServiceAccountToken: false
             ```
             under `metadata` (same level as `name`/`namespace`), then:
             ```bash theme={null}
             kubectl apply -f /tmp/sa.yaml
             ```
           * Ensure any pods that DO require API access and use this ServiceAccount explicitly set:
             ```yaml theme={null}
             spec:
               automountServiceAccountToken: true
             ```
             in their pod template.

        5. Coordinate and monitor rollout impact:
           * Changing pod templates causes pods to be re-created/rolled; schedule changes during a maintenance window if needed.
           * After changes, confirm affected pods are running and application functionality is intact:
             ```bash theme={null}
             kubectl -n <namespace> get pods
             ```

        6. Verification (run on any machine with kubectl access):
           ```bash theme={null}
           pods_with_token_mount=$(kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.automountServiceAccountToken != false)] | length')

           if [ "$pods_with_token_mount" -gt 0 ]; then
             echo "automountServiceAccountToken"
           else
             echo "OK: all pods explicitly set automountServiceAccountToken=false or do not mount tokens unnecessarily"
           fi
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with kubectl access:

        1. Identify pods and service accounts that do not need API server access
           ```bash theme={null}
           kubectl get pods --all-namespaces -o wide
           kubectl get sa --all-namespaces
           ```
           Review workloads and decide which ones truly need to talk to the Kubernetes API. Only those should keep token mounting enabled.

        2. Patch individual Pods that do not need the token (ephemeral; also fix their controllers)
           ```bash theme={null}
           # Example: disable token mount on a running pod
           kubectl patch pod <pod-name> -n <namespace> \
             --type=merge \
             -p '{"spec":{"automountServiceAccountToken":false}}'
           ```

        3. Configure ServiceAccounts to not mount tokens by default\
           For service accounts whose workloads do not need API access:

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

           Or declaratively, create/update a manifest such as:

           ```yaml theme={null}
           apiVersion: v1
           kind: ServiceAccount
           metadata:
             name: example-sa
             namespace: example-namespace
           automountServiceAccountToken: false
           ```

           Apply it:

           ```bash theme={null}
           kubectl apply -f example-sa.yaml
           ```

        4. Configure controllers (Deployments, DaemonSets, StatefulSets, Jobs, CronJobs) so new pods do not mount tokens\
           Edit or patch the pod template for each controller whose workloads don’t need API access.

           Example patch for a Deployment:

           ```bash theme={null}
           kubectl patch deployment <deploy-name> -n <namespace> \
             --type=merge \
             -p '{"spec":{"template":{"spec":{"automountServiceAccountToken":false}}}}'
           ```

           Example declarative Deployment snippet:

           ```yaml theme={null}
           apiVersion: apps/v1
           kind: Deployment
           metadata:
             name: example-deployment
             namespace: example-namespace
           spec:
             template:
               spec:
                 automountServiceAccountToken: false
                 serviceAccountName: example-sa
                 containers:
                   - name: app
                     image: nginx:stable
           ```

           Apply it:

           ```bash theme={null}
           kubectl apply -f example-deployment.yaml
           ```

        5. Recreate pods if needed\
           For controllers, new pods will inherit the new setting automatically after rollout. To force recreation:
           ```bash theme={null}
           kubectl rollout restart deployment <deploy-name> -n <namespace>
           ```

        6. Verification (same logic as the audit)
           ```bash theme={null}
           pods_with_token_mount=$(kubectl get pods --all-namespaces -o json | jq '
             [.items[] | select(.spec.automountServiceAccountToken != false)] | length')

           if [ "$pods_with_token_mount" -gt 0 ]; then
             echo "automountServiceAccountToken still enabled on some pods"
           else
             echo "All pods have automountServiceAccountToken set to false"
           fi
           ```
      </Accordion>

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

        # Automation: Disable automountServiceAccountToken where not explicitly required
        # Scope: Run on any machine with kubectl and jq installed, authenticated to the cluster.
        #
        # WARNING:
        # - This will PATCH pods and serviceaccounts that do not explicitly set
        #   automountServiceAccountToken=false to set it to false.
        # - It cannot distinguish workloads that truly need API access from those that don't.
        #   Review candidates before/after running, or restrict via namespace/label filters.

        # Optional: limit scope by namespace (uncomment and set, or leave empty for all)
        NAMESPACE_FILTER=""

        # Helper to run kubectl with optional namespace filter
        k() {
          if [[ -n "$NAMESPACE_FILTER" ]]; then
            kubectl -n "$NAMESPACE_FILTER" "$@"
          else
            kubectl "$@"
          fi
        }

        echo "Discovering pods with automountServiceAccountToken not explicitly set to false..."

        # List pods that currently have automountServiceAccountToken != false
        pods_json=$(k get pods --all-namespaces -o json)

        pods_to_patch=$(echo "$pods_json" | jq -r '
          .items[]
          | select(.spec.automountServiceAccountToken != false)
          | "\(.metadata.namespace) \(.metadata.name)"')

        if [[ -z "$pods_to_patch" ]]; then
          echo "No pods require patch for automountServiceAccountToken."
        else
          echo "Patching pods to set spec.automountServiceAccountToken=false..."
          while read -r ns name; do
            [[ -z "$ns" || -z "$name" ]] && continue
            echo "  Patching pod: $ns/$name"
            k -n "$ns" patch pod "$name" --type=merge -p '{
              "spec": {
                "automountServiceAccountToken": false
              }
            }' >/dev/null
          done <<< "$pods_to_patch"
        fi

        echo "Discovering ServiceAccounts with automountServiceAccountToken not explicitly set to false..."

        sa_json=$(k get serviceaccounts --all-namespaces -o json)

        sa_to_patch=$(echo "$sa_json" | jq -r '
          .items[]
          | select(.automountServiceAccountToken != false)
          | "\(.metadata.namespace) \(.metadata.name)"')

        if [[ -z "$sa_to_patch" ]]; then
          echo "No ServiceAccounts require patch for automountServiceAccountToken."
        else
          echo "Patching ServiceAccounts to set automountServiceAccountToken=false..."
          while read -r ns name; do
            [[ -z "$ns" || -z "$name" ]] && continue
            echo "  Patching ServiceAccount: $ns/$name"
            k -n "$ns" patch serviceaccount "$name" --type=merge -p '{
              "automountServiceAccountToken": false
            }' >/dev/null
          done <<< "$sa_to_patch"
        fi

        echo "Verification: re-running audit for pods..."

        pods_with_token_mount=$(kubectl get pods --all-namespaces -o json | jq '
          [.items[] | select(.spec.automountServiceAccountToken != false)] | length')

        if [ "$pods_with_token_mount" -gt 0 ]; then
          echo "Verification FAILED: Some pods still have automountServiceAccountToken != false"
          echo "Count: $pods_with_token_mount"
          exit 1
        else
          echo "Verification PASSED: All pods now have automountServiceAccountToken=false"
        fi

        echo "Listing ServiceAccounts that still allow token automount (if any)..."
        kubectl get serviceaccounts --all-namespaces -o json | jq -r '
          .items[]
          | select(.automountServiceAccountToken != false)
          | "\(.metadata.namespace) \(.metadata.name)"' || true

        echo "Automation completed."
        ```
      </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/)
