GitHub Actions OIDC statt long-lived Secrets
Federated Identity zu AWS, GCP und K8s.
von PlatPrep
In alten Pipelines war es normal: ein langer, niemals ablaufender AWS-Access-Key als GitHub Secret. Der Key existierte seit drei Jahren, hatte weitreichende Permissions, und wenn jemand aus dem Team ging, fiel niemandem sofort ein, ihn zu rotieren.
Das ist das Problem. Die Lösung ist OIDC.
OpenID Connect erlaubt es GitHub Actions, sich gegenüber AWS ohne statische Credentials zu authentifizieren. GitHub stellt für jeden Workflow-Run ein kurzlebiges, signiertes JWT aus. AWS prüft die Signatur gegen GitHubs OIDC-Endpoint und tauscht das Token per sts:AssumeRoleWithWebIdentity gegen temporäre Credentials für eine IAM-Rolle. Es gibt nichts mehr zu stehlen, das länger als ein paar Minuten gültig wäre — und nichts mehr zu rotieren.
Die Trust Policy ist der Sicherheitshebel
Auf AWS-Seite registrierst du einmalig token.actions.githubusercontent.com als OIDC Identity Provider und legst pro Einsatzzweck eine IAM-Rolle an. Die gesamte Sicherheit steckt in der Trust Policy — konkret in den Conditions auf den Token-Claims:
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:org/repo:ref:refs/heads/main"
}
}
}
Der sub-Claim kodiert, woher das Token stammt: Repository plus Kontext. repo:org/repo:ref:refs/heads/main heißt: nur Workflows, die auf dem main-Branch dieses einen Repos laufen. Nutzt der Workflow GitHub Environments, sieht der Claim stattdessen so aus: repo:org/repo:environment:production — die robustere Variante, weil dann zusätzlich die Protection Rules des Environments greifen (Required Reviewers, Branch-Einschränkungen), bevor überhaupt ein Token mit diesem Claim entsteht.
Hier passieren auch die typischen Fehler. Ein StringLike mit repo:org/*:* bedeutet: jedes Repository der Organisation — inklusive des Spielwiesen-Repos, in dem jeder Mitarbeiter Workflows ändern darf — kann die Deploy-Rolle übernehmen. Und wer die aud-Condition weglässt, akzeptiert Tokens, die für andere Zwecke ausgestellt wurden. Die Faustregel: Eine Trust Policy pro Rolle, so eng wie irgend möglich, und Wildcards nur mit explizitem Grund.
Auf der GitHub-Seite ist es dann kurz:
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-prod
aws-region: eu-central-1
id-token: write ist die Berechtigung, das OIDC-Token überhaupt anzufordern — ohne sie schlägt der Schritt mit einer wenig hilfreichen Fehlermeldung fehl, was erfahrungsgemäß die erste halbe Stunde jeder OIDC-Einführung kostet.
Die zweite halbe Stunde kostet meist ein Not authorized to perform sts:AssumeRoleWithWebIdentity. Die Fehlermeldung verrät nicht, welche Condition nicht passt. Fast immer ist es ein Mismatch im sub-Claim: Der Workflow läuft mit einem Environment, die Trust Policy erwartet aber das ref-Format — oder umgekehrt. Es lohnt sich, das erwartete Claim-Format einmal explizit nachzuschlagen, statt es zu raten: Pull-Request-Workflows haben repo:org/repo:pull_request, Tag-Builds ref:refs/tags/v1.2.3, Environment-Deployments das Environment-Format. Wer Reusable Workflows zentral pflegt, kann statt auf sub auch auf den job_workflow_ref-Claim einschränken — dann zählt, welcher Workflow läuft, nicht aus welchem Repo er aufgerufen wurde.
Rollen schneiden statt Generalschlüssel
Der eigentliche Gewinn von OIDC zeigt sich erst beim Rollen-Design. Mit statischen Keys hatte praktisch jede Organisation am Ende einen CI-Key mit zu vielen Rechten, weil Key-Anlegen und -Verteilen mühsam war. Mit OIDC ist eine zusätzliche Rolle nur ein weiteres Stück Terraform: Der Deploy-Workflow bekommt Schreibrechte auf ECS und das Artefakt-Bucket, der nächtliche Audit-Workflow eine Read-only-Rolle, der PR-Build vielleicht gar keine AWS-Rechte. Jede Rolle mit eigener, enger Trust Policy. Kompromittiert ein Angreifer einen PR-Workflow, erbeutet er die Rechte dieses Workflows — nicht die Schlüssel zum Konto.
Eine Restwahrheit gehört dazu: OIDC verschiebt das Vertrauen von “wer kennt den Key” zu “wer kann Workflows auf geschützten Branches ändern”. Branch Protection und Reviews auf Workflow-Dateien sind damit Teil der Sicherheitsarchitektur, nicht nur Hygiene. Wer Workflows aus Forks mit pull_request_target laufen lässt, sollte besonders genau hinsehen.
Das Muster ist nicht AWS-spezifisch. Bei GCP heißt es Workload Identity Federation mit Attribute-Conditions statt Trust Policy, Azure bindet OIDC an Service Principals mit Federated Credentials. Auch Vault und Kubernetes-Cluster selbst können GitHub als OIDC-Issuer akzeptieren — der Workflow authentifiziert sich dann direkt gegen den Cluster, ohne hinterlegtes Kubeconfig. Und es ist dasselbe Prinzip, mit dem Pods in EKS an IAM-Rollen kommen — nachzulesen unter EKS: IRSA und Node Pools. Einmal verstanden, taucht Federation überall auf.
Wer noch statische Cloud-Keys in Pipelines verwendet, hat ein Sicherheitsrisiko — egal wie diszipliniert rotiert wird. Die Migration ist pro Repository in wenigen Stunden erledigt und gehört zu den Maßnahmen mit dem besten Verhältnis von Aufwand zu Sicherheitsgewinn. Mehr zu CI/CD-Architektur und Build-Sicherheit gibt es im Lernpfad CI/CD und Builds.