Skip to main content

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

Manual Steps
  1. Identify AKS cluster and AAD configuration (any machine with Azure CLI access)

    az aks list -o table
    az aks show \
    --resource-group <RESOURCE_GROUP_NAME> \
    --name <CLUSTER_NAME> \
    --query "{aadProfile:aadProfile, oidcIssuerProfile:oidcIssuerProfile, apiServerAccessProfile:apiServerAccessProfile}" \
    -o json
    • Confirm whether aadProfile or oidcIssuerProfile are enabled and properly configured.
  2. 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 table

    az 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.
  3. Enumerate current Kubernetes access subjects (any machine with kubectl access)

    kubectl get clusterrolebindings -o wide
    kubectl get rolebindings --all-namespaces -o wide
    • Look for bindings that grant broad roles (e.g., cluster-admin) to generic groups like system:authenticated, system:serviceaccounts, or legacy local users instead of specific Azure AD users/groups.
  4. 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.
  5. 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-issuer and 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.
  6. Verify configuration and effective access (any machine with kubectl and Azure CLI access)

    # Confirm AAD / OIDC still enabled
    az aks show \
    -g <RESOURCE_GROUP_NAME> \
    -n <CLUSTER_NAME> \
    --query "{aadProfile:aadProfile, oidcIssuerProfile:oidcIssuerProfile}" \
    -o json

    # Re-check bindings for generic subjects
    kubectl 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-credentials and basic kubectl commands to confirm that access aligns with the intended roles.
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:

    • NAMESPACE is a non-system namespace (not kube-system, kube-public, kube-node-lease, gatekeeper-system, etc.), and
    • SERVICEACCOUNT is default
      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.

Additional Reading: