Skip to main content

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

Manual Steps
  1. List pods that rely on the default ServiceAccount in each namespace

    • Run on: any machine with kubectl access
    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 default instead of a dedicated ServiceAccount.

  2. Identify application/owner and required permissions for each pod

    • Run on: any machine with kubectl access
    # Example for one pod; repeat as needed
    kubectl get pod <pod-name> -n <namespace> -o yaml

    Use labels, annotations, and image names to determine the team/owner and what cluster or namespace permissions (if any) the pod actually needs.

  3. 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.
  4. 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: v1
    kind: ServiceAccount
    metadata:
    name: <workload-sa>
    namespace: <namespace>
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    name: <workload-role>
    namespace: <namespace>
    rules:
    - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
    name: <workload-rb>
    namespace: <namespace>
    subjects:
    - kind: ServiceAccount
    name: <workload-sa>
    namespace: <namespace>
    roleRef:
    kind: Role
    name: <workload-role>
    apiGroup: rbac.authorization.k8s.io

    Adapt these objects in your cloud/IaC configuration for each workload.

  5. 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).
  6. Verify that pods no longer use the default ServiceAccount

    • Run on: any machine with kubectl access
    # Confirm new ServiceAccount is used
    kubectl get pods -n <namespace> \
    -o custom-columns='POD:.metadata.name,SA:.spec.serviceAccountName'
    # Re-run global check
    kubectl 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 default ServiceAccount, and all others use dedicated accounts with least-privilege RBAC.

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_SA indicate pods that:
    • Either explicitly use serviceAccountName: default, or
    • Have no spec.serviceAccountName set and therefore rely on the namespace’s default service account.
  • These pods should be reviewed to decide whether a dedicated, least-privileged service account should be created and referenced in their Pod/Deployment specs.

Additional Reading: