Kai Ole Hartwig
11 Min. Lesezeit

Grundschutz++ als Code, Teil 4: Messung als Nachweis

Ein nächtlicher Job prüft, ob jeder Hauptzweig geschützt ist. Ein anderer vergleicht die Infrastruktur mit ihrem Code. In vielen Betrieben laufen solche Jobs seit Jahren, und für ein Audit taugen sie trotzdem wenig: Ihr Ergebnis steht im Job-Log, und das ist nach 30 Tagen gelöscht. Vorgelegt wird dann eine Tabelle, die jemand von Hand gepflegt hat.

In diesem Teil geht es darum, wie die Prüfungen ihr Ergebnis selbst als Nachweis ablegen.

Teil 4 der Serie „Grundschutz++ als Code“. Die Übersicht aller Teile steht weiter unten.

01 — Was ein Prüfergebnis in OSCAL ist

Für Prüfungen hat OSCAL ein eigenes Modell, die Assessment Results. Es hält auseinander, was in einem Log ineinanderläuft:

In meinen Ergebnissen gibt es deshalb keinen Befund ohne Beobachtung und keine Beobachtung ohne Prüfgegenstand. Erst das macht aus einer Aussage einen Nachweis.

02 — Prüfungen, die schon laufen

Neue Prüfungen habe ich dafür nicht gebaut. Mich hat interessiert, welche der vorhandenen eine Anforderung aus Grundschutz++ belegen, und zwar über Wochen hinweg und nicht nur an einem Stichtag.

Welche Prüfung welche Anforderung belegt, ist eine Einschätzung. Ich habe sie deshalb als Daten neben die Prüfungen gelegt statt in den Code. Wer sie anders sieht, ändert eine Zeile und sieht im nächsten Lauf, was sich daraus ergibt.

03 — Vom Prüfbericht zum Ergebnis

Jede Prüfung schreibt einen kleinen Lauf-Datensatz: welche Anforderungen, welche Gegenstände, was sie an jedem Prüfgegenstand gesehen hat. Daraus macht results.mjs aus grundschutz-worksheets ein gültiges OSCAL-Dokument.

 

{
  "check": "protected-tags",
  "title": "Protected release tags",
  "method": "TEST",
  "start": "2026-10-01T03:00:00Z", "end": "2026-10-01T03:02:41Z",
  "catalog": { "path": "…/Grundschutz++-resolved_catalog.json", "commit": "367d775…" },
  "requirements": ["TEST.4.1"],
  "subjects": [
    { "title": "group/app", "href": "https://git.example.org/group/app",
      "satisfied": true, "detail": "v* protected, maintainers only" }
  ]
}

 

node results.mjs run.json > results.json
node validate.mjs results.json

 

Der Generator folgt drei Regeln:

04 — Was nicht geprüft wurde, muss dastehen

Heikel wird es bei dem, was eine Prüfung auslässt. Archivierte Projekte oder Repositories ohne CI haben zur Frage „Mergen nur mit grüner Pipeline“ nichts beizutragen. Ließe man sie einfach weg, sähe das Ergebnis besser aus, als es ist.

Die Zuordnung kennt deshalb drei Urteile: erfüllt, ausgenommen und nicht erfüllt. Ausgenommene Projekte tauchen nicht als Beobachtung auf. Die Beschreibung des Ergebnisses nennt sie aber mit Anzahl und Grund. Alles Übrige gilt als nicht erfüllt, auch ein Urteil, mit dem niemand gerechnet hat.

Das ist gleich am ersten Tag passiert. Eine Prüfung gab für archivierte Projekte ein eigenes Urteil aus, das in der Zuordnung fehlte, und der erste Lauf meldete prompt 45 Verstöße, die keine waren. Seitdem prüft ein Test bei jeder Änderung, ob jedes mögliche Urteil zugeordnet ist. Eine solche Lücke fällt jetzt beim Bauen auf und nicht erst im Audit.

Für Quellen außerhalb von GitLab gilt dasselbe. Ist eine Quelle noch nicht eingerichtet, fehlt sie im Ergebnis, und das Log sagt warum. Ist sie eingerichtet, lässt sich aber nicht lesen, zählt sie als nicht erfüllt. Eine Messung, die nicht stattgefunden hat, belegt nichts.

