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

# Service Account Token Authentication Should Not Be Used For Users

### More Info:

Service account tokens are intended for workloads, not users, and provide weak user authentication. Use OIDC instead.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify any user-facing processes or scripts using service account tokens**
           * On any machine with access to your clusters and automation code, search your repos and scripts for common SA token usage patterns:
             ```bash theme={null}
             rg 'service-account-token|serviceaccount/token|Authorization: Bearer ' / -n --hidden --glob '!*/.git/*' 2>/dev/null
             ```
           * Review CI/CD pipelines, jump-host scripts, and local dev scripts for:
             * `curl`/`kubectl` using `Authorization: Bearer <token>` where the token is from `/var/run/secrets/kubernetes.io/serviceaccount/token` or a long-lived SA secret.
             * Saved token files used for “user logins” to the API server.

        2. **List all service accounts and check for suspicious “user-like” usage**
           * On any machine with `kubectl` access, list SAs and related secrets:
             ```bash theme={null}
             kubectl get serviceaccounts --all-namespaces -o wide
             kubectl get secrets --all-namespaces | grep -i 'service-account'
             ```
           * For any SA that looks like a human user (names like `alice`, `devops-john`, `admin-user`), inspect annotations and usage:
             ```bash theme={null}
             kubectl describe serviceaccount -n <namespace> <serviceaccount-name>
             ```
           * Check if those SAs are referenced in kubeconfigs or scripts used by humans.

        3. **Verify API server authentication configuration on each control plane node**
           * On every control plane node, inspect the API server manifest to understand supported user auth methods:
             ```bash theme={null}
             sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
             ```
           * In `command:` flags, note presence/absence of:
             * `--oidc-issuer-url`, `--oidc-client-id`, `--oidc-username-claim`, `--oidc-groups-claim`
             * Any `--token-auth-file` or `--authentication-token-webhook-config-file` indicating token-based user auth
           * This does not by itself prove misuse, but it shows whether OIDC (preferred) is available as an alternative.

        4. **Review kubeconfigs and access methods used by human users**
           * On any machine with `kubectl` access, list configured contexts:
             ```bash theme={null}
             kubectl config get-contexts
             kubectl config view --raw
             ```
           * For each user entry, check the `user` section for:
             * `token:` fields that are static, long-lived tokens (especially if they match SA tokens from step 2).
             * `auth-provider:` or `exec:` sections that use OIDC (preferred) or other stronger mechanisms.
           * Any kubeconfig distributed to humans that directly embeds an SA token should be flagged for remediation.

        5. **Plan and implement migration from service account token usage to OIDC (or other approved user auth)**
           * For each identified human user or script using an SA token:
             * Create or map to an identity in your IdP (e.g., OIDC provider).
             * Configure OIDC on the API server if not already present by adding flags in `/etc/kubernetes/manifests/kube-apiserver.yaml` (this will restart the API server when saved):
               ```yaml theme={null}
               - --oidc-issuer-url=<https://your-issuer-url>
               - --oidc-client-id=<your-client-id>
               - --oidc-username-claim=email
               - --oidc-groups-claim=groups
               ```
             * Update RBAC to bind roles to OIDC identities/groups instead of SAs:
               ```bash theme={null}
               kubectl create clusterrolebinding oidc-user-admin \
                 --clusterrole=cluster-admin \
                 --user=<user@yourdomain.com>
               ```
             * Regenerate kubeconfigs or client auth flows so humans authenticate via OIDC (or your chosen strong method), not via SA tokens.

        6. **Verify no human access depends on service account tokens**
           * After migration, search again for SA token usage in user tools:
             ```bash theme={null}
             rg 'Authorization: Bearer ' / -n --hidden --glob '!*/.git/*' 2>/dev/null
             kubectl config view --raw | grep -i 'token:' -n
             ```
           * Confirm that any remaining `token:` entries are:
             * Bound only to non-human workloads, and
             * Not distributed outside the workload environment.
           * Optionally, rotate or delete any SA secrets previously used by humans:
             ```bash theme={null}
             kubectl delete secret -n <namespace> <service-account-token-secret>
             ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot fix this finding because it requires changing the kube-apiserver configuration on each control plane node, specifically `/etc/kubernetes/manifests/kube-apiserver.yaml`, and configuring an alternative auth mechanism such as OIDC. Refer to the **Manual Steps** section for host-level remediation guidance on disabling user access via service account tokens and enabling OIDC-based authentication.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Report potential *user* use of service account tokens across the cluster.
        #   This is for review only; it does NOT attempt to fix or definitively prove compliance.
        #
        # Requirements:
        #   - Run on any machine with kubectl access and cluster-wide RBAC rights to:
        #       * list serviceaccounts, secrets, pods, events, and audit logs (if enabled)
        #   - kubectl must be configured (KUBECONFIG or in-cluster config).

        set -euo pipefail

        NL=$'\n'

        header() {
          echo
          echo "=== $1 ==="
        }

        ###############################################################################
        # 1. Detect SA tokens mounted into Pods that look like *interactive user* pods
        ###############################################################################
        header "1) Pods with service account tokens mounted (cluster-wide)"

        # This shows all pods with the standard SA token mount path.
        # Service accounts are expected for workloads; flag namespaces/pods that look like user environments.
        kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\t"}{range .spec.volumes[*]}{.name}{"="}{.projected.sources[*].serviceAccountToken.path}{";"}{end}{"\n"}{end}' \
          | awk -F'\t' '
            NF==4 {
              ns=$1; pod=$2; sa=$3; vols=$4
              if (vols ~ /token/ || vols ~ /serviceaccount/ || vols ~ /sa-token/) {
                print ns "\t" pod "\t" sa "\t" vols
              }
            }
          ' \
          | column -t || true

        cat <<EOF

        Review guidance:
        - NORMAL for workloads to have SA tokens.
        - POTENTIAL ISSUE if:
          - Namespace or pod names suggest interactive/user use, e.g.: "user", "dev-shell", "jumpbox", "bastion",
            "notebook", "jupyter", "workspace", or personal names.
          - ServiceAccountName suggests user identity, e.g. "alice", "bob", "team-x-user".
        These indicate service account tokens might be used as user credentials instead of OIDC.
        EOF

        ###############################################################################
        # 2. ServiceAccounts that appear to represent *users*
        ###############################################################################
        header "2) ServiceAccounts that look like user identities"

        kubectl get sa -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.metadata.annotations}{"\n"}{end}' \
          | awk -F'\t' '
            {
              ns=$1; sa=$2; ann=$3
              lower=tolower(sa)
              if (lower ~ /user/ || lower ~ /login/ || lower ~ /human/ ||
                  lower ~ /jupyter/ || lower ~ /notebook/ ||
                  lower ~ /alice/ || lower ~ /bob/ || lower ~ /dev-.*-shell/ ) {
                print ns "\t" sa "\t" ann
              }
            }
          ' \
          | column -t || true

        cat <<EOF

        Review guidance:
        - NORMAL for SAs to be workload-specific names (e.g. "nginx", "controller", "ci-runner").
        - POTENTIAL ISSUE if SAs appear to model human users (names, emails, "user", "login", etc.),
          especially when bound to broad RBAC roles. This suggests user identities may rely on SA tokens.
        EOF

        ###############################################################################
        # 3. Secrets that are or were service account tokens
        ###############################################################################
        header "3) ServiceAccount token secrets (cluster-wide)"

        # Kubernetes v1.24+ typically uses projected SA tokens; older clusters used Secret-type tokens.
        # This lists any classic token secrets that could be directly exfiltrated/used.
        kubectl get secrets -A \
          -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.type}{"\t"}{.metadata.annotations}{"\n"}{end}' \
          | awk -F'\t' '
            {
              ns=$1; name=$2; type=$3; ann=$4
              if (type ~ /kubernetes.io\/service-account-token/) {
                print ns "\t" name "\t" type "\t" ann
              }
            }
          ' \
          | column -t || true

        cat <<EOF

        Review guidance:
        - NORMAL in older clusters to have many kubernetes.io/service-account-token secrets.
        - POTENTIAL ISSUE if:
          - These secrets are referenced outside Pods (e.g., given directly to users, external tools,
            or checked into source control).
          - Annotations or names suggest human users or external non-workload usage.
        Manual investigation needed to see if humans are authenticating with these tokens.
        EOF

        ###############################################################################
        # 4. (If audit logs available) Look for bearer-token auth using SA tokens
        ###############################################################################
        header "4) (Optional) Audit log indications of SA token authentication"

        cat <<'EOF'
        If Kubernetes API audit logs are enabled and accessible, search for use of service
        account bearer tokens as user authentication.

        Examples (run on the machine that has access to audit logs, adjust paths/commands):

          # Example: GREP for 'system:serviceaccount' subjects in audit logs
          sudo find /var/log -type f -name '*kube-apiserver-audit*' -print0 \
            | xargs -0 grep -H "system:serviceaccount" | head

          # Example: If logs in JSON, extract subjects that might represent "users" via jq
          sudo find /var/log -type f -name '*kube-apiserver-audit*' -print0 \
            | xargs -0 jq -r '
                select(.user.username | startswith("system:serviceaccount:")) |
                .user.username
              ' | sort -u

        Review guidance:
        - NORMAL: service accounts are used by workloads; you will see system:serviceaccount:* identities.
        - POTENTIAL ISSUE:
          - Requests from unusual source IPs corresponding to user networks/laptops/VPNs.
          - Long-lived tokens reused from many locations that map to "user-like" SAs.
          - Evidence that humans are using curl/kubectl with "Authorization: Bearer <SA token>" instead of OIDC.

        There is no one-shot automated remediation:
        - Use this evidence to decide:
          - Which service accounts must be migrated off for human use.
          - How to introduce/require OIDC for user authentication.
        EOF

        ###############################################################################
        # Summary of what indicates a PROBLEM
        ###############################################################################
        header "5) Quick interpretation summary"

        cat <<EOF
        Potential problems to investigate further:

        1) Pods in user-like namespaces or with user-like names that have service account tokens mounted.
        2) ServiceAccounts with names/annotations that represent human users or logins.
        3) ServiceAccount token secrets used outside normal pod mounting (e.g., handed to users/tools).
        4) Audit log entries showing serviceaccount identities coming from user endpoints
           or being used as long-lived user credentials.

        This script only surfaces *signals*; you must manually confirm whether humans are
        authenticating with service account tokens instead of using OIDC.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
