Zurück zum Blog
7 min

Schluss mit Service-Account-Schlüsseln: Workload Identity Federation auf GCP 2026

Langlebige Service-Account-Schlüssel sind ein Sicherheitsvorfall, der nur auf seinen Moment wartet. Ein praxisnaher Leitfaden für 2026 zu Workload Identity Federation auf GCP: wie der schlüssellose Token-Austausch funktioniert, GitHub Actions ohne Secrets, die attribute_condition-Falle und die Migration ohne Ausfallzeit.

Teil vonSecurity →
workload-identity-federationservice-account-schluesselgcpcloud-securitygithub-actionsiamgoogle-clouddevsecops
Inhalt

Jede GCP-Sicherheitsgeschichte beginnt mit derselben Szene. Eine Datei sa-key.json liegt in einer CI-Variable, einer angepinnten Slack-Nachricht und seit 2023 in irgendjemandes ~/Downloads. Sie hat eine Eigenschaft, die dir Angst machen sollte: Sie läuft nie ab. Wer diese Datei besitzt, ist dein Service-Account — mit allen Rollen, die du ihm je gegeben hast — bis sich jemand daran erinnert, sie zu rotieren. Niemand erinnert sich.

Langlebige Service-Account-Schlüssel sind der mit Abstand häufigste Weg, wie ein Google-Cloud-Projekt vollständig kompromittiert wird. Kein raffinierter Exploit — eine geleakte JSON-Datei. 2026 brauchst du sie für fast nichts mehr, und dies ist der Praxis-Leitfaden, um sie loszuwerden: wie der schlüssellose Austausch tatsächlich funktioniert, wie du GitHub Actions ohne Secrets verdrahtest, die eine Konfigurationszeile, die über Sicherheit oder Katastrophe entscheidet, und wie du migrierst, ohne eine einzige Pipeline zu zerbrechen.

Schluss mit Service-Account-Schlüsseln — Workload Identity Federation auf Google Cloud.

Warum ein langlebiger Schlüssel 2026 ein Risiko ist

Ein Service-Account-Schlüssel ist ein statisches Credential mit drei fatalen Eigenschaften:

  • Er läuft nie ab. Ein Passwort hat eine Rotationsrichtlinie; ein Schlüssel keine. Er ist gültig, bis er manuell widerrufen wird.
  • Er wandert. JSON lässt sich kopieren und einfügen. Er landet in der Git-Historie, in CI-Logs, auf Laptops und in Screenshots — jedes davon ein neuer Ort, an dem er leaken kann.
  • Er verbirgt, wer ihn genutzt hat. Audit-Logs zeigen den Service-Account handeln, nie den Menschen oder die Maschine, die den Schlüssel vorgelegt hat. Nach einem Leak kannst du Angreifer-Traffic nicht von legitimem unterscheiden.

Ein Schlüssel in einem öffentlichen Repo bedeutet vollen Zugriff auf alles, was dieser Account erreichen kann — oft mehr, als sich jemand daran erinnert, vergeben zu haben. Die Lösung heißt nicht „häufiger rotieren“. Sie heißt: den Schlüssel gar nicht erst existieren lassen.

Was Workload Identity Federation wirklich ist

Hier die Übersetzung aus dem Doku-Deutsch. Dein externes System besitzt bereits eine Identität, die es beweisen kann: GitHub Actions stellt jedem Workflow-Lauf ein signiertes OIDC-Token aus, AWS signiert seine Instanz-Identität, eine On-Premises-Maschine kann jeden OIDC-Provider betreiben. Workload Identity Federation bringt Google Cloud bei, diesem Token zu vertrauen und es gegen ein kurzlebiges GCP-Zugriffstoken zu tauschen. Es wird kein Schlüssel erzeugt. Kein Secret verlässt Google. Nichts Statisches existiert, das leaken könnte.