Im Kleinen genauso: Antwortet die API für ein einzelnes Projekt nicht, bekommt es das Urteil „nicht lesbar“ und gilt als nicht erfüllt. Der Bericht über alle anderen Projekte bleibt davon unberührt. Anfangs hat ein einziger Lese-Timeout noch die Nachweise sämtlicher Projekte verworfen.

05 — Das Datum gehört zum Nachweis

„Die Hauptzweige sind geschützt“ beschreibt den heutigen Tag. Ein Audit fragt nach mehr. Es will wissen, ob das in den vergangenen Monaten durchgehend so war, und darauf hat ein einzelner Bericht keine Antwort. Deshalb laufen die Prüfungen alle sechs Stunden, und jeder Lauf erzeugt ein eigenes Dokument mit Beginn und Ende.

Die Kennungen darin leiten sich aus Prüfung, Startzeit und Prüfgegenstand ab (UUID Version 5). Derselbe Lauf ergibt byte-genau dasselbe Dokument. Zwei Läufe lassen sich direkt nebeneinanderlegen, und eine Änderung zwischen ihnen springt sofort ins Auge. Nach den ersten sieben Tagen lagen je Prüfung 34 bis 38 Ergebnisse vor. Der Takt allein ergibt 28, dazu kamen Läufe von Hand und nach Änderungen an den Prüfungen.

06 — Signiert und nicht löschbar

Einen Nachweis, den der Betreiber nachträglich ändern kann, kann man sich sparen. Jedes Ergebnis landet deshalb an zwei Stellen:

oras pull registry.example.org/evidence/results:protected-tags-2026-10-01T0300Z
cosign verify --key cosign.pub registry.example.org/evidence/results@sha256:<digest>

 

Warum beides? Die Signatur verhindert, dass jemand ein Ergebnis unbemerkt verändert. Löschen kann man es trotzdem. Bei Images ist das kein Problem, die lassen sich aus dem Code neu bauen. Die Messung von gestern lässt sich nicht wiederholen.

Drei Details, bei denen man leicht danebenliegt:

07 — Die absichtlich kaputte Kontrolle

Eine Prüfung, die bisher nur grüne Läufe hatte, hat noch nicht gezeigt, dass sie Rot überhaupt erkennt. Dafür braucht es einen Gegenbeweis, und den habe ich absichtlich herbeigeführt.

Grundlage ist ein leeres Testprojekt, eingestellt wie alle anderen: Release-Tags darf nur anlegen, wer Maintainer ist. Am 30. September lief der Test so ab:

Am Ende liegen drei Dokumente vor, die sich nachträglich nicht mehr ändern lassen. Dass zwischen 20:37 und 20:59 eine Lücke bestand, steht damit fest, und die Prüfung hat sie gesehen. Darauf kommt es an.

Ganz glatt lief es übrigens nicht. Beim ersten Versuch am Vormittag hatte die Prüfung den Bruch zwar erkannt, ein Lese-Timeout bei einem anderen Projekt verwarf aber den ganzen Bericht. Daraus ist die Regel „nicht lesbar“ aus Abschnitt 04 entstanden.

08 — Drei Fehler, die lokal nicht auffielen

Alle drei steckten in den Schritten, die messen, signieren und ablegen. Keiner davon trat auf meinem Rechner auf.

Für einen Nachweis-Job heißt das: Er muss genauso laut scheitern wie eine Prüfung, die etwas findet. Ein stiller Abbruch sieht im Dashboard aus wie ein ruhiger Tag.

09 — Was ein Ergebnis nicht sagt

Wie aus Messungen, Komponentendefinitionen und dieser Bewertung ein Sicherheitsplan wird, zeigt Teil 5.

