Prefer Using Dedicated Service Accounts
More Info:
Assign each pod a dedicated service account instead of relying on the default service account, so that permissions can be scoped per workload.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all workloads and their service accounts
- Run on: any machine with
kubectlaccess - Command (per namespace; start with production namespaces):
kubectl get pods -A -o custom-columns='NAMESPACE:.metadata.namespace,POD:.metadata.name,SA:.spec.serviceAccountName' | sort
- Identify pods where
SAis empty ordefault, especially for internet-facing, privileged, or data-sensitive workloads.
- Run on: any machine with
-
Review namespace-level usage of the default service account
- Run on: any machine with
kubectlaccess - Commands:
kubectl get sa -Akubectl get sa default -n <namespace> -o yamlkubectl get rolebinding,clusterrolebinding -A | grep default | grep ServiceAccount
- Decide per namespace whether the
defaultservice account is (a) unused and should stay unprivileged, or (b) used by many workloads and should be replaced with per-workload service accounts.
- Run on: any machine with
-
Design dedicated service accounts and permissions (IaC / control-plane configuration)
- In your cloud/IaC configuration (e.g., Helm values, Terraform, CD pipeline manifests, or cloud console workload configuration screens), for each application:
- Define a dedicated
ServiceAccountobject name (e.g.,orders-api-sa). - Bind that service account only to the minimal
Role/ClusterRoleneeded.
- Define a dedicated
- Example manifest snippet to model in IaC (do not apply with
kubectlif you manage via IaC):apiVersion: v1kind: ServiceAccountmetadata:name: orders-api-sanamespace: prod
- In your cloud/IaC configuration (e.g., Helm values, Terraform, CD pipeline manifests, or cloud console workload configuration screens), for each application:
-
Update workload definitions to use dedicated service accounts
- In your cloud provider console, CLI, or IaC for each deployment/statefulset/cronjob:
- Set
spec.template.spec.serviceAccountNameto the dedicated service account.
- Set
- Example pod template snippet for IaC/console:
spec:template:spec:serviceAccountName: orders-api-sa
- Redeploy workloads via your normal CI/CD or cloud provider deployment mechanism.
- In your cloud provider console, CLI, or IaC for each deployment/statefulset/cronjob:
-
Optionally restrict the default service account
- In namespaces where dedicated service accounts are now used for all meaningful workloads:
- Ensure the
defaultservice account has no elevatedRoleBinding/ClusterRoleBinding. Remove or adjust bindings in IaC/cloud console where they referencedefault.
- Ensure the
- If your provider supports toggling “automount service account token” at namespace or service account level, disable it for
defaultwhere practical.
- In namespaces where dedicated service accounts are now used for all meaningful workloads:
-
Verify that dedicated service accounts are in use
- Run on: any machine with
kubectlaccess - Commands:
Confirm that all non-trivial workloads show a specific, non-kubectl get pods -A -o custom-columns='NAMESPACE:.metadata.namespace,POD:.metadata.name,SA:.spec.serviceAccountName' | sort
defaultservice account. For a spot check, inspect a pod’s full spec:kubectl get pod <pod-name> -n <namespace> -o yaml | grep -n 'serviceAccountName'
- Run on: any machine with
Using kubectl
kubectl cannot remediate this finding because it concerns how workloads are defined and deployed in your cloud provider / IaC configuration, not a one-off API change. Make the changes in your cloud console, CI/CD pipeline, or IaC templates to assign explicit, non-default service accounts to pods, and follow the guidance in the Manual Steps section to review and update those definitions.
Automation
#!/usr/bin/env bash
#
# Report pods that use the default service account in each namespace.
# Run on: any machine with kubectl access and correct kubeconfig.
# Requirements: kubectl, jq
set -euo pipefail
# Ensure kubectl works
kubectl auth can-i list pods >/dev/null 2>&1 || {
echo "ERROR: Current identity cannot list pods cluster-wide." >&2
exit 1
}
echo "=== Pods using default service accounts per namespace ==="
echo
# Header
printf "%-30s %-50s %-30s\n" "NAMESPACE" "POD" "SERVICE_ACCOUNT"
printf -- "%0.s-" {1..120}; echo
# Iterate all namespaces
for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'); do
# List all pods with their namespace, name, serviceAccountName
kubectl get pods -n "$ns" -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
sa: (.spec.serviceAccountName // "default")
}
| select(.sa == "default")
| "\(.ns) \(.pod) \(.sa)"
' 2>/dev/null \
| while read -r ns_name pod_name sa_name; do
printf "%-30s %-50s %-30s\n" "$ns_name" "$pod_name" "$sa_name"
done
done
echo
echo "=== Summary: count of pods using the default service account per namespace ==="
echo
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
sa: (.spec.serviceAccountName // "default")
}
| select(.sa == "default")
| .ns
' \
| sort \
| uniq -c \
| awk '{printf "namespace=%-40s pods_using_default_sa=%s\n", $2, $1}'
How to interpret the output
- Any line in the first table shows a pod currently using the
defaultservice account in its namespace. - Namespaces with a non-zero
pods_using_default_sacount in the summary need review. - For each such pod, decide (manually) whether:
- It is acceptable for it to use the namespace’s
defaultservice account with its current RBAC, or - You should create and assign a dedicated, least-privilege service account via your cloud/IaC configuration.
- It is acceptable for it to use the namespace’s