Drei Bausteine erledigen die Arbeit:

  • Workload Identity Pool — eine Vertrauensgrenze, die eine oder mehrere externe Identitätsquellen enthält.
  • Provider — der konkrete Aussteller, dem du vertraust (GitHubs OIDC-Endpunkt, AWS, eine OIDC-URL), plus die Art, wie seine Claims gelesen werden.
  • Attribute Mapping + Condition — wie die Felder des externen Tokens (repository, repository_owner, sub) auf Google-Attribute gemappt werden und welche davon überhaupt tauschen dürfen.

Der Ablauf von Anfang bis Ende:

So funktioniert ein schlüsselloses Login: Dein Workload legt ein OIDC-Token vor, Pool und Provider prüfen die Claims, Google STS tauscht es gegen ein kurzlebiges Token, und dein Service-Account wird impersoniert — es wird nie ein Schlüssel erzeugt.

Der externe Workload legt sein OIDC-Token vor, der Provider validiert und mappt die Claims, Googles Security Token Service (STS) gibt ein kurzlebiges Token zurück, und dieses Token impersoniert einen Service-Account, der auf genau die Rollen beschränkt ist, die du vergeben hast. Wenn der Job endet, stirbt das Token. Es gibt nichts zu rotieren, weil es nichts zu speichern gibt.

Praxis: GitHub Actions zu GCP ganz ohne Schlüssel

Der häufigste Wunsch ist ein Deployment aus GitHub ohne ein GCP_SA_KEY-Secret. Hier das komplette Setup.

Zuerst Pool und einen GitHub-Provider erstellen:

Terminal window
# Ein Pool pro Vertrauensgrenze (z. B. gesamte CI)
gcloud iam workload-identity-pools create github-pool \
--location=global \
--display-name="GitHub Actions"
# Ein Provider, der GitHubs OIDC-Aussteller vertraut
gcloud iam workload-identity-pools providers create-oidc github-provider \
--location=global \
--workload-identity-pool=github-pool \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
--attribute-condition="assertion.repository_owner == 'deine-org'"

Dieses letzte Flag ist das entscheidende. Merke es dir — wir kommen im nächsten Abschnitt darauf zurück, denn es falsch zu setzen ist genau der Weg, wie Leute ihr Projekt an Fremde verschenken.

Als Nächstes einem bestimmten Repo erlauben, einen Deploy-Service-Account zu impersonieren:

Terminal window
PROJECT_NUMBER=$(gcloud projects describe my-project --format='value(projectNumber)')
gcloud iam service-accounts add-iam-policy-binding \
deployer@my-project.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/deine-org/my-app"

Zuletzt der Workflow — beachte, dass nirgends ein Schlüssel steht:

permissions:
contents: read
id-token: write # erlaubt dem Runner, ein OIDC-Token anzufordern
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: auth
uses: google-github-actions/auth@v2
with:
project_id: my-project
workload_identity_provider: projects/${{ env.PROJECT_NUMBER }}/locations/global/workloadIdentityPools/github-pool/providers/github-provider
service_account: deployer@my-project.iam.gserviceaccount.com
- run: gcloud run deploy my-app --source .

Kein Secret zum Leaken, kein Schlüssel zum Rotieren. Der Runner beweist, wer er ist, Google gibt ein Token zurück, das in Minuten abläuft, und das Deployment läuft.

Die Falle, in die alle tappen: attribute_condition

Das ist der Teil, den die Quickstarts überspringen, und der Grund, diesen Artikel zu lesen.

Wenn du den Provider erstellst, entscheidet die attribute_condition, welche externen Identitäten überhaupt ein Token tauschen dürfen. Lässt du sie weg, hast du Google gesagt, dem gesamten Aussteller zu vertrauen. Bei GitHub ist der Aussteller token.actions.githubusercontent.com — der Tokens für jedes öffentliche Repository der Welt signiert. Jeder Fremde kann einen Workflow forken, ein Token anfordern und deinen Service-Account impersonieren.

Gefahr versus sicher: Ohne attribute_condition kann jedes GitHub-Repo deine Identität annehmen; mit assertion.repository_owner auf deine Organisation gesperrt können nur deine Repos ein Token tauschen.

