Prefer Using Dedicated Aks Service Accounts
More Info:
Use Approved Container Registries.
Risk Level
High
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AKS
- CIS Critical Security Controls v8
- 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
-
Identify AKS cluster and AAD configuration (any machine with Azure CLI access)
az aks list -o tableaz aks show \--resource-group <RESOURCE_GROUP_NAME> \--name <CLUSTER_NAME> \--query "{aadProfile:aadProfile, oidcIssuerProfile:oidcIssuerProfile, apiServerAccessProfile:apiServerAccessProfile}" \-o json- Confirm whether
aadProfileoroidcIssuerProfileare enabled and properly configured.
- Confirm whether
-
Review how cluster access is granted (any machine with Azure CLI access)
az role assignment list \--scope $(az aks show -g <RESOURCE_GROUP_NAME> -n <CLUSTER_NAME> --query id -o tsv) \-o tableaz role assignment list \--scope $(az aks show -g <RESOURCE_GROUP_NAME> -n <CLUSTER_NAME> --query nodeResourceGroup -o tsv) \-o table- Verify that Azure AD users/groups (not generic or shared principals) are used for admin/operator roles and that least-privilege role definitions are applied.
-
Enumerate current Kubernetes access subjects (any machine with kubectl access)
kubectl get clusterrolebindings -o widekubectl get rolebindings --all-namespaces -o wide- Look for bindings that grant broad roles (e.g.,
cluster-admin) to generic groups likesystem:authenticated,system:serviceaccounts, or legacy local users instead of specific Azure AD users/groups.
- Look for bindings that grant broad roles (e.g.,
-
Decide and plan remediation approach (design review, no commands)
- Determine which Azure AD groups should map to which Kubernetes roles (for example, “AKS-Cluster-Admins” →
cluster-admin, “AKS-Developers-<TEAM>” → namespace-scoped roles). - Decide whether to:
- Enable AAD/OIDC integration if not already enabled (may require cluster upgrade/migration depending on cluster version), and
- Replace broad or generic role bindings with bindings to specific Azure AD groups.
- Determine which Azure AD groups should map to which Kubernetes roles (for example, “AKS-Cluster-Admins” →
-
Implement Azure AD integration and RBAC mapping (any machine with Azure CLI access)
- If AAD is not enabled, create or select appropriate Azure AD groups, then follow Azure guidance to enable AAD/OIDC on the cluster (this may require creating a new cluster with
--enable-aad/--enable-oidc-issuerand migrating workloads). - After AAD is in place, create least-privilege role bindings to Azure AD groups:
# Example: bind AD group objectId to cluster-admin (adjust as needed)kubectl create clusterrolebinding aks-cluster-admins \--clusterrole=cluster-admin \--group=<AAD_GROUP_OBJECT_ID>
- Gradually remove legacy or overly broad bindings identified in step 3 once equivalent AAD-based bindings are verified.
- If AAD is not enabled, create or select appropriate Azure AD groups, then follow Azure guidance to enable AAD/OIDC on the cluster (this may require creating a new cluster with
-
Verify configuration and effective access (any machine with kubectl and Azure CLI access)
# Confirm AAD / OIDC still enabledaz aks show \-g <RESOURCE_GROUP_NAME> \-n <CLUSTER_NAME> \--query "{aadProfile:aadProfile, oidcIssuerProfile:oidcIssuerProfile}" \-o json# Re-check bindings for generic subjectskubectl get clusterrolebindings -o yaml | grep -E "system:authenticated|system:serviceaccounts" -n || echo "No broad generic subjects found"kubectl get rolebindings --all-namespaces -o yaml | grep -E "system:authenticated|system:serviceaccounts" -n || echo "No broad generic subjects found"- Finally, have a user from each mapped Azure AD group run
az aks get-credentialsand basickubectlcommands to confirm that access aligns with the intended roles.
- Finally, have a user from each mapped Azure AD group run
Using kubectl
kubectl cannot configure Azure AD integration or enforce the use of dedicated AKS service accounts, because this control is managed at the AKS/ Azure AD level via the Azure portal, Azure CLI, or IaC. To address this finding, make the required changes in the managed control plane and identity configuration as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
# Purpose: Report pods that do NOT use a dedicated ServiceAccount (i.e., they use "default")
# Scope: Runs from any machine with kubectl access and appropriate RBAC
set -euo pipefail
echo "=== Checking for pods using the 'default' ServiceAccount in all namespaces ==="
echo
# Header
printf "%-32s %-32s %-40s %-20s\n" "NAMESPACE" "POD" "SERVICEACCOUNT" "CONTAINER_IMAGES"
printf "%-32s %-32s %-40s %-20s\n" "---------" "---" "--------------" "----------------"
# List all pods with their serviceAccountName and container images
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
sa: ( .spec.serviceAccountName // "default" ),
images: (
( .spec.containers // [] | map(.image) ) +
( .spec.initContainers // [] | map(.image) )
)
}
| select(.sa == "default") # Only show pods using the default ServiceAccount
| [
.ns,
.pod,
.sa,
( .images | join(",") )
]
| @tsv' | \
while IFS=$'\t' read -r ns pod sa images; do
printf "%-32s %-32s %-40s %-20s\n" "$ns" "$pod" "$sa" "$images"
done
echo
echo "=== Summary by namespace: count of pods using the 'default' ServiceAccount ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| {
ns: .metadata.namespace,
sa: ( .spec.serviceAccountName // "default" )
}
| select(.sa == "default")
| .ns' | \
sort | uniq -c | sort -nr || true
echo
echo "Review guidance:"
echo "1) Every workload should normally have a dedicated ServiceAccount with least-privilege RBAC."
echo "2) Any non-system namespace showing pods with ServiceAccount=default in the table above"
echo " is a potential issue and should be reviewed."
echo "3) Pay special attention to pods with powerful roles (cluster-admin, broad list/watch)"
echo " or access to sensitive data (secrets, key stores, databases)."
echo
echo "NOTE: This script only reports usage of the 'default' ServiceAccount."
echo " It does NOT change cluster configuration or RBAC; remediation must be done manually."
How to run (any machine with kubectl access):
chmod +x report-default-serviceaccounts.sh
./report-default-serviceaccounts.sh
What output indicates a problem
-
In the first table, any row where:
NAMESPACEis a non-system namespace (notkube-system,kube-public,kube-node-lease,gatekeeper-system, etc.), andSERVICEACCOUNTisdefault
indicates a pod that is not using a dedicated ServiceAccount and should be reviewed.
-
In the summary section, any non-system namespace with a non-zero count of pods is a candidate for remediation:
- For each such namespace, plan to create one or more dedicated ServiceAccounts and bind them with least-privilege RBAC, then update pod specs/deployments to use them.