Prefer Using Dedicated Service Accounts
More Info:
When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace. Prefer using dedicated service accounts.
Risk Level
High
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CIS OKE
- 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)
- 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
- Remediation
Remediation
Manual Steps
-
List pods that rely on the default ServiceAccount in each namespace
- Run on: any machine with
kubectlaccess
kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'Review which workloads are unintentionally using
defaultinstead of a dedicated ServiceAccount. - Run on: any machine with
-
Identify application/owner and required permissions for each pod
- Run on: any machine with
kubectlaccess
# Example for one pod; repeat as neededkubectl get pod <pod-name> -n <namespace> -o yamlUse labels, annotations, and image names to determine the team/owner and what cluster or namespace permissions (if any) the pod actually needs.
- Run on: any machine with
-
Decide whether a dedicated ServiceAccount is required
- For each pod/workload:
- If it needs no API access, plan to use a dedicated ServiceAccount with no Roles/RoleBindings (or consider disabling automount of token).
- If it needs specific access, list the minimal verbs, resources, and namespaces required.
- If it is a platform/add-on component already using a purpose-built ServiceAccount (not
default), no change is needed.
- For each pod/workload:
-
Create least-privilege ServiceAccounts and RBAC bindings (via cloud/IaC tooling)
- Implement in your cloud provider/IaC (e.g., Terraform, Helm values, or managed control-plane config) so changes are controlled and repeatable.
- Example Kubernetes manifest snippet to model in your IaC (do not apply directly with kubectl if that violates your process):
apiVersion: v1kind: ServiceAccountmetadata:name: <workload-sa>namespace: <namespace>---apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: <workload-role>namespace: <namespace>rules:- apiGroups: [""]resources: ["pods"]verbs: ["get", "list"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: <workload-rb>namespace: <namespace>subjects:- kind: ServiceAccountname: <workload-sa>namespace: <namespace>roleRef:kind: Rolename: <workload-role>apiGroup: rbac.authorization.k8s.ioAdapt these objects in your cloud/IaC configuration for each workload.
-
Update workload definitions to use the dedicated ServiceAccount
- In your deployment mechanism (cloud console, managed add-on config, Helm charts, or IaC templates), add or change the pod spec to reference the new ServiceAccount:
spec:serviceAccountName: <workload-sa>- Redeploy the workload through your normal CI/CD or cloud control-plane process.
- Operational impact: pods are recreated; plan rollout to avoid downtime (e.g., use rolling updates, multiple replicas).
-
Verify that pods no longer use the default ServiceAccount
- Run on: any machine with
kubectlaccess
# Confirm new ServiceAccount is usedkubectl get pods -n <namespace> \-o custom-columns='POD:.metadata.name,SA:.spec.serviceAccountName'# Re-run global checkkubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.serviceAccountName=="default")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'Ensure that only intentionally unprivileged workloads (if any) still use the
defaultServiceAccount, and all others use dedicated accounts with least-privilege RBAC. - Run on: any machine with
Using kubectl
kubectl cannot change this setting because it is governed by how workloads and service accounts are defined in your cloud provider’s managed control plane and IaC, not by a single API toggle. To remediate, adjust your deployment manifests and provider/IaC configuration so pods use dedicated service accounts, following the guidance in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Report pods that use the default service account (or have none explicitly set)
# Run from any machine with kubectl access and sufficient RBAC to list pods.
# Requires: kubectl, jq
set -euo pipefail
echo "Namespace,Pod,ServiceAccount,Problem"
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
name: .metadata.name,
sa: (
# spec.serviceAccountName is the configured SA (may be null/empty)
.spec.serviceAccountName // ""
)
}
| . + {
problem: (
if .sa == "" or .sa == "default"
then "USES_DEFAULT_OR_UNSET_SA"
else ""
end
)
}
| select(.problem != "")
| "\(.ns),\(.name),\(.sa),\(.problem)"
'
How to interpret the output:
- Each line is:
Namespace,Pod,ServiceAccount,Problem. - Lines with
Problem=USES_DEFAULT_OR_UNSET_SAindicate pods that:- Either explicitly use
serviceAccountName: default, or - Have no
spec.serviceAccountNameset and therefore rely on the namespace’s default service account.
- Either explicitly use
- These pods should be reviewed to decide whether a dedicated, least-privileged service account should be created and referenced in their Pod/Deployment specs.