Die gefährliche Variante — ohne Condition:

Terminal window
# GEFAHR: vertraut jedem Repo, für das GitHub je ein Token signiert
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub"
# (keine --attribute-condition)

Die sichere Variante — auf deine Organisation gesperrt, dann auf dem Binding auf ein Repo eingegrenzt:

Terminal window
# SICHER: nur Tokens aus Repos, die du besitzt, dürfen überhaupt tauschen
--attribute-condition="assertion.repository_owner == 'deine-org'"

Zwei unabhängige Schranken schützen dich: Die Condition auf dem Provider entscheidet, wer ein Token tauschen darf, und der principalSet auf dem IAM-Binding entscheidet, wer davon einen bestimmten Service-Account impersonieren darf. Setze beide. Ein Provider ohne Condition ist die Nummer-eins-Fehlkonfiguration bei Workload Identity Federation — und genau das, wonach ein Angreifer scannt.

Migration von bestehenden Schlüsseln ohne Ausfallzeit

Du kannst keine Schlüssel löschen, die du nicht siehst. Beginne mit einer Inventur über alle Service-Accounts:

Terminal window
for sa in $(gcloud iam service-accounts list --format='value(email)'); do
gcloud iam service-accounts keys list --iam-account="$sa" \
--managed-by=user --format="table(name, validAfterTime)"
done

--managed-by=user ist wichtig: Es filtert die von Google verwalteten Schlüssel heraus (die in Ordnung sind und sich selbst rotieren), sodass du nur die selbst erstellten siehst, die du tatsächlich abschaffen musst.

Migriere dann einen Workload nach dem anderen, niemals alles auf einmal:

  1. Federation parallel aufbauen. Erstelle Pool, Provider und Binding. Der alte Schlüssel funktioniert weiter — noch ist nichts kaputt.
  2. Eine Pipeline umstellen auf schlüssellose Authentifizierung und prüfen, dass sie deployt.
  3. Deaktivieren, nicht löschen. Beobachte die Audit-Logs auf alles, was ihn noch nutzt:
Terminal window
gcloud logging read \
'protoPayload.authenticationInfo.principalEmail="deployer@my-project.iam.gserviceaccount.com"
AND protoPayload.metadata.@type:"ServiceAccountKey"' \
--freshness=7d --limit=20
  1. Löschen, wenn es ruhig ist. Wenn den Schlüssel einen ganzen Zyklus lang nichts genutzt hat, entferne ihn.

Deaktivieren-vor-Löschen gibt dir ein kostenloses Rollback: Falls etwas Vergessenes den Schlüssel doch noch braucht, aktivierst du ihn in Sekunden wieder, statt einen Produktionsausfall zu bekämpfen.

Schlüssel unwiederbringlich machen

Schlüssel zu entfernen ist wertlos, wenn nächsten Sprint jemand einen neuen erstellt. Schließe die Tür auf Organisationsebene:

Terminal window
gcloud resource-manager org-policies enable-enforce \
iam.disableServiceAccountKeyCreation \
--organization=YOUR_ORG_ID

Mit aktivierter Policy schlägt gcloud iam service-accounts keys create für alle fehl. Kombiniere sie mit einer Benachrichtigung auf das Audit-Event CreateServiceAccountKey, sodass jeder Versuch — etwa eine angefragte Policy-Ausnahme — sichtbar statt stillschweigend ist. Jetzt ist „keine Schlüssel“ ein erzwungener Zustand, keine Hoffnung.

Wenn schlüssellos noch nicht geht

Ehrlichkeit hält das Ganze glaubwürdig: Federation deckt nicht alles ab. Ein Legacy-SDK ohne OIDC-Unterstützung, eine Vendor-Integration, die nur eine Schlüsseldatei akzeptiert, ein Air-Gap-System, das Googles STS nicht erreichen kann — das gibt es weiterhin. Minimiere für diese Fälle stattdessen den Schaden:

  • Beschränke den Service-Account des Schlüssels auf die absolut geringsten Rechte, mit denen er die Aufgabe erfüllen kann.
  • Rotiere nach einem kurzen, automatisierten Zeitplan — ein Schlüssel, den du behalten musst, ist ein Schlüssel, den du ablaufen lassen musst.
  • Speichere ihn im Secret Manager, niemals in einem Repo, einer CI-Variable oder einem geteilten Laufwerk.

