Lückenlos sicher entwickeln mit DevSecOps

Seite 2: Auf der Baustelle

Inhaltsverzeichnis

Die nächste Station auf der Reise des Codes ist der Build-Prozess, bei dem unter anderem aus dem Sourcecode ein lauffähiges Artefakt entsteht. Das ist eine gute Station für weitere Prüfungen auf dem Code, um die Qualität zu sichern. Zunächst lässt sich die Codebasis mit diversen Tools einer Sicherheitsanalyse unterziehen. Die Werkzeuge decken die Bereiche von der statischen Analyse des Quellcodes bis zu ausgefeilten Fuzzing-Methoden ab.

Nicht zu unterschätzen ist der Berg von Abhängigkeiten. Nur wenige Anwendungen nutzen ausschließlich die Standardbibliothek ihrer Programmiersprache. Entsprechende Dependencies innerhalb des Ökosystems werden stattdessen für Paketmanager wie npm, Maven oder pip im Projekt deklariert und während des Build-Vorgangs heruntergeladen. Damit gleicht bei vielen aktuellen Frameworks die vollständige Codebasis einem Eisberg: Der eigene und selbst verwaltete Code ist nur dessen kleine Spitze über der Wasseroberfläche, während sich der Großteil der gesamten Codebasis in den Abhängigkeiten versteckt. Der Trend zu Cloud und Containern hat die Tendenz verstärkt, da die Nutzung der Dienste nicht mehr manuell, sondern ebenfalls codebasiert erfolgt. Dieser Teil ist für Angreifer besonders interessant, da erfolgreiche Attacken auch jenseits der eigentlichen Anwendung Zugriff finden.

Die deklarative Form ermöglicht beim Überprüfen der Abhängigkeiten weitere Maßnahmen. Durch die Beschreibung, die beispielsweise im XML- oder JSON-Format vorliegt, kann eine automatische Prüfung der externen Dependencies im Abgleich mit einer Liste bekannter Schwachstellen erfolgen. Dazu sind mehrere Scanner erhältlich, die beispielsweise die Maven-Abhängigkeiten prüfen und beim Erkennen schwerer Sicherheitslücken die Pipeline sofort stoppen. Dass die meisten Tools nicht Open Source beziehungsweise kostenfrei, sondern kommerziell sind, ist verständlich. Schließlich ist damit neben der eigentlichen Scannersoftware ein nicht unerheblicher Aufwand bei der manuellen Pflege der Datenbank von Schwachstellen verbunden. Populäre Beispiele hierbei sind Snyk und Aqua im kommerziellen Bereich sowie clair für Docker Images als Open Source Tool.

Beim Patching ist es wichtig, mit der Automatisierung auf halber Strecke stehen zu bleiben. Nur wenn das gefährdete Artefakt ausgetauscht wird, kann ein sicherer Zustand wiederhergestellt werden (Abb. 2).

Während die Prüftechniken die Sicherheitslage durch mehr Transparenz verbessern, bleibt eine Herausforderung bestehen: Die als unsicher erkannten Dependencies durch gefixte Versionen auszutauschen. Die zeitraubende und aufwendige manuelle Arbeit haben Teams bis vor einigen Jahren häufig an Junior-Entwicklerinnen oder Praktikanten delegiert. Inzwischen haben sich einige Tools wie Dependabot und Renovate etabliert, die den finalen Schritt des Updatezyklus automatisieren. Passende Updates erhalten Entwicklerinnen und Entwickler auf eine für sie gewohnte Art, beispielsweise per Pull Request. Auf die Weise fügen sie sich in den regulären Workflow ein. Die Deklaration von Code spielt damit ihre Stärke aus.

