Skip to main content

Ensure That Default Service Accounts Are Not Actively Used

More Info:​

Default service accounts should not be actively used by workloads and should have token automounting disabled. Use explicit service accounts scoped to each workloads needs.

Risk Level​

Medium

Address​

Security

Compliance Standards​

  • CIS EKS

Triage and Remediation​

Remediation​

Manual Steps
  1. Identify all default service accounts and namespaces
    Run on: any machine with kubectl access

    kubectl get serviceaccount default --all-namespaces -o wide
  2. Disable token automount on every default service account
    Run on: any machine with kubectl access
    (Run once per namespace; default, kube-system, and any others in use.)

    for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
    kubectl patch serviceaccount default \
    -n "$ns" \
    --type merge \
    -p '{"automountServiceAccountToken": false}' || true
    done
  3. List pods currently using the default service account
    Run on: any machine with kubectl access

    kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default")]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}'
  4. Create explicit service accounts for workloads that need API access
    Run on: any machine with kubectl access
    (Example for one namespace; repeat as needed, adjusting names and namespaces.)

    kubectl create serviceaccount app-sa -n your-namespace

    # Optionally bind RBAC as required for the workload:
    kubectl create rolebinding app-sa-access \
    --clusterrole=view \
    --serviceaccount=your-namespace:app-sa \
    -n your-namespace
  5. Update workloads to use the explicit service accounts and (optionally) disable pod-level automount
    Run on: any machine with kubectl access
    Edit each deployment/statefulset/cronjob/etc. that currently uses serviceAccountName: default:

    kubectl edit deployment your-deployment -n your-namespace

    In .spec.template.spec:

    serviceAccountName: app-sa # change from "default"
    automountServiceAccountToken: false # add if the pod should not get a token
  6. Verification
    Run on: any machine with kubectl access

    # 1) Confirm all default SAs have automount disabled
    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 "all_default_sa_automount_disabled"
    fi

    # 2) Confirm no pods are using the default service account
    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 "no_pods_using_default_sa"
    fi
Using kubectl

On any machine with kubectl access:

  1. Disable token automounting on all existing default ServiceAccounts
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl patch serviceaccount default \
-n "$ns" \
--type merge \
-p '{"automountServiceAccountToken": false}'
done
  1. For workloads that need API access, create explicit ServiceAccounts and use them in Pod specs

Example (save as sa-and-deployment.yaml and apply):

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

Apply:

kubectl apply -f sa-and-deployment.yaml
  1. Optionally, prevent default use in new workloads by setting an explicit ServiceAccount in your own pod/deployment manifests and avoiding serviceAccountName: default.

  2. Verification

# 1) Ensure all default SAs have automountServiceAccountToken: false
kubectl get serviceaccounts --all-namespaces -o json | jq '
[.items[] | select(.metadata.name == "default" and (.automountServiceAccountToken != false))] | length'

# 2) Ensure no pods are using the default SA
kubectl get pods --all-namespaces -o json | jq '
[.items[] | select(.spec.serviceAccountName == "default")] | length'
Automation
#!/usr/bin/env bash
#
# Remediates CISEKS 4.1.5:
# - Sets automountServiceAccountToken: false on every "default" ServiceAccount
# - Detects Pods using the default ServiceAccount so they can be remediated
#
# Run on: any machine with kubectl access and jq installed

set -euo pipefail

echo "==> Ensuring 'default' ServiceAccounts have automountServiceAccountToken: false"

# Patch all existing 'default' ServiceAccounts cluster-wide
# This is idempotent: patching with the same value is safe.
kubectl get serviceaccount --all-namespaces -o json \
| jq -r '
.items[]
| select(.metadata.name=="default")
| "\(.metadata.namespace)"
' \
| sort -u \
| while read -r ns; do
[ -z "$ns" ] && continue
echo "Patching default ServiceAccount in namespace: $ns"
kubectl patch serviceaccount default -n "$ns" \
--type merge \
-p '{"automountServiceAccountToken": false}' >/dev/null
done

echo "==> Verifying ServiceAccount configuration"

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 "ERROR: Some 'default' ServiceAccounts still do not have automountServiceAccountToken set to false."
echo "Count: $default_sa_count"
exit 1
fi

echo "All 'default' ServiceAccounts have automountServiceAccountToken: false"

echo "==> Detecting Pods using the 'default' ServiceAccount (no automatic change)"

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 "Found Pods using the 'default' ServiceAccount: $pods_using_default_sa"
echo "Listing them for manual remediation (create and bind explicit ServiceAccounts, then update pod specs):"
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| select(.spec.serviceAccountName == "default")
| "\(.metadata.namespace) \(.metadata.name)"
' \
| while read -r ns name; do
echo " Namespace: $ns Pod: $name"
done
else
echo "No Pods are currently using the 'default' ServiceAccount."
fi

echo "==> Final verification (re-running benchmark audit logic)"

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

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

if [ "$default_sa_count_check" -gt 0 ]; then
echo "default_sa_not_auto_mounted"
fi

if [ "$pods_using_default_sa_check" -gt 0 ]; then
echo "default_sa_used_in_pods"
fi

if [ "$default_sa_count_check" -eq 0 ]; then
echo "Remediation complete: all 'default' ServiceAccounts have automountServiceAccountToken: false."
fi

# Note: Pods still using the 'default' ServiceAccount must be changed by:
# - Creating explicit ServiceAccounts per workload with only needed permissions
# - Updating Pod/Deployment specs (.spec.serviceAccountName) to use them