Ein Schlüssel, den du behalten musst, sollte die seltene, dokumentierte Ausnahme sein — nicht der Standard, den du nie hinterfragt hast.

Die Feldregel

Behandle jeden langlebigen Service-Account-Schlüssel als einen Sicherheitsvorfall, der noch nicht passiert ist. Ersetze ihn durch Workload Identity Federation: ein externes OIDC-Token, getauscht gegen ein kurzlebiges GCP-Token, ohne dass je ein Secret gespeichert wird. Setze immer eine attribute_condition — ohne sie kann jedes Repo deine Identität tragen. Migriere einen Workload nach dem anderen mit Deaktivieren-vor-Löschen und erzwinge dann disableServiceAccountKeyCreation, damit Schlüssel nie wiederkehren. Mach das richtig, und die gefährlichste Datei in deiner Infrastruktur hört einfach auf zu existieren.

Die Feldregel: schlüssellos werden und schlüssellos bleiben auf Google Cloud.

Wenn du eine GCP-Umgebung härtest — oder dieselbe schlüssellose Migration selbst durcharbeitest — melde dich. Ich teile, was ich baue und absichere, unter #GoogleCloud, #CloudSecurity und #GoogleCloudAmbassador.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Workload Identity Federation und GKE Workload Identity?

Beide lösen dasselbe Problem — keine Schlüssel — an zwei verschiedenen Stellen. Workload Identity Federation lässt ein externes System (GitHub Actions, AWS, on-premises, jeden OIDC-Provider) sein eigenes Token gegen ein kurzlebiges GCP-Token tauschen. GKE Workload Identity ist die Variante im Cluster: Sie bindet einen Kubernetes-Service-Account an einen Google-Service-Account, sodass Pods ohne eingebundenen Schlüssel Anmeldedaten erhalten. Nutze Federation für alles außerhalb von GCP und GKE Workload Identity für Pods innerhalb eines Clusters.

Ist Workload Identity Federation auf Google Cloud kostenlos?

Ja. Workload Identity Pools, Provider und der Token-Austausch selbst verursachen keine zusätzlichen Kosten — du zahlst nur für die GCP-Ressourcen, die dein Workload tatsächlich aufruft. Es gibt keinen Grund, weiter das Sicherheitsrisiko langlebiger Schlüssel zu tragen, wenn der schlüssellose Weg kostenlos ist.

Wie sichere ich Workload Identity Federation gegen Token-Missbrauch ab?

Setze immer eine attribute_condition auf dem Provider. Ohne sie kann jede Identität des externen Ausstellers — bei GitHub bedeutet das jedes öffentliche Repository — ein Token für dein Projekt anfordern. Sperre sie auf deine eigene Organisation oder dein Repo mit einer Bedingung wie assertion.repository_owner == 'deine-org', mappe nur die benötigten Claims und gib dem impersonierten Service-Account die geringstmöglichen Rechte.

Kann ich ohne Ausfallzeit von Service-Account-Schlüsseln migrieren?

Ja. Betreibe Federation zunächst parallel: Richte Pool und Provider ein, stelle einen Workflow auf schlüssellose Authentifizierung um und prüfe, dass er funktioniert, während der alte Schlüssel noch existiert. Deaktiviere den Schlüssel dann (lösche ihn noch nicht) und beobachte die Audit-Logs auf verbleibende Nutzung. Sobald ihn einen ganzen Zyklus lang nichts mehr aufruft, lösche ihn und blockiere neue Schlüssel mit der Org-Policy, damit er nie wiederkehren kann.

War dieser Artikel hilfreich?

ENDE