Nachdem das Build-System ein Artefakt möglichst ohne Schwachstellen erzeugt hat, muss es in einer Form bereitgestellt werden, in der Enduser etwas damit anfangen können. Dabei lauern erneut potenzielle Schwachstellen und unsichere Zustände. Da Build- und Ausführungsumgebung häufig nicht identisch sind, sollte zunächst eine automatische Überprüfung sicherstellen, dass ein valides Artefakt vorhanden ist. Dafür lässt es sich beim Build- und Analyseprozess digital signieren. Später prüft die Ausführungsumgebung vor dem Start bei der sogenannten Binary Attestation, ob alle erforderlichen Unterschriften vorhanden sind. Auf diese Weise lässt sich ein Binary von mehreren unabhängigen Instanzen testen und als valide kennzeichnen.

Grundsätzlich sollte gelten, dass nur erfolgreich geprüfte Artefakte ausgeführt werden dürfen. Das ermöglicht eine technische Bedingung, ob die eingesetzte Software sowohl eigenen als auch regulatorischen Vorgaben genügt. Die Prüfung ermöglicht oft den Verzicht auf umfangreiche Checklisten, die bei jedem Release manuell zu prüfen sind. Allerdings ist Vorsicht geboten: Technische Regularien sind oft bewusst schwammig definiert, um sie nicht ständig anpassen zu müssen. Für eine automatische Prüfung reicht aber beispielsweise eine Definition als "Stand der Technik" nicht aus. Sie benötigt Regeln, die konkret und maschinenlesbar deklariert sind.

Häufig ist das Secrets-Management eine weitere Herausforderung beim Deployment. Das gilt zunächst für die Zugangsdaten, um die Bereitstellung zu autorisieren. Teams müssen beim Design der CI / CD-Pipeline (Continuous Integration / Continuous Delivery) den Fokus auf die Sicherheit setzen. Schließlich soll nicht zentral etwas vorhanden sein, was Schlüssel zu allen Umgebungen bereithält und nach einem kompromittierenden Angriff Zugang zu allen Systemen frei Haus bereitstellt. Als erster Schritt bietet sich die Trennung von Zugängen auf der Ebene der Anwendungen oder Teams an. Eine Alternative ist das agentenbasierte Deployment: Ein Agent läuft in der Zielumgebung und erhält über die IAM-Mechanismen (Identity and Access Management) des Zielsystems die Berechtigung, es von innen zu bestücken. Das Vorgehen vermeidet eine allzu große Konzentration der Zugangsdaten an einer Stelle der Landschaft.

Nach der erfolgreichen Bereitstellung steht für die Anwendung ein sicherer Betrieb im Fokus. Als einer der ersten Schritte bietet sich an, die verwendeten Artefakte nicht nur beim Build auf bekannte Schwachstellen zu prüfen, sondern die Analyse regelmäßig zu wiederholen. Auf diese Weise können Unternehmen auf später bekannt gewordene Schwachstellen reagieren.

Ein weiterer Punkt ist die Kontrolle der laufenden Software, für die als Minimalanforderung alle Regeln der Kunst des klassischen Betriebs gelten. Die Automatisierung ermöglicht weitergehende Schritte. Über Policy-basierte Systeme wie den Open Policy Agent lässt sich sicherstellen, dass Anwendungen von vorneherein nur eine Untermenge der Rechte in der Laufzeitumgebung erhalten. Darüber hinaus lassen sich zusätzliche Maßnahmen wie die durchgehende Verschlüsselung aller Datenspeicher erzwingen.

Als letzter Punkt gilt, dass man immer mit Fehlern rechnen sollte und auf sie vorbereitet sein muss. Sinnvoll sind Übungen, um Abläufe für den Notfall zu proben. Dazu gehört regelmäßig zu prüfen, ob alle im Team wissen, wo im Krisenfall der Treffpunkt ist. Daneben muss sichergestellt sein, dass alle Zugänge zu den Systemen vorhanden sind. Zum einen spart die Vorsorge im Ernstfall viel Zeit und zum anderen geben regelmäßig geübte Vorgänge allen Beteiligten Sicherheit beim Eintreten einer unbekannten Situation.