Leitfaden
Workload Identity Federation: Schluss mit API-Keys – von MCP-Chatbots über RAG bis zur ganz normalen Enterprise-App
Statische Secrets sind das größte vermeidbare Risiko in modernen Architekturen. Workload Identity Federation ersetzt API-Keys und Service-Account-Dateien durch kurzlebige, föderierte Tokens – und das funktioniert nicht nur in der Cloud, sondern auch für KI-Chatbots mit MCP, RAG-Pipelines und klassische Anwendungen. Eine praxisnahe Anleitung.
Workload Identity Federation: Schluss mit API-Keys – von MCP-Chatbots über RAG bis zur ganz normalen Enterprise-App
TL;DR: Jeder API-Key, jede Service-Account-Datei und jeder Connection-String mit Passwort ist ein Secret, das geleakt, vergessen und nie rotiert wird. Workload Identity Federation (WIF) dreht das Modell um: Die Anwendung beweist, wer sie ist – mit einem kurzlebigen Token ihrer Laufzeitumgebung – und tauscht diesen Beweis gegen temporäre Zugriffsrechte. Kein gespeichertes Geheimnis, nichts zu rotieren, nichts zu leaken. Das funktioniert heute für Kubernetes-Workloads, CI/CD-Pipelines, MCP-Server hinter KI-Chatbots und RAG-Ingestion-Pipelines gleichermaßen. Der Artikel zeigt die Mechanik und drei konkrete Umsetzungen.
Das Problem: Secrets, die niemand rotiert
Die typische Enterprise-Anwendung im Jahr 2026 hat erstaunlich viele Geheimnisse:
- Den Datenbank-Connection-String mit Benutzername und Passwort
- Den API-Key für den Object Storage
- Die Service-Account-JSON-Datei für die Cloud-Anbindung
- Den Client-Secret der App-Registrierung fürs SSO
- Und seit neuestem: API-Keys für LLM-Provider, Vektordatenbanken und ein halbes Dutzend MCP-Server
Jedes dieser Secrets ist ein statischer Wert, der irgendwo liegt – in einer .env-Datei, einem Kubernetes-Secret, einer CI/CD-Variable, im schlimmsten Fall im Git-Repository. Und jedes davon hat dieselben strukturellen Probleme:
- Es altert nicht. Ein geleakter API-Key von 2023 funktioniert 2026 noch genauso gut, wenn ihn niemand rotiert hat. Und niemand rotiert ihn.
- Es ist kopierbar. Wer das Secret einmal gesehen hat – in einem Log, einem Stacktrace, einem Screenshot – kann es von überall verwenden.
- Es ist anonym. Der API-Key sagt nicht, wer ihn gerade benutzt. Im Audit-Log steht „Service Account X”, nicht „der kompromittierte Build-Agent”.
GitGuardian zählte 2024 über 23 Millionen geleakte Secrets allein in öffentlichen GitHub-Repositories – ein Plus von 25 % gegenüber dem Vorjahr. Und mit dem KI-Boom kommt eine neue Welle dazu: LLM-API-Keys und MCP-Server-Konfigurationen mit eingebetteten Credentials sind die neuen config.php-Dateien.
Die übliche Antwort lautet „Secret Manager” – Vault, Azure Key Vault, AWS Secrets Manager. Das ist besser als .env-Dateien, löst aber das Henne-Ei-Problem nicht: Womit authentifiziert sich die Anwendung gegenüber dem Secret Manager? Mit noch einem Secret? Das Problem wird verschoben, nicht gelöst.
Die Idee: Identität beweisen statt Geheimnis vorzeigen
Workload Identity Federation löst das Henne-Ei-Problem an der Wurzel. Die Kernbeobachtung: Die Laufzeitumgebung weiß bereits, wer die Anwendung ist.
Kubernetes weiß, welcher Pod unter welchem Service Account läuft. Azure weiß, welche VM gerade Code ausführt. GitHub weiß, welcher Workflow in welchem Repository auf welchem Branch gestartet wurde. Diese Plattformen können das auch kryptographisch bezeugen – in Form eines kurzlebigen, signierten OIDC-Tokens (ein JWT), das die Plattform selbst ausstellt.
Der Trick ist nun ein Vertrauensverhältnis: Der Ziel-Identity-Provider (Entra ID, Google Cloud, AWS IAM, Keycloak) wird so konfiguriert, dass er Tokens eines fremden Ausstellers akzeptiert – unter präzisen Bedingungen. Der Ablauf, standardisiert als OAuth 2.0 Token Exchange (RFC 8693):
- Die Workload bekommt von ihrer Plattform ein kurzlebiges Identitäts-Token (z. B. ein projiziertes Service-Account-Token in Kubernetes, Lebensdauer: Minuten bis wenige Stunden).
- Sie schickt dieses Token an den Security Token Service (STS) des Ziel-Providers.
- Der STS validiert Signatur, Aussteller (
iss), Zielgruppe (aud) und Subjekt (sub) gegen die hinterlegte Vertrauenskonfiguration. - Passt alles, gibt der STS ein kurzlebiges Access-Token für die Zielressource zurück – typischerweise eine Stunde gültig.
Das Ergebnis: Es existiert kein einziges statisches Secret mehr. Nichts liegt auf der Platte, nichts steht in der CI/CD-Variable, nichts kann aus einem Backup gestohlen werden. Ein abgefangenes Token ist nach 60 Minuten wertlos, und im Audit-Log steht exakt, welche Workload-Identität wann was getan hat.
Alle großen Plattformen sprechen dieses Modell, nur unter verschiedenen Namen:
| Plattform | Name | Mechanik |
|---|---|---|
| Azure | Entra Workload ID / Federated Credentials | OIDC-Token gegen Entra-Token tauschen |
| Google Cloud | Workload Identity Federation | Workload Identity Pools + Provider |
| AWS | IRSA / EKS Pod Identity / Roles Anywhere | OIDC- bzw. X.509-basierte Role Assumption |
| Kubernetes | Projected Service Account Tokens | Eingebauter OIDC-Issuer pro Cluster |
| On-Premises | SPIFFE/SPIRE, Keycloak Token Exchange | Eigene Workload-Identitäten + RFC 8693 |
Die Konzepte sind überall identisch – wer es einmal verstanden hat, kann es auf jeder Plattform anwenden. Die folgenden drei Anwendungsfälle zeigen es konkret, mit Azure als Beispielplattform (in DACH-Unternehmen schlicht am häufigsten anzutreffen).
Anwendungsfall 1: KI-Chatbot mit MCP-Servern
Das Model Context Protocol hat ein bekanntes Deployment-Muster etabliert: Ein Chat-Frontend (Open WebUI, LibreChat, ein Custom-Bot) spricht mit einem LLM, und das LLM ruft über MCP-Server Tools auf – Ticketsystem, CRM, Dokumentenablage, interne APIs.
Und genau hier entsteht gerade in vielen Unternehmen ein Secret-Albtraum: Jeder MCP-Server bekommt in seiner Konfiguration die API-Keys für seine Downstream-Systeme mitgegeben. Eine mcp.json mit fünf Servern enthält schnell fünf langlebige Credentials – und der MCP-Server für den Object Storage läuft dann mit einem Storage-Key, der nie abläuft.
Das ist doppelt gefährlich, weil MCP-Server hinter einem LLM stehen: Eine erfolgreiche Prompt Injection (siehe meinen Artikel zum Thema) macht aus jedem überprivilegierten MCP-Server ein Exfiltrationswerkzeug. Die Formel von Wiz gilt hier wörtlich: Risiko = Autonomie × Zugang.
Mit Workload Identity Federation sieht die Architektur anders aus. Der MCP-Server läuft als Kubernetes-Deployment mit einem eigenen Service Account – und der ist über eine Federated Credential mit einer Entra-Identität verknüpft:
# 1. User-assigned Managed Identity anlegen
az identity create --name mcp-storage-server --resource-group rg-ai
# 2. Federated Credential: Vertraue dem K8s-Service-Account
az identity federated-credential create \
--name mcp-storage-server-fc \
--identity-name mcp-storage-server \
--resource-group rg-ai \
--issuer "$(az aks show -n my-cluster -g rg-ai --query oidcIssuerProfile.issuerUrl -o tsv)" \
--subject "system:serviceaccount:ai-tools:mcp-storage-server" \
--audiences "api://AzureADTokenExchange"
# 3. Nur die nötige Rolle zuweisen – Lesezugriff, ein Container, fertig
az role assignment create \
--assignee-object-id "$(az identity show -n mcp-storage-server -g rg-ai --query principalId -o tsv)" \
--role "Storage Blob Data Reader" \
--scope "/subscriptions/.../containers/dokumente"
Im Kubernetes-Manifest genügen ein Label und eine Annotation:
apiVersion: v1
kind: ServiceAccount
metadata:
name: mcp-storage-server
namespace: ai-tools
annotations:
azure.workload.identity/client-id: "<client-id-der-managed-identity>"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-storage-server
spec:
template:
metadata:
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: mcp-storage-server
containers:
- name: server
image: registry.internal/mcp-storage-server:1.4
Und im Code des MCP-Servers? Kein Secret. Keine Umgebungsvariable mit Key. Eine Zeile:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# Findet das projizierte K8s-Token automatisch und tauscht es bei Entra ID
credential = DefaultAzureCredential()
blob_client = BlobServiceClient(
account_url="https://firmenspeicher.blob.core.windows.net",
credential=credential,
)
Der Webhook von Entra Workload ID mountet das projizierte Service-Account-Token in den Pod, DefaultAzureCredential erkennt das, tauscht es beim Entra-STS gegen ein einstündiges Access-Token und erneuert es automatisch. Token-Rotation ist kein Betriebsthema mehr – sie passiert einfach.
Workload-Identität ≠ Nutzer-Identität
Ein wichtiger Punkt, der in MCP-Architekturen gerne verwischt wird: Die Workload-Identität sagt, was der MCP-Server prinzipiell darf. Sie sagt nicht, was der Nutzer darf, der gerade mit dem Chatbot spricht.
Wer dem MCP-Server pauschal Leserechte auf alle Dokumente gibt, hat einen Chatbot gebaut, der jedem Praktikanten die Gehaltslisten zusammenfasst. Die saubere Lösung ist zweistufig:
- Workload Identity Federation für die Maschinenidentität des MCP-Servers (kein statisches Secret, minimale Grundrechte)
- User-Delegation obendrauf: Das Chat-Frontend authentifiziert den Nutzer per SSO, und der MCP-Server agiert per OAuth On-Behalf-Of-Flow mit den Rechten des Nutzers weiter. Die MCP-Spezifikation sieht seit der 2025er-Auth-Überarbeitung genau dafür OAuth 2.1 vor.
Die Faustregel: Die Workload-Identität öffnet die Tür zum System, die Nutzer-Identität entscheidet, welche Daten herauskommen.
Anwendungsfall 2: RAG-Pipeline und Enterprise Search
Eine RAG-basierte Suchmaschine (die Architektur dazu im Detail hier) hat mindestens drei Workloads mit ganz unterschiedlichen Zugriffsmustern:
- Die Ingestion-Pipeline – liest Fileserver und SharePoint, schreibt in die Vektordatenbank
- Der Retrieval-Service – liest die Vektordatenbank, sonst nichts
- Der LLM-Orchestrator – ruft Retrieval-Service und LLM-Endpunkt auf
Der klassische Fehler: Alle drei teilen sich einen Service-Account mit einem dicken Berechtigungsbündel, weil das beim Aufsetzen am schnellsten ging. Damit kann der Retrieval-Service theoretisch den SharePoint leerlesen und die Ingestion-Pipeline den LLM-Endpunkt befeuern – Rechte, die niemand braucht, aber jeder Angreifer dankend nimmt.
Mit Workload Identity Federation bekommt jede Stufe ihre eigene Identität mit exakt den nötigen Rechten:
ingestion-pipeline → Graph API: Sites.Read.All (Application Permission)
→ Storage: Blob Data Reader auf den Quell-Container
→ Vektordatenbank: Schreibrechte auf den Index
retrieval-service → Vektordatenbank: Leserechte auf den Index
→ sonst: nichts
llm-orchestrator → Azure OpenAI: Cognitive Services User
→ Retrieval-Service: internes mTLS/JWT
→ sonst: nichts
Das ist nicht nur Least Privilege im Lehrbuchsinn – es macht auch das Audit-Log endlich aussagekräftig. Wenn nachts um drei jemand 40.000 Dokumente aus dem SharePoint zieht, steht im Log nicht „svc-rag-prod”, sondern die konkrete Workload-Identität der Ingestion-Pipeline. Läuft der Abzug aber unter der Identität des Retrieval-Service, ist sofort klar: Hier stimmt etwas nicht, denn diese Identität hat gar keine SharePoint-Rechte. Anomalien werden strukturell sichtbar.
Ein Detail verdient besondere Aufmerksamkeit: Die Ingestion-Pipeline läuft oft nicht im Kubernetes-Cluster, sondern als geplanter Job – etwa in GitHub Actions, einer Azure DevOps Pipeline oder einem Airflow-Worker. Auch dafür gibt es Federation. GitHub Actions etwa stellt jedem Workflow-Lauf ein OIDC-Token aus, dem Entra ID vertrauen kann:
# .github/workflows/ingest.yml
permissions:
id-token: write # erlaubt dem Workflow, ein OIDC-Token anzufordern
contents: read
jobs:
ingest:
runs-on: ubuntu-latest
steps:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }} # keine Secrets –
tenant-id: ${{ vars.AZURE_TENANT_ID }} # nur öffentliche IDs
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- run: python ingest.py # DefaultAzureCredential greift, fertig
Die Federated Credential auf Azure-Seite vertraut dabei exakt repo:firma/rag-pipeline:ref:refs/heads/main – ein Fork oder ein Feature-Branch bekommt kein Token. Der Unterschied zum alten Modell ist fundamental: Früher lag ein Cloud-Credential mit weitreichenden Rechten als Repository-Secret herum, das jeder mit Schreibzugriff auf den Workflow exfiltrieren konnte. Jetzt liegt dort: nichts.
Anwendungsfall 3: Die ganz normale Enterprise-Applikation
Kein LLM, kein MCP, kein RAG – einfach eine interne Web-Anwendung mit einer Datenbank dahinter. Auch hier (gerade hier!) lohnt sich das Modell, denn der Datenbank-Connection-String mit Passwort ist das vermutlich am häufigsten geleakte Secret der Unternehmensgeschichte.
Alle drei großen Clouds können Datenbank-Logins inzwischen direkt an Workload-Identitäten knüpfen:
- Azure: SQL Database und PostgreSQL Flexible Server akzeptieren Entra-Tokens als Passwort-Ersatz
- AWS: RDS IAM Database Authentication generiert 15-Minuten-Tokens für PostgreSQL/MySQL
- Google Cloud: Cloud SQL IAM Authentication, analog
Für eine .NET-Anwendung auf AKS mit Azure-PostgreSQL sieht das so aus:
// Kein Passwort im Connection-String – das Token kommt zur Laufzeit
var credential = new DefaultAzureCredential();
var token = await credential.GetTokenAsync(
new TokenRequestContext(["https://ossrdbms-aad.database.windows.net/.default"]));
var connString = $"Host=db.postgres.database.azure.com;" +
$"Database=appdb;Username=app-identity;Password={token.Token};" +
$"SslMode=Require";
In der Praxis übernimmt das ein Connection-Pooler oder die Framework-Integration (Npgsql hat dafür einen UsePeriodicPasswordProvider, der Tokens automatisch erneuert). Das Ergebnis: Die Anwendung hat kein Datenbank-Passwort mehr – nicht in der Config, nicht im Key Vault, nirgends. Es existiert schlicht keines.
Dasselbe Muster gilt für alles andere, was die App braucht: Der Zugriff auf den Key Vault (für Secrets von Drittsystemen, die noch keine Federation können), auf den Storage, auf die Message Queue – alles über dieselbe eine Workload-Identität, alles ohne gespeicherte Credentials.
Und on-premises?
Workload Identity Federation ist kein Cloud-Exklusivfeature. Wer self-hosted unterwegs ist, hat zwei solide Wege:
- Kubernetes als Token-Aussteller: Jeder Cluster (auch RKE2, k3s, OpenShift im eigenen Rechenzentrum) hat einen eingebauten OIDC-Issuer. Solange der Ziel-IdP die Issuer-URL erreichen kann (oder die Signaturschlüssel als JWKS hinterlegt bekommt), funktioniert Federation gegen Entra ID, Keycloak oder Vault genauso wie aus der Cloud.
- SPIFFE/SPIRE für heterogene Landschaften: SPIRE attestiert Workloads (VMs, Container, Bare Metal) anhand von Eigenschaften wie Node, Pfad und Prozess und stellt ihnen kurzlebige Identitäten als X.509-SVIDs oder JWTs aus – die sich dann wiederum per RFC 8693 bei Keycloak oder Vault eintauschen lassen. Das ist auch die Grundlage für Zero-Trust-Architekturen mit mTLS zwischen Services.
Keycloak verdient hier eine besondere Erwähnung: Token Exchange ist seit Version 26.2 ein offiziell unterstütztes Feature. Ein on-premises Keycloak kann damit dieselbe Rolle spielen wie der Entra-STS – Kubernetes-Tokens entgegennehmen und gegen Tokens für interne APIs tauschen.
Die Stolpersteine aus der Praxis
So elegant das Modell ist – ein paar Dinge gehen regelmäßig schief:
Zu breite Subject-Bedingungen. Die Vertrauenskonfiguration entscheidet über alles. Wer bei GitHub Actions repo:firma/* statt eines konkreten Repos und Branches einträgt, hat jedem Repository der Organisation Cloud-Zugriff gegeben – inklusive des Test-Repos, in dem externe Dienstleister arbeiten. Subjects immer so eng wie möglich fassen: konkretes Repo, konkreter Branch oder Environment, konkreter Namespace und Service Account.
Audience nicht geprüft. Das aud-Claim ist der Schutz davor, dass ein für Dienst A ausgestelltes Token bei Dienst B eingelöst wird. Wer eigene Token-Exchange-Endpunkte baut (etwa mit Keycloak), muss die Audience-Validierung explizit konfigurieren – das ist der Unterschied zwischen Federation und einem Generalschlüssel.
Lokale Entwicklung vergessen. Auf dem Entwickler-Laptop gibt es kein projiziertes Kubernetes-Token. Die Credential-Ketten der SDKs (DefaultAzureCredential und Pendants) lösen das sauber: lokal greift die CLI-Anmeldung des Entwicklers (az login), im Cluster die Workload Identity – derselbe Code, ohne if (dev)-Verrenkungen. Das gehört von Anfang an getestet, nicht erst beim ersten Deployment.
Token-Lebensdauer und Caching. Access-Tokens leben typischerweise eine Stunde. Wer pro Request ein neues Token anfordert, baut sich ein Rate-Limit-Problem beim STS; wer Tokens ewig cached, bekommt 401er nach Ablauf. Die SDKs cachen und erneuern korrekt – Eigenbau-HTTP-Clients mit manuell verwalteten Tokens sind die häufigste Fehlerquelle.
Der Rest-Bestand an echten Secrets. Nicht alles kann föderiert werden – der SaaS-Anbieter, der nur statische API-Keys kennt, wird nicht verschwinden. Diese Rest-Secrets gehören in den Key Vault, und der Zugriff darauf läuft über Workload Identity. So schrumpft das Secret-Inventar auf das unvermeidbare Minimum, und jedes verbleibende Secret hat einen klaren Besitzer und ein Rotations-Datum.
Fazit: Erst die Identität, dann die Features
Workload Identity Federation ist keine exotische Spezialtechnik mehr, sondern der Stand der Technik für Maschinen-Authentifizierung – von allen großen Plattformen unterstützt, von den SDKs transparent wegabstrahiert, on-premises genauso machbar wie in der Cloud.
Gerade bei KI-Projekten lohnt es sich, die Reihenfolge ernst zu nehmen: Ein Chatbot mit MCP-Anbindung und ein RAG-Index über Unternehmensdokumente konzentrieren enorm viel Zugriff an einer Stelle – hinter einem LLM, das per Prompt Injection manipulierbar bleibt. Wer dort mit statischen God-Mode-Keys arbeitet, baut die Exfiltrations-Infrastruktur gleich mit. Wer dagegen jede Workload mit einer eigenen, föderierten, kurzlebigen Identität ausstattet, bekommt Least Privilege, automatische Rotation und ein aussagekräftiges Audit-Log geschenkt.
Die pragmatische Migrationsreihenfolge für den Bestand:
- CI/CD zuerst – Cloud-Credentials aus den Pipeline-Secrets entfernen, OIDC-Federation aktivieren. Geringster Aufwand, größter Sicherheitsgewinn.
- Neue Workloads nur noch föderiert – jede neue App, jeder neue MCP-Server startet ohne statische Cloud-Secrets.
- Datenbank-Passwörter ablösen – IAM-/Entra-Authentifizierung für die Datenbanken aktivieren, App für App.
- Rest-Secrets inventarisieren – was übrig bleibt, kommt in den Key Vault, mit Besitzer und Ablaufdatum.
Der beste Umgang mit einem Secret ist, gar keines zu haben.