10 — Die Serie im Überblick

  1. Grundschutz++ gegen die eigene Dokumentation: die Methode, der Katalog als Datenmodell, der Abgleich mit IaC und GitOps.
  2. Die Anwendbarkeit als Datensatz: die Anwendbarkeitserklärung als OSCAL-Profil.
  3. Container, die sagen, welche Anforderungen sie erfüllen: eine signierte Komponentendefinition an jedem Image, das die Pipeline baut.
  4. Messung als Nachweis: Prüfungen schreiben ihre Ergebnisse als OSCAL, datiert, signiert, nicht löschbar. Dieser Beitrag.
  5. Das ISMS als Build-Produkt: Konzept, Prüfplan, Ergebnis und Maßnahmenplan als OSCAL-Kette, bei jeder Messung neu gebaut.
  6. Was kein Repository weiß: die zweite Ebene, das laufende System gegen seinen Code.
  7. Ein Nachweis, viele Standards: NIS2, DORA, C5 und SOC 2 als Mappings auf Grundschutz++.
  8. Die Kette zum Mitnehmen: allgemeine Checks, der Bericht über einen Zeitraum und eine Vorlage, die alles zusammenschaltet.

Die Teile 1 bis 6 beschreiben, was in meinem ISMS läuft. Sie erscheinen erst, wenn der Schritt im Betrieb läuft und gemessen ist. Die Teile 7 und 8 zeigen Werkzeuge, die ich nach dem Feedback beim InfoSec-Stammtisch gebaut habe und selbst nicht einsetze. Der Code liegt in grundschutz-worksheets. Eine Karte der ganzen Serie zeigt OSCAL in der Praxis: acht Modelle, eine Kette.

Häufige Fragen

Warum OSCAL und nicht einfach JSON-Berichte?+

Weil ein Werkzeug die Ergebnisse lesen können muss, ohne meine Skripte zu kennen. Assessment Results verknüpfen Befund, Beobachtung und Anforderung in einer Form, die jedes OSCAL-Werkzeug versteht. Der Sicherheitsplan aus Teil 5 baut genau darauf auf.

Reicht nicht der Audit-Log von GitLab?+

Er sagt, wer wann eine Einstellung geändert hat. Er sagt nicht, ob alle Projekte zu einem Zeitpunkt wie verlangt eingestellt waren. Das beantwortet erst eine Prüfung über alle Projekte.

Warum alle sechs Stunden?+

Oft genug, damit eine Lücke nicht einen ganzen Tag unbemerkt bleibt. Selten genug, dass die Ergebnisse überschaubar bleiben. Der Takt ist eine Einstellung, keine Eigenschaft des Verfahrens.

Geht das ohne Registry und Object Lock?+

Ja. results.mjs schreibt eine normale Datei. Signatur und Sperre machen sie zum belastbaren Nachweis. Ohne sie muss man der Ablage vertrauen.

Fazit

Die Prüfungen gab es schon vorher. Neu ist, dass ihr Ergebnis bleibt: als datiertes OSCAL-Dokument, signiert und in einer Kopie, die niemand löschen kann. Die eigentliche Arbeit lag weniger im Format als in zwei Entscheidungen, nämlich was als erfüllt zählt und was nicht geprüft wurde. Beide liegen als Daten neben dem Code, und ein Test sorgt dafür, dass keine Lücke unbemerkt bleibt.

Weiter mit Teil 5: Das ISMS als Build-Produkt.

Ich mache aus deinen vorhandenen Prüfungen Nachweise. Datiert, signiert, 400 Tage gesperrt.

Zuordnung zu Grundschutz++ als Daten, Ergebnisse als OSCAL, Ablage als signiertes Artefakt mit gesperrter Kopie und ein Gegenbeweis, der zeigt, dass Rot auch rot wird.

Plattform-Betrieb statt Beratung auf Papier: Auf Wunsch baue ich die nächsten Schritte gleich mit, bis zum Sicherheitsplan.

Termin buchen →

Über den Autor

Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freiberuflicher DevSecOps-Berater · OnlyOle Consulting

Programmiert seit 2002 – autodidaktisch gelernt, 2012 mit KO-Web selbständig gemacht. Über 100 Projekte, Fokus auf Security, Performance, Automatisierung und Qualität. Heute freiberuflich: DevSecOps-Beratung, Schulungen und Softwareentwicklung.