What Are the Security Risks of the Default ServiceAccount?
Every namespace has a default ServiceAccount that is automatically assigned to Pods without an explicit serviceAccountName. If RBAC bindings are added to the default ServiceAccount, every Pod in that namespace inherits those permissions, creating an over-privileged attack surface.
Detailed Answer
Every Kubernetes namespace is created with a ServiceAccount called default. When a Pod does not specify a serviceAccountName, it automatically runs as this default ServiceAccount. This seemingly harmless behavior creates a significant security risk when the default ServiceAccount accumulates permissions.
The Problem
Consider this common scenario:
- A developer needs a Pod to list ConfigMaps in the
appnamespace. - Instead of creating a dedicated ServiceAccount, they bind the permission to
default. - Now every Pod in the namespace — including those that never need API access — can list ConfigMaps.
- Over time, more permissions are added to
defaultfor convenience. - A compromised Pod (e.g., through a vulnerable dependency) can now query the API server with all accumulated permissions.
# This is dangerous — granting permissions to the default ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: default-can-read-secrets
namespace: app
subjects:
- kind: ServiceAccount
name: default
namespace: app
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
With this binding, every Pod in the app namespace (unless explicitly using another ServiceAccount) can read Secrets.
Real-World Attack Scenario
- An attacker exploits an RCE vulnerability in a web application Pod.
- The Pod runs as the
defaultServiceAccount, which has accumulated permissions. - The attacker reads the mounted token from
/var/run/secrets/kubernetes.io/serviceaccount/token. - Using that token, the attacker queries the API server to list Secrets, read ConfigMaps, or discover other workloads.
- If the default ServiceAccount has
create podspermission, the attacker can launch new Pods with even broader access.
Mitigation: Lock Down the Default ServiceAccount
Step 1: Disable automatic token mounting.
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: production
automountServiceAccountToken: false
Apply this to every namespace:
# Patch the default ServiceAccount in all namespaces
for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
kubectl patch serviceaccount default -n "$ns" \
-p '{"automountServiceAccountToken": false}'
done
Step 2: Create dedicated ServiceAccounts for each workload.
apiVersion: v1
kind: ServiceAccount
metadata:
name: order-processor
namespace: production
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-processor
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: order-processor
template:
metadata:
labels:
app: order-processor
spec:
serviceAccountName: order-processor
containers:
- name: app
image: order-processor:3.1
resources:
requests:
cpu: "200m"
memory: "256Mi"
Step 3: Remove any existing bindings to the default ServiceAccount.
# Find all bindings referencing the default ServiceAccount
kubectl get rolebindings --all-namespaces -o json | \
jq -r '.items[] |
select(.subjects[]? | .name == "default" and .kind == "ServiceAccount") |
"\(.metadata.namespace)/\(.metadata.name)"'
kubectl get clusterrolebindings -o json | \
jq -r '.items[] |
select(.subjects[]? | .name == "default" and .kind == "ServiceAccount") |
.metadata.name'
Step 4: Enforce with admission control.
Use a policy engine to reject Pods that use the default ServiceAccount:
# Example: Kyverno policy to block default ServiceAccount
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-default-sa
spec:
validationFailureAction: Enforce
rules:
- name: check-sa
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Pods must use a dedicated ServiceAccount, not 'default'."
pattern:
spec:
serviceAccountName: "!default"
Audit Script
Run this periodically to check for default ServiceAccount misuse:
#!/bin/bash
echo "=== Pods using default ServiceAccount ==="
kubectl get pods --all-namespaces -o json | \
jq -r '.items[] |
select(.spec.serviceAccountName == "default" or
.spec.serviceAccountName == null) |
"\(.metadata.namespace)/\(.metadata.name)"'
echo ""
echo "=== Bindings referencing default ServiceAccount ==="
kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | \
jq -r '.items[] |
select(.subjects[]? | .name == "default" and .kind == "ServiceAccount") |
"\(.kind): \(.metadata.namespace // "cluster")/\(.metadata.name)"'
echo ""
echo "=== Default ServiceAccounts with token mounting enabled ==="
kubectl get serviceaccount default --all-namespaces -o json | \
jq -r '.items[] |
select(.automountServiceAccountToken != false) |
.metadata.namespace'
What About the Default ServiceAccount in kube-system?
The kube-system namespace deserves special attention. Some cluster components may rely on the default ServiceAccount. Do not blindly disable token mounting in kube-system without verifying that no critical components depend on it. Test in a staging environment first.
Summary of Best Practices
| Practice | Why |
|---|---|
| Disable automountServiceAccountToken on default | Prevents token exposure in Pods that do not need API access |
| Create per-workload ServiceAccounts | Limits blast radius — one compromised SA does not affect others |
| Never bind permissions to default | Prevents accidental privilege inheritance |
| Enforce with admission control | Catches misconfiguration before it reaches the cluster |
| Audit regularly | Detect drift from the desired security posture |
Why Interviewers Ask This
Interviewers ask this to probe your security awareness. The default ServiceAccount is a common source of privilege escalation in real-world clusters, and knowing how to lock it down is essential.
Common Follow-Up Questions
Key Takeaways
- Every namespace has a default ServiceAccount — Pods use it unless overridden.
- Adding RBAC bindings to the default ServiceAccount affects every Pod in the namespace.
- Always create dedicated ServiceAccounts and disable token mounting on the default.
- Use admission policies to enforce that Pods specify a non-default ServiceAccount.