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
Remediation​
Manual Steps
-
Identify all default service accounts and namespaces
Run on: any machine with kubectl accesskubectl get serviceaccount default --all-namespaces -o wide -
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}'); dokubectl patch serviceaccount default \-n "$ns" \--type merge \-p '{"automountServiceAccountToken": false}' || truedone -
List pods currently using the default service account
Run on: any machine with kubectl accesskubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default")]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' -
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 -
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 usesserviceAccountName: default:kubectl edit deployment your-deployment -n your-namespaceIn
.spec.template.spec:serviceAccountName: app-sa # change from "default"automountServiceAccountToken: false # add if the pod should not get a token -
Verification
Run on: any machine with kubectl access# 1) Confirm all default SAs have automount disableddefault_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 ]; thenecho "default_sa_not_auto_mounted"elseecho "all_default_sa_automount_disabled"fi# 2) Confirm no pods are using the default service accountpods_using_default_sa=$(kubectl get pods --all-namespaces -o json | jq '[.items[] | select(.spec.serviceAccountName == "default")] | length')if [ "$pods_using_default_sa" -gt 0 ]; thenecho "default_sa_used_in_pods"elseecho "no_pods_using_default_sa"fi
Using kubectl
On any machine with kubectl access:
- Disable token automounting on all existing
defaultServiceAccounts
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl patch serviceaccount default \
-n "$ns" \
--type merge \
-p '{"automountServiceAccountToken": false}'
done
- 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
-
Optionally, prevent default use in new workloads by setting an explicit ServiceAccount in your own pod/deployment manifests and avoiding
serviceAccountName: default. -
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