Ein kompromittierter Runner trifft eine Maschine. Ein kompromittierter Runner-Pool trifft jedes Team, das sich diesen Pool teilt.
Zwei Abgrenzungen vorab
Zum Self-hosted-Runner-Thema gibt es auf diesem Blog bereits zwei Artikel, und dieser hier wiederholt sie nicht. „Runner-Sicherheit: Warum Self-hosted Runner ein eigenes Risiko sind“ (09.07.2026, digital-business.blog, 09.07.2026) behandelt die einzelne Maschine: Fork-PRs aus öffentlichen Repos, Caches und Zugangsdaten, die zwischen Jobs liegen bleiben, den Runner als privilegierten Host. „Ephemere Runner: warum persistente CI-Maschinen die Isolation kaputtmachen“ (12.08.2026, muellermh.blog, 12.08.2026) behandelt den Zustand, der auf einer langlebigen Maschine überlebt, und das --ephemeral-Flag als Gegenmittel.
Beide Artikel fragen: Was passiert auf einem Runner. Dieser Artikel fragt etwas anderes: Was passiert, wenn mehrere Teams denselben Pool von Runnern nutzen und ein einziger kompromittierter Job plötzlich Zugriff auf alles hat, was dieser Pool bedient.
Was eine Runner Group technisch regelt
GitHub Actions ordnet jeden self-hosted Runner einer Runner Group zu. Beim Anlegen einer Gruppe legst du eine Policy fest, die bestimmt, welche Repositories Zugriff auf die Runner dieser Gruppe haben; auf Enterprise-Ebene kann eine solche Organisations-Gruppe zusätzlich von einem Enterprise geteilt werden. Eine Gruppe kann auf eine feste Liste von Repositories beschränkt werden oder für alle Repositories einer Organisation offen sein. Jede Organisation hat genau eine Default-Gruppe, und ein Runner, der ohne explizite Gruppenangabe registriert wird, landet automatisch dort (zur Frage, warum eine einzelne Maschine in dieser Default-Gruppe ohnehin riskant ist, siehe den Artikel vom 09.07.).
Scoping ist also kein Zusatzfeature, sondern die einzige Stelle, an der du festlegst, wer einen Pool überhaupt erreichen kann.
Warum ein geteilter Pool den Blast Radius vervielfacht
Ein einzelner Runner, der kompromittiert wird, gefährdet die Secrets und die Netzwerkreichweite eines Jobs. Ein kompromittierter Pool gefährdet jeden Job, der diesen Pool in den nächsten Minuten zugewiesen bekommt, über Repo- und Teamgrenzen hinweg. Teilen sich fünf Teams eine Runner Group, weil das Infrastruktur-Team Kapazität sparen wollte, reicht ein einziger erfolgreicher Angriff auf eine der fünf Pipelines, um lateral auf die Jobs der anderen vier zuzugreifen: dieselbe Maschine, derselbe Prozessraum, oft dieselben eingehängten Caches. Der Angriff muss die Policy des Pools nicht einmal brechen, er nutzt sie.
Beispielausschnitt: enge statt weite Zuweisung
Eine zu weite Policy sieht in der Praxis so aus, mit einer einzigen Gruppe für alles:
# .github/workflows/build.yml, mehrere Repos, eine Grupperuns-on: group: shared-runners labels: self-hosted-linux
Granulares Scoping trennt Gruppen entlang der Vertrauensgrenze, zum Beispiel nach Team oder Sensitivität der Secrets:
# Repo im Team "payments", eigene Gruppe statt Shared-Poolruns-on: group: payments-prod-runners labels: self-hosted-linux
Die zugehörige Gruppen-Policy lässt in diesem Fall nur die Repositories des Payments-Teams zu, nicht die gesamte Organisation. Der Unterschied steht nicht im Workflow, sondern in der Repository-Policy der Gruppe selbst.
Granulare Gruppen statt eines Shared-Pools
Die Begrenzung des Blast Radius ist eine Zuschnittsfrage: Wie viele Gruppen legst du an, und nach welchem Kriterium trennst du sie? Sinnvolle Trennlinien sind Vertraulichkeitsstufe der Secrets, Team- oder Produktgrenze und Umgebung (Produktion gegen alles andere). Je feiner der Zuschnitt, desto kleiner der Kreis an Repos, der im Kompromissfall betroffen ist, aber desto mehr Pools musst du pflegen und auslasten. Dieser Kompromiss lässt sich nicht pauschal entscheiden, er hängt an der Frage, welche Repos zusammen vertrauenswürdig sind und welche nicht.
Eine pool-weite Kompromittierung erkennen
Ein Vorfall auf einem einzelnen Runner zeigt sich in einem auffälligen Job. Ein Vorfall auf einem Pool zeigt sich erst im Muster über mehrere Repos: mehrere unabhängige Workflows aus verschiedenen Repositories, die im selben Zeitfenster ungewöhnliche Netzwerkziele ansprechen, oder ein Secret, das plötzlich aus einem Job heraus verwendet wird, dessen Repository es gar nicht besitzt. Wer einen Pool betreibt, sollte deshalb nicht nur pro Repo, sondern pro Pool auswerten: welche Repositories ihn in einem Zeitraum genutzt haben und ob sich Auffälligkeiten über diese Liste hinweg wiederholen, statt isoliert in einem einzelnen Workflow-Lauf.
Was das für deinen Zuschnitt bedeutet
Ein Shared-Pool ist bequem, solange nichts passiert. Sobald etwas passiert, haftet jeder Mitnutzer für den Fehler jedes anderen. Die Frage ist deshalb nicht, ob eine Runner Group existiert, sondern wie eng ihre Policy tatsächlich gezogen ist und ob diese Grenze mit der Vertrauensgrenze deiner Teams übereinstimmt.
Das Leistungsspektrum ist gestaffelt und baut auf Delivery-Transparenz auf. Es läuft über drei Felder: Implementation (Delivery- und Nachweiskontrollen in die Pipeline einziehen), AI Governance (Nachvollziehbarkeit dort schaffen, wo KI-gestützte Schritte in Build und Deployment Freigaben und Verantwortung verwischen) und Maintenance (die Übergabefrage: wem ein System nach dem Go-Live gehört und woran man merkt, dass es niemandem gehört). Ein festes Angebot daraus entsteht erst, wenn klar ist, was du wirklich brauchst. Kontakt: mm@mhm-dl.de.
Über das Anmeldeformular für den Newsletter trägst du deine E-Mail-Adresse ein, kreuzt die Einwilligung an und bestätigst die Anmeldung danach per Mail. Mit der Anmeldung willigst du ein, dass der Newsletter unter anderem folgende Themen behandelt: Schulungen zu Docker, Kubernetes, CI/CD, Git-Workflows und DevSecOps-Werkzeugen sowie die Anforderungen aus NIS2, CRA und DORA und deren technische Umsetzung.
Kommentar verfassen