Start / Seminare / GitHub Actions in der Praxis
Modul
GitHub Actions sicher betreiben
4 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
GitHub Actions sicher betreiben
0:00 Ein Workflow führt Code aus, der Zugriff auf Ihre Geheimnisse hat, in Ihr Repository schreiben kann und in Ihre Produktion ausrollt. Er verdient damit dieselbe Sorgfalt wie die Anwendung selbst — und bekommt sie in der Praxis selten. Dieses Modul behandelt die drei Angriffsflächen, die im Alltag zählen: Eingaben von außen, die zu ausgeführtem Code werden; fremde Actions, die Sie einbinden; und selbst betriebene Runner, auf denen Rückstände liegenbleiben.
0:25 Am Ende bauen Sie eine dieser Lücken absichtlich ein — denn eine Schwachstelle, die man einmal ausgelöst hat, vergisst man nicht mehr.
GitHub Actions sicher betreiben
0:33 Drittes Modul des dritten Tages. Wir gehen von innen nach außen: erst der eigene Workflow-Code und die Script Injection, dann die fremden Actions und ihre Referenzierung, zuletzt die Runner. Alle drei Themen haben denselben Kern — es geht darum, wem und was Sie in Ihrer Pipeline vertrauen, und ob dieses Vertrauen begründet ist.
Workflows als Produktionscode behandeln
0:53 Fangen wir beim eigenen Code an. Eine Angriffsfläche entsteht dort, wo Werte von außen in Ihren Workflow fließen — und das sind mehr, als man zunächst denkt. Script Injection entsteht durch einen Mechanismus, den man kennen muss: Ein Ausdruck in einem Kommando wird vor dem Ausführen textuell ersetzt. Die Shell sieht also nicht einen Wert, sondern zusammengesetzten Code.
1:15 Wer den Titel eines Pull Requests kontrolliert, kontrolliert damit die Kommandozeile — und Pull Requests kann bei einem öffentlichen Repository jeder öffnen. Das gilt genauso für Branchnamen, Kommentare, Issue-Texte und alles andere, was aus dem Ereignis kommt. Es ist derselbe Fehler wie SQL-Injection, nur an einer Stelle, an der ihn kaum jemand sucht.
1:36 Zwei Varianten, ein Unterschied — und der ist fundamental. Oben wird der Wert in das Kommando hineingeschrieben, bevor die Shell es sieht; ein Titel mit den richtigen Sonderzeichen wird damit zu einem zusätzlichen Befehl. Unten geht derselbe Wert über eine Umgebungsvariable, und die Shell behandelt ihn als Daten. Der Wert wird nie Teil des Codes.
1:56 Diese Umstellung kostet zwei Zeilen und schließt die Lücke vollständig. Noch besser ist der Weg über eine Action, die den Wert als Eingabe entgegennimmt — dort stellt sich die Frage gar nicht. Vier Regeln, die zusammen den Alltag abdecken. Werte aus Ereignissen gehen über Umgebungsvariablen oder als Eingaben an eine Action — nie direkt ins Kommando.
2:16 Geheimnisse gehören nicht auf die Kommandozeile, weil sie dort in Prozesslisten sichtbar werden. Änderungen an Workflow-Dateien brauchen ein Review wie Produktionscode, und dafür sollte im Team klar sein, wer sie liest. Und die vierte Regel ist die bequemste: Code Scanning findet gefährliche Muster auch in Workflow-Dateien — Sie müssen also nicht allein danach suchen.
2:38 Der erste Punkt zeigt die Reichweite: Nicht nur Titel, auch Branchnamen können Sonderzeichen enthalten, und die kommen in einem Fork von jemandem, den Sie nicht kennen. Der zweite ist eine falsche Sicherheit — geprüft wird ein Wert, der schon eingesetzt wurde; zu diesem Zeitpunkt ist es zu spät. Der dritte ist der Auslöser aus Modul drei, der im Kontext des Zielrepositories läuft; in Verbindung mit fremdem Code ist er die gefährlichste Kombination überhaupt.
3:03 Und der vierte ist ein Prozessproblem: Die Workflow-Änderung reist in einem großen Pull Request mit und wird mit durchgewinkt.
Drittanbieter-Actions beherrschen
3:10 Jetzt zu dem, was Sie einbinden. Jede fremde Action ist Code, der in Ihrem Job läuft — und die Art, wie Sie sie referenzieren, entscheidet, ob Sie wissen, welcher. Sie können eine Action über einen Branch, ein Tag oder einen vollständigen Commit referenzieren. Und GitHubs Sicherheitsempfehlung ist an dieser Stelle ungewöhnlich deutlich: Die Festlegung auf einen vollständigen Commit ist gegenwärtig die einzige Möglichkeit, eine Action als unveränderliche Version zu verwenden.
3:38 Der Grund ist simpel: Ein Tag ist nur ein Zeiger, und der Autor kann ihn jederzeit verschieben. Wenn Sie also auf Version drei zeigen, zeigen Sie auf das, was der Autor heute unter Version drei versteht — nicht auf das, was Sie geprüft haben. Von oben nach unten nimmt die Kontrolle ab. Der Commit ist unveränderlich, kostet Sie aber die Pflege — Sie müssen Aktualisierungen selbst nachziehen, und dafür gibt es Dependabot.
4:02 Das Tag ist der übliche Kompromiss und angemessen bei Actions, deren Herausgeber Sie kennen und denen Sie vertrauen. Der Branch ist keine Referenz, sondern ein bewegliches Ziel — dort sollte nichts stehen, was Zugriff auf Ihre Geheimnisse hat. Und die unterste Zeile ist der oft übersehene Sonderfall: Eine Action aus dem eigenen Repository verlagert die Frage nur, sie beantwortet sie nicht.
4:26 Fünf Schritte, und der zweite wird am häufigsten ausgelassen. Herkunft prüfen ist naheliegend. Umfang prüfen heißt: Welche Rechte und welchen Netzzugang braucht diese Action wirklich — und passt das zu dem, was sie tun soll? Eine Action zum Formatieren von Code sollte nicht ins Internet telefonieren. Dann auf den Commit festlegen, und zwar mit der Versionsnummer als Kommentar daneben, sonst weiß in drei Monaten niemand mehr, welcher Stand das ist.
4:52 Dependabot übernimmt die Aktualisierung. Und organisationsweit lässt sich zusätzlich begrenzen, was überhaupt erlaubt ist. Der erste Punkt beschreibt die Lieferkettenangriffe der letzten Jahre in einem Satz. Der zweite ist die Kehrseite der Festlegung, und sie wird unterschätzt: Wer pinnt und nie aktualisiert, sitzt irgendwann auf einer Action mit bekannter Schwachstelle — Unveränderlichkeit ohne Pflege ist auch keine Lösung.
5:17 Der dritte ist eine ungenutzte Möglichkeit, denn viele Organisationen könnten die erlaubten Actions einschränken und tun es nicht. Und der vierte macht die Automatisierung wirkungslos: Ein Aktualisierungs-Pull-Request, der ungelesen zusammengeführt wird, ist genau das, wovor wir uns schützen wollten.
Runner-Risiken begrenzen
5:33 Zum Schluss die Maschine selbst. Bei gehosteten Runnern nimmt GitHub Ihnen die Frage ab. Bei eigenen nicht — und das ist der Kern des Risikos. Ein selbst gehosteter Runner ist eine Maschine, die dauerhaft läuft und Jobs entgegennimmt. Der entscheidende Unterschied zu gehosteten Runnern: Sie beginnt nicht bei jedem Job frisch.
5:54 Was ein Job zurücklässt — Dateien, Prozesse, zwischengespeicherte Zugangsdaten —, findet der nächste vor. Deshalb rät GitHub ausdrücklich davon ab, sie in öffentlichen Repositories zu verwenden. Denn dort kann jeder einen Pull Request öffnen, und ein Pull Request führt Code aus. Auf Ihrer Maschine, in Ihrem Netz. Die Tabelle stellt die beiden Betriebsarten gegenüber, und die zweite Zeile enthält den Sicherheitsunterschied: Rückstände bleiben liegen oder verschwinden.
6:23 Kurzlebige Runner registrieren sich für genau einen Job und werden danach verworfen — damit haben Sie die Eigenschaft zurückgewonnen, die gehostete Runner von Haus aus mitbringen. Der Preis ist etwas Startzeit je Job. Für sensible Workloads ist das eine leichte Entscheidung. In Modul fünfzehn sehen wir uns an, wie sich das mit dem Actions Runner Controller in Kubernetes automatisch umsetzen lässt.
6:45 Der erste Punkt ist der häufigste Entwurfsfehler: Der Runner steht im Produktionsnetz, weil er dort einmal etwas erreichen musste — und kann seitdem Systeme sehen, die kein Build je braucht. Der zweite ist die direkte Folge fehlender Kurzlebigkeit. Der dritte entsteht aus einer alten Installation, die Administratorrechte verlangte, und bleibt dann so.
7:05 Und der vierte ist eine organisatorische Lücke: Ohne Runner Groups darf jedes Repository der Organisation auf dieser Maschine Code ausführen — auch das Repository, das gestern jemand neu angelegt hat.
Übung
7:17 In der Übung bauen Sie eine echte Lücke ein und schließen sie wieder. Das klingt ungewöhnlich für ein Sicherheitsmodul — und ist der wirksamste Weg, es nicht zu vergessen. Der Kern dieser Aufgabe ist der Nachweis. Es genügt nicht, die sichere Variante zu schreiben; Sie sollen die unsichere einmal ausgelöst haben. Ein präparierter Pull-Request-Titel, eine zusätzliche Ausgabe im Log — mehr braucht es nicht, und niemand nimmt Schaden.
7:42 Danach stellen Sie den Schritt um und wiederholen den Versuch, der dann folgenlos bleibt. Der zweite Teil ist Routinearbeit mit Wirkung: alle fremden Actions auf Commits festlegen und Dependabot einrichten, damit die Festlegung nicht zur Altlast wird. Die Schritte eins bis drei sind der Nachweis-Zyklus: bauen, auslösen, absichern, erneut auslösen.
8:03 Nehmen Sie sich für Schritt zwei Zeit — es ist lehrreich zu sehen, wie wenig es braucht. Schritt vier ist die Fleißarbeit mit den Commits; denken Sie an den Versionskommentar daneben. Und Schritt fünf schließt den Kreis, denn ohne Dependabot wird aus der Festlegung ein eingefrorener Stand mit bekannten Schwachstellen. Beides zusammen ergibt erst den Schutz, einzeln ist jedes nur eine halbe Maßnahme.
8:27 Der erste Punkt ist der, der die Übung entwertet: Die Lücke wird beschrieben, aber nie ausgelöst — und bleibt damit abstrakt. Der zweite ist die Nachlässigkeit danach: Der verwundbare Schritt bleibt im Repository stehen, weil die Übung ja vorbei ist. Der dritte macht die Pflege unmöglich, weil ohne Versionskommentar niemand erkennt, welcher Stand gepinnt ist.
8:47 Und der vierte ist der, den man in echten Projekten ständig sieht: Dependabot läuft, produziert brav Pull Requests, und die stapeln sich ungelesen. Im nächsten Modul geht es um die Herkunft der Artefakte selbst.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →