Inhoudsopgave
- Doel
- Vereisten
- Waarom statische credentials in Secrets niet voldoen
- Het gedeelde mechanisme: OIDC-federatie
- EKS: IRSA en Pod Identity
- GKE: Workload Identity Federation
- AKS: Microsoft Entra Workload ID
- Vergelijking tussen providers
- IRSA vs. Pod Identity: wanneer welke
- Beveiligingsaanbevelingen voor alle providers
- Eindresultaat verifiëren
- Veelvoorkomende problemen
- Wanneer escaleren
Doel
Na het doorlopen van deze gids authenticeren je pods zich bij clouddiensten (S3, GCS, Azure Storage en vergelijkbaar) met kortstondige, automatisch roterende credentials, zonder dat er ergens in je cluster een statische access key staat.
Vereisten
- Een EKS-, GKE- of AKS-cluster (minimaal een) met de minimumversies uit de vergelijkingstabel
kubectl-toegang met rechten om ServiceAccounts aan te maken en te annoteren- IAM-rechten aan de cloudzijde: rollen aanmaken (AWS), IAM-policybindings (GCP) of managed identities (Azure)
- CLI-tools geïnstalleerd:
eksctlenaws(EKS),gcloud(GKE), ofaz(AKS) - Bekend met Kubernetes RBAC en service accounts
Waarom statische credentials in Secrets niet voldoen
Kubernetes Secrets worden standaard onversleuteld opgeslagen in etcd. Base64-encoding is serialisatie, geen beveiliging. Iedereen met API-toegang of etcd-backups kan elke Secret in het cluster lezen. Een langlevende AWS-accesskey of GCP-serviceaccount-JSON in een Secret opslaan betekent dat die key onbeperkt bruikbaar is, overal, door iedereen die hem te pakken krijgt.
Kortstondige tokens lossen beide problemen in een keer op. Workload identity geeft tokens uit die binnen een uur verlopen en niet buiten de oorspronkelijke vertrouwensketen herbruikbaar zijn. Geen key om handmatig te roteren, geen credential die in Git kan lekken. Wil je dieper vergelijken hoe Sealed Secrets, ESO en Vault het etcd-probleem aanpakken? Bekijk dan de secrets management-vergelijking.
Het gedeelde mechanisme: OIDC-federatie
Alle drie de providers gebruiken hetzelfde onderliggende protocol:
- Het Kubernetes-cluster treedt op als een OIDC identity provider en publiceert een discovery-endpoint en signing keys.
- Een pod krijgt een kortstondige, audience-scoped JWT (de projected service account token) ondertekend door de private key van het cluster.
- De pod toont die JWT aan de Security Token Service van de cloudprovider (AWS STS, Google STS, Microsoft Entra ID).
- De STS valideert de JWT-handtekening tegen de gepubliceerde sleutels van het cluster, controleert de trust-voorwaarden en geeft kortstondige cloudcredentials uit.
- De applicatie gebruikt die credentials transparant via standaard SDK's. Geen codewijzigingen nodig.
De cloud slaat nooit een kopie op van de Kubernetes private key. Alleen de publieke signing keys zijn nodig om tokens te verifiëren. Dat is de beveiligingseigenschap die het hele model laat werken.
EKS: IRSA en Pod Identity
AWS biedt twee mechanismen. IRSA (IAM Roles for Service Accounts) bestaat sinds 2019. EKS Pod Identity werd in november 2023 gelanceerd als eenvoudiger alternatief.
IRSA-setup
IRSA werkt door een OIDC JWT in de pod te injecteren op /var/run/secrets/eks.amazonaws.com/serviceaccount/token. De AWS SDK leest dat pad via de AWS_WEB_IDENTITY_TOKEN_FILE omgevingsvariabele en roept automatisch STS AssumeRoleWithWebIdentity aan.
Stap 1. Koppel een IAM OIDC provider aan het cluster (eenmalig per cluster):
# Maakt de OIDC provider aan in IAM voor je EKS-cluster
eksctl utils associate-iam-oidc-provider \
--cluster=payments-prod \
--approve
Gebruikt je cluster een VPC-endpoint? Dan kan dit commando falen met NXDOMAIN op oidc.eks.<region>.amazonaws.com. Voer het uit van buiten de VPC of stel split-horizon DNS in via Route 53 Resolver.
Stap 2. Maak een IAM-rol aan met een trust policy die is beperkt tot een specifiek service account:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/ABCDEF1234567890"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.eu-west-1.amazonaws.com/id/ABCDEF1234567890:sub": "system:serviceaccount:payments:s3-reader"
}
}
}]
}
De StringEquals-conditie op :sub is niet onderhandelbaar. Zonder die conditie kan elk service account in het cluster deze rol aannemen.
Stap 3. Annoteer het Kubernetes ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: s3-reader
namespace: payments
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/payments-s3-reader
Stap 4. Verwijs naar het service account in je pod spec en deploy. De SDK regelt de rest. Verifieer door de omgevingsvariabelen van de pod te controleren:
kubectl exec -n payments deploy/payment-processor -- env | grep AWS_
# Verwachte output:
# AWS_ROLE_ARN=arn:aws:iam::123456789012:role/payments-s3-reader
# AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token
Pod Identity-setup
Pod Identity vereist geen OIDC-providerregistratie. Een EKS Pod Identity Agent DaemonSet draait op elke node en serveert credentials op 169.254.170.23.
Stap 1. Installeer de Pod Identity Agent add-on (overslaan bij EKS Auto Mode):
aws eks create-addon \
--cluster-name payments-prod \
--addon-name eks-pod-identity-agent
Stap 2. Maak een IAM-rol aan met een herbruikbare trust policy (niet clusterspecifiek):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "pods.eks.amazonaws.com"},
"Action": ["sts:AssumeRole", "sts:TagSession"]
}]
}
Dezelfde trust policy werkt voor elk EKS-cluster in je account. Geen cluster-specifieke OIDC ARN nodig.
Stap 3. Maak de pod identity association aan:
aws eks create-pod-identity-association \
--cluster-name payments-prod \
--namespace payments \
--service-account s3-reader \
--role-arn arn:aws:iam::123456789012:role/payments-s3-reader
Geen annotatie nodig op het service account. De mapping leeft in het EKS control plane.
Gebruikt je omgeving een HTTP-proxy? Voeg dan 169.254.170.23 (IPv4) of [fd00:ec2::23] (IPv6) toe aan NO_PROXY zodat credential-verzoeken de proxy omzeilen.
IRSA-kanttekeningen
- Als IMDS niet is beperkt op nodeniveau, kunnen pods nog steeds terugvallen op de EC2-noderol, ongeacht de IRSA-configuratie.
- Pods met
hostNetwork: truehebben altijd IMDS-toegang. - Cross-account vereist handmatige role chaining: de pod neemt een rol aan in het eigen account, die vervolgens een rol aanneemt in het doelaccount.
- IRSA vereist Kubernetes 1.12+ voor
ProjectedServiceAccountToken-ondersteuning.
Pod Identity-kanttekeningen
- Ondersteunt geen Fargate, Windows-pods of EKS Anywhere.
- Vereist Kubernetes 1.24+ (platformversie
eks.4voor 1.28+). - Maximaal 5.000 pod identity associations per cluster.
- Native cross-account support (
targetRoleArn) werd in juni 2025 toegevoegd.
GKE: Workload Identity Federation
GKE Workload Identity Federation maakt gebruik van een per-project workload identity pool (PROJECT_ID.svc.id.goog) waarbij het cluster als identity provider is geregistreerd. Een GKE Metadata Server DaemonSet onderschept metadata-verzoeken en wisselt Kubernetes service account JWT's om voor Google access tokens via Google's Security Token Service.
Op Autopilot-clusters is Workload Identity Federation altijd ingeschakeld. Geen setup nodig.
Setup voor Standard clusters
Stap 1. Schakel de workload identity pool in op het cluster:
gcloud container clusters update payments-prod \
--location=europe-west4 \
--workload-pool=myproject-123.svc.id.goog
Stap 2. Schakel de GKE Metadata Server in op de nodepool:
gcloud container node-pools update default-pool \
--cluster=payments-prod \
--location=europe-west4 \
--workload-metadata=GKE_METADATA
Het inschakelen op een bestaande nodepool werkt direct voor alle workloads in die pool. Houd rekening met een korte verstoring.
Stap 3. Ken IAM-rechten direct toe aan de Kubernetes ServiceAccount principal (de aanbevolen methode sinds directe KSA-binding beschikbaar werd):
gcloud projects add-iam-policy-binding projects/myproject-123 \
--role=roles/storage.objectViewer \
--member="principal://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/myproject-123.svc.id.goog/subject/ns/payments/sa/gcs-reader" \
--condition=None
Deze aanpak slaat het legacy Google service account (GSA) impersonation-patroon volledig over. Geen GSA om aan te maken, geen workloadIdentityUser-binding, geen annotatie op de KSA. Sommige Google Cloud API's ondersteunen directe federatie nog niet en vereisen nog het legacy GSA-impersonatiepad.
Stap 4. Maak het Kubernetes ServiceAccount aan en deploy je workload:
apiVersion: v1
kind: ServiceAccount
metadata:
name: gcs-reader
namespace: payments
Verifieer:
kubectl exec -n payments deploy/payment-processor -- \
curl -s -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email
# Verwacht: principal://iam.googleapis.com/... (of GSA-e-mail bij legacy methode)
GKE-kanttekeningen
- Pods met
hostNetwork: trueomzeilen Workload Identity Federation. - De metadata server heeft een limiet van 500 gelijktijdige verbindingen per node; extra aanvragen worden in de wachtrij gezet.
- Workloads die dezelfde namespace en service account-naam delen over clusters in hetzelfde project delen dezelfde identiteit. Onbetrouwbare clusters in hetzelfde project kunnen elkaars workloads imiteren. Voorkom dit door aparte projecten of unieke namespace-prefixes te gebruiken.
- Token exchange API-quota: 6.000 verzoeken per minuut per project.
AKS: Microsoft Entra Workload ID
AKS Workload Identity verving het verouderde AAD Pod Identity (einde ondersteuning september 2025). Een mutating admission webhook injecteert omgevingsvariabelen en een projected token in pods die gelabeld zijn met azure.workload.identity/use: "true". De Azure Identity-clientbibliotheek wisselt het token om voor een Microsoft Entra-accesstoken.
Setup
Stap 1. Schakel de OIDC-issuer en Workload Identity in op het cluster:
# Nieuw cluster
az aks create \
--resource-group payments-rg \
--name payments-prod \
--enable-oidc-issuer \
--enable-workload-identity \
--generate-ssh-keys
# Bestaand cluster
az aks update \
--resource-group payments-rg \
--name payments-prod \
--enable-oidc-issuer \
--enable-workload-identity
Stap 2. Haal de OIDC issuer-URL op:
export AKS_OIDC_ISSUER="$(az aks show \
--name payments-prod \
--resource-group payments-rg \
--query "oidcIssuerProfile.issuerUrl" \
--output tsv)"
Stap 3. Maak een user-assigned managed identity aan en ken er een rol aan toe:
az identity create \
--name payments-keyvault-reader \
--resource-group payments-rg \
--location westeurope
export CLIENT_ID="$(az identity show \
--resource-group payments-rg \
--name payments-keyvault-reader \
--query 'clientId' --output tsv)"
Stap 4. Maak het Kubernetes ServiceAccount met de client-ID-annotatie:
apiVersion: v1
kind: ServiceAccount
metadata:
name: keyvault-reader
namespace: payments
annotations:
azure.workload.identity/client-id: "${CLIENT_ID}"
Stap 5. Maak de federated identity credential die de managed identity koppelt aan het Kubernetes service account:
az identity federated-credential create \
--name payments-keyvault-fedcred \
--identity-name payments-keyvault-reader \
--resource-group payments-rg \
--issuer "${AKS_OIDC_ISSUER}" \
--subject "system:serviceaccount:payments:keyvault-reader" \
--audience api://AzureADTokenExchange
De propagatie van de federated credential duurt een paar seconden. Tokenverzoeken direct na aanmaak kunnen falen met een 401 totdat de cache is vernieuwd. Azure RBAC-roltoewijzingen hebben tot 10 minuten nodig om te propageren.
Stap 6. Voeg het vereiste label toe aan je pod spec en deploy:
metadata:
labels:
azure.workload.identity/use: "true" # activeert de webhook
spec:
serviceAccountName: keyvault-reader
Zonder dit label injecteert de webhook niets. De pod draait wel, maar cloudauthenticatie faalt stilletjes.
AKS-kanttekeningen
- Maximaal 20 federated identity credentials per managed identity.
- Virtual nodes (Virtual Kubelet) worden niet ondersteund.
- Vereist AKS 1.22+ en Azure CLI 2.47.0+.
- Het wijzigen van de
client-id-annotatie vereist een herstart van de pod. - Minimale SDK-versies: Azure.Identity 1.9.0 (.NET), azidentity 1.3.0 (Go), azure-identity 1.9.0 (Java), @azure/identity 3.2.0 (Node.js), azure-identity 1.13.0 (Python).
Vergelijking tussen providers
| Eigenschap | EKS IRSA | EKS Pod Identity | GKE WIF | AKS Workload ID |
|---|---|---|---|---|
| Token-issuer | Kubernetes OIDC | Pod Identity Agent | GKE Metadata Server | Kubernetes OIDC |
| Cloud STS | AWS STS | Agent-endpoint | Google STS | Microsoft Entra ID |
| IAM-object | IAM Role (OIDC trust) | IAM Role (service trust) | IAM principal binding | User-assigned managed identity |
| Tokenlevensduur | 1 uur | Kortstondig (agent-beheerd) | 1 uur | 1 uur (configureerbaar 1-24u) |
| Min K8s-versie | 1.12 | 1.24 | 1.21 (GA) | 1.22 |
| Fargate-ondersteuning | Ja | Nee | N.v.t. | N.v.t. |
| Windows-ondersteuning | Ja | Nee | Ja | Ja |
| Cross-account | Handmatige role chaining | Native (targetRoleArn, 2025) |
Cross-project via Fleet WIF | Cross-tenant via federated cred |
| Verouderde voorganger | kiam, kube2iam | N.v.t. | Legacy GSA-impersonatie | AAD Pod Identity |
IRSA vs. Pod Identity: wanneer welke
Pod Identity voor nieuwe clusters. Simpelere setup, geen OIDC-providerregistratie nodig, herbruikbare trust policies over clusters heen, en native cross-account ondersteuning sinds juni 2025.
IRSA voor bestaande setups. Er is geen dwingende reden om een werkende IRSA-configuratie te migreren. IRSA is ook de enige optie voor Fargate, Windows-pods, EKS Anywhere en clusters onder Kubernetes 1.24.
Beide kunnen naast elkaar bestaan in hetzelfde cluster. Migratie is geleidelijk, niet alles-of-niets.
Beveiligingsaanbevelingen voor alle providers
Blokkeer IMDS op nodeniveau (EKS). Als de EC2 Instance Metadata Service niet is beperkt, kunnen pods de IAM-rol van de node overnemen, ongeacht de IRSA- of Pod Identity-configuratie. Stel de IMDS hop limit in op 1 of blokkeer het volledig voor non-hostNetwork pods.
Een service account per workload. Maak een apart ServiceAccount en een aparte cloudidentiteit per applicatie. Hergebruik het default service account niet. Deel geen IAM-rol tussen ongerelateerde workloads. Dit sluit aan bij het least-privilege service account-principe uit RBAC.
Scoop trust-voorwaarden strak af. Op EKS: neem altijd de :sub-conditie op in de IRSA trust policy. Op GKE: scheid onbetrouwbare clusters in verschillende projecten. Op AKS: gebruik aparte managed identities per workload.
Audit credential-uitwisselingen. AWS logt alle AssumeRoleWithWebIdentity-aanroepen in CloudTrail. GCP logt principal identifiers (inclusief namespace en SA-naam) in Cloud Audit Logs. Azure legt gefedereerde token-uitwisselingen vast in Entra sign-in logs. Stel alerts in voor onverwachte role assumptions.
Schakel automountServiceAccountToken uit op niet-API workloads. Als een pod de Kubernetes API niet nodig heeft, zet automountServiceAccountToken: false op het service account. Dit heeft geen effect op workload identity tokens (die gebruiken een apart projected volume), maar verkleint het aanvalsoppervlak als de pod gecompromitteerd wordt.
Eindresultaat verifiëren
Controleer na het doorlopen van de setup voor jouw provider dat de workload cloudresources kan benaderen:
# EKS: controleer of de pod S3-buckets kan listen
kubectl exec -n payments deploy/payment-processor -- aws s3 ls
# GKE: controleer of de pod GCS-buckets kan listen
kubectl exec -n payments deploy/payment-processor -- gcloud storage ls
# AKS: controleer of de pod een Key Vault-secret kan lezen
kubectl exec -n payments deploy/payment-processor -- \
az keyvault secret show --vault-name payments-vault --name db-password
Als het commando slaagt, werkt de workload identity-keten. De pod heeft zich geauthenticeerd bij de cloudprovider zonder statische credential.
Veelvoorkomende problemen
Pod toont An error occurred (AccessDenied) op EKS. Controleer dat de OIDC-provider gekoppeld is (aws eks describe-cluster --name <cluster> --query "cluster.identity.oidc.issuer"), de trust policy de :sub-conditie bevat met de juiste namespace en service account-naam, en de annotatie op het service account exact overeenkomt met de role ARN.
Pod krijgt 403 op GKE ondanks IAM-binding. Controleer of de nodepool --workload-metadata=GKE_METADATA heeft ingeschakeld. Zonder de GKE Metadata Server valt de pod terug op het standaard service account van de node.
AKS-pod faalt stilletjes bij authenticatie. Controleer of de pod het label azure.workload.identity/use: "true" heeft. Zonder dat label injecteert de mutating webhook het projected token niet. Controleer ook of de federated credential gepropageerd is (wacht 30 seconden na aanmaak).
Token refresh-fouten bij langlopende pods. Alle drie de providers geven tokens uit die verlopen (doorgaans na 1 uur). Standaard SDK's vernieuwen tokens automatisch door het tokenbestand opnieuw van schijf te lezen. Gebruik je een eigen HTTP-client of een oude SDK-versie, dan kan het vernieuwen niet plaatsvinden. Werk bij naar een ondersteunde SDK-versie.
Wanneer escaleren
Als workload identity niet werkt na het verifiëren van de setup, verzamel dan:
- Het exacte foutbericht en de HTTP-statuscode
- Cloudprovider: EKS, GKE of AKS, en clusterversie (
kubectl version --short) - De ServiceAccount YAML (annotaties, namespace)
- De IAM trust policy of federated credential-configuratie
kubectl describe pod <naam> -n <namespace>output (controleer op webhook-injectie of projected volume mounts)- CloudTrail, Cloud Audit Logs of Entra sign-in logs voor het geweigerde verzoek
- Of IMDS beperkt is (EKS) of de nodepool de GKE Metadata Server heeft ingeschakeld (GKE)