Workload Identity
Key Takeaways
- Workload identity assigns a cryptographic identity to each workload — proving 'I am service X' without static secrets or network-based trust
- SPIFFE (Secure Production Identity Framework for Everyone) standardizes workload identity as URIs embedded in X.509 certificates
- Cloud workload identity (GKE, EKS) lets pods assume cloud IAM roles without storing credentials — using projected service account tokens
- Workload identity is the foundation of zero-trust: authenticate every request based on cryptographic proof, not network location
Workload identity is the practice of assigning a verifiable cryptographic identity to every software workload — containers, pods, VMs, serverless functions, or any process that communicates over a network. Instead of trusting workloads based on their IP address or network segment (which can be spoofed), or authenticating with static credentials (which can be stolen), workload identity uses short-lived certificates or tokens that cryptographically prove “I am this specific service, running in this specific environment, with these specific permissions.”
Why it matters
- Zero-trust foundation — in zero-trust architectures, network location doesn’t grant trust. Every request must be authenticated. Workload identity provides the cryptographic proof that makes this possible.
- Eliminates static secrets — instead of distributing API keys, passwords, or long-lived tokens to workloads, identity is derived from the workload’s runtime context (service account, namespace, cluster). Nothing to steal, nothing to rotate.
- Cross-platform identity — SPIFFE provides a standard identity format that works across Kubernetes, VMs, bare metal, and multi-cloud. A workload in GKE can authenticate to a service in AWS using the same identity framework.
- Fine-grained authorization — policies can specify “pod running as service-account X in namespace Y can access resource Z.” This is more precise than network policies (which only see IPs) or API keys (which don’t encode context).
- Automatic credential rotation — workload identity credentials are short-lived (minutes to hours) and automatically refreshed. No rotation procedures, no expiry alerts, no credential management overhead.
How it works
SPIFFE (standard workload identity):
- SPIFFE ID — a URI identifying the workload:
spiffe://trust-domain/path(e.g.,spiffe://example.com/ns/production/sa/payment-service) - SVID (SPIFFE Verifiable Identity Document) — an X.509 certificate with the SPIFFE ID in the SAN URI field, or a JWT token containing the SPIFFE ID
- SPIRE (SPIFFE Runtime Environment) — the reference implementation that issues SVIDs to workloads based on attestation (proving the workload is what it claims to be)
Cloud workload identity (Kubernetes → Cloud IAM):
- Pod runs with a Kubernetes service account
- Kubernetes projects a signed service account token into the pod
- Pod presents the token to the cloud provider’s token exchange endpoint
- Cloud provider validates the token (trusts the cluster’s OIDC issuer)
- Cloud provider returns short-lived cloud credentials (IAM role)
- Pod accesses cloud resources (S3, KMS, databases) with the assumed role
In real systems
GKE Workload Identity (pod → GCP IAM):
# 1. Create GCP service account
# gcloud iam service-accounts create payment-sa
# 2. Bind K8s service account to GCP service account
# gcloud iam service-accounts add-iam-policy-binding payment-sa@project.iam.gserviceaccount.com \
# --role roles/iam.workloadIdentityUser \
# --member "serviceAccount:project.svc.id.goog[production/payment-k8s-sa]"
# 3. Annotate K8s service account
apiVersion: v1
kind: ServiceAccount
metadata:
name: payment-k8s-sa
namespace: production
annotations:
iam.gke.io/gcp-service-account: payment-sa@project.iam.gserviceaccount.com
# 4. Pod uses the service account — automatically gets GCP credentials
apiVersion: v1
kind: Pod
spec:
serviceAccountName: payment-k8s-sa
containers:
- name: app
# Application uses default credentials — no keys, no env vars
# GCP client libraries automatically use workload identity
EKS Pod Identity / IRSA (pod → AWS IAM):
# Service account with IAM role annotation
apiVersion: v1
kind: ServiceAccount
metadata:
name: s3-reader
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/s3-reader-role
# Pod automatically receives AWS credentials via projected token
# AWS SDK detects the token and assumes the IAM role
# No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY needed
SPIRE (cross-platform workload identity):
# Register a workload with SPIRE
spire-server entry create \
-spiffeID spiffe://example.com/ns/production/sa/payment \
-parentID spiffe://example.com/node/k8s-node-01 \
-selector k8s:ns:production \
-selector k8s:sa:payment-service
# Workload receives SVID (X.509 certificate):
# Subject Alternative Name: URI:spiffe://example.com/ns/production/sa/payment
# Valid for: 1 hour (auto-rotated by SPIRE agent)
# Other services verify the SVID to authenticate the caller
Istio workload identity (automatic via service mesh):
# Every pod in the mesh automatically gets:
# SPIFFE ID: spiffe://cluster.local/ns/{namespace}/sa/{service-account}
# X.509 certificate with 24-hour validity
# Automatic rotation before expiry
# Authorization policy uses these identities:
principals: ["cluster.local/ns/production/sa/frontend"]
# Only the frontend service (proven cryptographically) can access this endpoint
Where it breaks
Token audience mismatch — the projected service account token has an audience field. The cloud provider expects a specific audience value. If the cluster’s OIDC configuration specifies a different audience than what the cloud provider expects, token exchange fails with “invalid audience.” This is a common misconfiguration during initial setup — verify the audience matches between the cluster OIDC issuer and the cloud provider’s trust configuration.
OIDC issuer not publicly reachable — cloud workload identity requires the cluster’s OIDC discovery endpoint (/.well-known/openid-configuration) to be publicly accessible so the cloud provider can validate tokens. Private clusters with no public endpoint can’t use standard workload identity without additional configuration (private OIDC endpoint, or a proxy). EKS and GKE handle this automatically for managed clusters.
Identity too coarse — all pods using the same Kubernetes service account get the same workload identity (and therefore the same cloud permissions). If 5 different microservices share one service account for convenience, they all have access to each other’s cloud resources. Workload identity is only as granular as your service account assignment. Use one service account per workload for proper least-privilege.
Operational insight
Workload identity solves the “secret zero” problem — how does a workload get its first credential without already having a credential? The answer: attestation. The workload proves its identity through properties of its runtime environment (which Kubernetes node it’s on, which namespace, which service account, which container image) rather than through a pre-distributed secret. SPIRE calls this “workload attestation.” Cloud providers do it through projected service account tokens signed by the cluster’s CA. The key insight: the workload’s identity is derived from its context, not from a secret it possesses. This means there’s nothing to distribute, nothing to steal, and nothing to rotate — the identity exists as long as the workload runs in the correct context.
Related topics
Ready to Secure Your Enterprise?
Experience how our cryptographic solutions simplify, centralize, and automate identity management for your entire organization.