Ein Scanner wie tfsec oder checkov prüft deine Terraform-Konfiguration gegen einen festen Katalog bekannter Fehlmuster: offene Security Groups, unverschlüsselte Volumes, fehlende Logging-Konfiguration. Das deckt einen großen Teil der üblichen Fehlkonfigurationen ab, stößt aber an eine klare Grenze: Regeln, die nur für deine Organisation gelten, kennt kein Scanner-Katalog. „S3-Buckets dürfen nur in der Region eu-central-1 liegen“ oder „Instanztyp m5.24xlarge ist verboten“ sind keine allgemeingültigen Sicherheitsregeln, sondern organisationsspezifische Vorgaben. Dafür brauchst du eine eigene Regelsprache statt eines fixen Regelkatalogs.
Genau das leistet die Kombination aus Open Policy Agent (OPA) und Conftest: Du schreibst eigene Policies in der Sprache Rego und prüfst damit den Terraform-Plan, bevor er angewendet wird.
Wie der Mechanismus funktioniert
Rego ist die deklarative Policy-Sprache von OPA. Eine Rego-Datei besteht aus einer Package-Deklaration und einer oder mehreren Regeln, die über strukturierte Daten wie JSON auswerten, ob eine Bedingung zutrifft. Conftest nutzt diese Regeln, um beliebige strukturierte Konfigurationsdateien zu testen, darunter auch das JSON-Format, das Terraform für einen Plan erzeugt.
Der Ablauf besteht aus drei Schritten. Zuerst erzeugst du einen Terraform-Plan und speicherst ihn in einer Datei:
terraform plan -out=plan.tfplan
Anschließend wandelst du diese Plandatei in ihre JSON-Repräsentation um. Laut Terraform-Dokumentation zeigt terraform show -json „a JSON representation of the plan, configuration, and current state“:
terraform show -json plan.tfplan > plan.json
Diese JSON-Struktur enthält unter anderem das Array resource_changes, in dem jeder Eintrag Felder wie type (Ressourcentyp), address und change.after (die geplanten Attributwerte nach der Änderung) trägt. Gegen genau diese Struktur schreibst du deine Rego-Policy, zum Beispiel um einen verbotenen Instanztyp zu blockieren:
package mainimport rego.v1deny contains msg if { some rc in input.resource_changes rc.type == "aws_instance" rc.change.after.instance_type == "m5.24xlarge" msg = sprintf("%s: instance_type m5.24xlarge ist nicht erlaubt", [rc.address])}
Conftest legt seine Policies standardmäßig im Ordner policy/ ab und testet eine Datei damit über:
conftest test plan.json
Findet Conftest eine deny-Regel, deren Bedingungen zutreffen, meldet es die zurückgegebene Nachricht als Fehler und beendet sich mit einem von null verschiedenen Exit-Code. Neben deny unterstützt Conftest auch warn für Regeln, die nicht blockieren sollen, und violation für ein strukturiertes Fehlerformat.
Abgrenzung zu bestehenden Artikeln
Der Artikel Infrastructure as Code absichern: die typischen Terraform-Fehlkonfigurationen beschreibt feste tfsec- und checkov-Regeln gegen bekannte Fehlmuster. Hier geht es um selbstdefinierte Rego-Policies gegen den terraform plan-Output, eine eigene Regelsprache statt eines fixen Scanner-Katalogs.
Der Artikel Admission Control im Cluster: Kyverno und Policy Controller praktisch behandelt Policy-Durchsetzung zur Kubernetes-Laufzeit im Cluster. OPA und Conftest prüfen dagegen den Terraform-Plan vor dem Apply, das ist eine Vorab-Kontrolle statt Laufzeit-Durchsetzung.
Grenzen von Policy as Code mit OPA und Conftest
Rego hat eine eigene Auswertungslogik und eine eigene Syntax, die sich von imperativen Sprachen unterscheidet. Bis eine Regel wie oben selbstständig geschrieben werden kann, braucht es Einarbeitung, insbesondere bei Konstrukten wie some, contains und der Unterscheidung zwischen Regeln mit und ohne if-Body.
Policies sind außerdem Code, der gepflegt werden muss. Ändert sich das Plan-JSON-Format oder die eigene Organisationsregel, muss die Rego-Datei mitgezogen und getestet werden. Das ist ein eigener Wartungsaufwand, der bei einem reinen Scanner-Einsatz nicht anfällt.
Policy as Code mit OPA und Conftest ersetzt tfsec oder checkov nicht. Scanner decken bekannte, breit gültige Fehlmuster ab, ohne dass du dafür etwas schreiben musst. Rego-Policies decken die organisationsspezifischen Regeln ab, die kein Scanner kennen kann. Beide Prüfschritte ergänzen sich, sie stehen nicht in Konkurrenz zueinander.
Einbindung in die CI-Pipeline
In einer Pipeline setzt du den Conftest-Schritt zwischen terraform plan und terraform apply. Ein möglicher Ablauf:
terraform plan -out=plan.tfplanterraform show -json plan.tfplan > plan.jsonconftest test plan.json
Schlägt conftest test fehl, bricht die Pipeline vor dem Apply ab. Damit läuft die Policy-Prüfung als eigener, unabhängiger Schritt neben dem Scanner, nicht als dessen Ersatz.
Fragen oder Anmerkungen zu diesem Setup: 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.
Hinterlasse einen Kommentar