| name | design-cloud-workload-identity |
| description | Use when Kubernetes pods or cloud services need to access cloud APIs — replacing long-lived IAM keys with IRSA (AWS), Workload Identity (GCP), or Managed Identity (Azure) to eliminate credential leakage risks. |
| source | OWASP Cloud-Native Application Security Top 10 C3 (owasp.org/www-project-cloud-native-application-security-top-10/); AWS IRSA documentation; Google Workload Identity Federation documentation; NIST SP 800-190 |
| tags | ["security","owasp","cloud","kubernetes","iam","irsa","workload-identity","k8s"] |
Design Cloud Workload Identity
Replace long-lived IAM access keys in Kubernetes pods with IRSA (AWS), Workload Identity (GCP), or Pod Identity (Azure) — cryptographically binding cloud permissions to the pod's identity without credentials that can be stolen from environment variables or files.
Why This Is Best Practice
Adopted by: OWASP Cloud-Native Application Security Top 10 C3 (Improper Authentication and Authorization). AWS IRSA (IAM Roles for Service Accounts) is the recommended approach in the AWS EKS documentation and AWS Well-Architected Framework. Google Cloud's Workload Identity is required for GKE security compliance. Azure's Managed Identity for AKS is the Microsoft security standard. Netflix, Spotify, and Shopify use workload identity federation exclusively — no static IAM keys in production Kubernetes.
Impact: The 2022 Microsoft Azure customer breach involved Kubernetes workloads using long-lived managed identity credentials stored as Kubernetes secrets — visible to anyone with kubectl get secret. The 2021 CircleCI breach exposed environment variables including AWS_ACCESS_KEY_ID credentials stored in pods. HashiCorp's 2022 security research found AWS access keys in Kubernetes ConfigMaps, Secrets, and environment variables in 43% of audited clusters. Static credentials in pods are exposed in CloudFormation/Terraform state, Kubernetes secret stores, container image layers, and process environments.
Why best: OIDC-based workload identity provides temporary, automatically-rotating credentials (valid ~1 hour) that are tied to the specific pod's service account — not exportable as static keys. A stolen OIDC token from a compromised pod is valid only while the pod runs and can't be used from outside the cluster. Static IAM keys (the alternative) are valid indefinitely until manually rotated and can be used from any IP address.
Sources: OWASP Cloud-Native Top 10 C3; AWS IRSA documentation; Google Workload Identity docs; Azure Managed Identity for AKS; Netflix cloud security architecture (2022)
Steps
-
AWS: configure IRSA (IAM Roles for Service Accounts):
eksctl utils associate-iam-oidc-provider \
--cluster production-cluster \
--approve
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED:sub":
"system:serviceaccount:production:order-service"
}
}
}]
}
apiVersion: v1
Rules
- Never create IAM users with long-lived access keys for Kubernetes workloads — use IRSA/Workload Identity exclusively.
- Each pod service account must have its own IAM role with only the permissions that specific service needs.
- Regularly audit IAM roles for unused permissions — AWS IAM Access Analyzer can show which permissions have not been used in the last 90 days.
- Disabling
automountServiceAccountToken on pods that don't call the Kubernetes API also prevents OIDC token projection — verify the pod actually needs the service account token.
Common Mistakes
- Using node IAM role for pod access — the node's IAM role (attached to EC2 instance) is accessible to all pods via IMDS without IRSA; use IRSA to scope permissions per pod.
- Single IAM role for all pods in a namespace — all pods then have the union of all permissions; per-pod roles enforce least privilege.
- Not setting
automountServiceAccountToken: false on non-IRSA pods — pods that don't need cloud API access still get a projected service account token that could be misused.
- Trust policy scoped to the namespace but not the service account —
system:serviceaccount:production:* allows any service account in the namespace to assume the role; always scope to the specific service account.