ADMIN

2026

01

2025-12-29T12:00:00

Infrastruktur und Rechenzentrum

PRAXIS

044

Sicherheit

Infrastruktur

Infrastructure-as-Code

Infrastructure-as-Code-Sicherheit mit Checkov

Gutachter

von Dr. Guido Söldner

Veröffentlicht in Ausgabe 01/2026 - PRAXIS

Infrastructure-as-Code gehört mittlerweile zum festen Rüstzeug für den Aufbau und Betrieb von Cloudumgebungen. Doch spielen dabei Sicherheits- und Complianceaspekte eine gewichtige Rolle und entsprechende Probleme sollten identifiziert werden, bevor Admins den IaC-Code produktiv schalten. Das Open-Source-Tool Checkov hilft bei der Suche und dem Beheben von Schwachstellen.

Checkov [1] ist ein Open-Source Security-Scanner, der Infrastructure-as-Code-Dateien (IaC) auf Fehlkonfigurationen, Sicherheitslücken und Ver- stöße gegen Best Practices oder Compliancestandards wie CIS, HIPAA oder GDPR prüft. Er bietet über 750 vordefinierte Richtlinien und erlaubt das Erstellen benutzerdefinierter Richtlinien in Python oder YAML. Zusätzlich unterstützt das Werkzeug die "Software Composition Analysis" (SCA) für Container-Images und Open-Source-Pakete, um Schwachstellen (CVEs) zu erkennen.
Im Detail liefert Checkov einen großen Funktionsumfang:
- IaC-Dateien auf Sicherheits- und Complianceprobleme scannen.
Checkov [1] ist ein Open-Source Security-Scanner, der Infrastructure-as-Code-Dateien (IaC) auf Fehlkonfigurationen, Sicherheitslücken und Ver- stöße gegen Best Practices oder Compliancestandards wie CIS, HIPAA oder GDPR prüft. Er bietet über 750 vordefinierte Richtlinien und erlaubt das Erstellen benutzerdefinierter Richtlinien in Python oder YAML. Zusätzlich unterstützt das Werkzeug die "Software Composition Analysis" (SCA) für Container-Images und Open-Source-Pakete, um Schwachstellen (CVEs) zu erkennen.
Im Detail liefert Checkov einen großen Funktionsumfang:
- IaC-Dateien auf Sicherheits- und Complianceprobleme scannen.
- Erkennt Sicherheitslücken wie Fehlkonfigurationen, offene Ports, unverschlüsselte Daten oder übermäßige Berechtigungen in IaC.
- Prüfen der Compliance gegen Standards wie CIS, PCI, HIPAA oder AWS Best Practices.
- SCA-Scans für Container und Pakete auf bekannte Schwachstellen.
- Python oder YAML für benutzerdefinierte Richtlinien.
- Integration in CI/CD-Pipelines wie etwa GitHub Actions, GitLab CI oder Azure DevOps.
- Erstellt detaillierte Scan-Berichte.
- Integriert sich in IDEs wie Visual Studio Code.
Neben Scans von Terraform-Code unterstützt Checkov noch eine ganze Reihe weiterer Technologien. Hierzu gehören unter anderem Helm, Kustomize, AWS SAM Configuration, Ansible, Argo Workflows, Azure ARM Templates, Azure-Pipeline-Konfigurationen, Azure Biceps, BitBucket, AWS CDK, CloudFormation, Dockerfile Scanning, GitHub und GitLab-Konfigurationen oder auch Kubernetes-Konfigurationen.
Erste Schritte
Checkov ist in Python implementiert und lässt sich daher mit dem Python Paket Manager installieren. Dies gelingt mit folgendem Befehl:
pip install checkov
Anschließend können Sie sofort loslegen und Code scannen mit checkov -d /user/tf. Wir wollen uns diesen Vorgang am Beispiel aus Listing 1 ansehen. Darin legen wir einen S3-Bucket an, der zwar verschlüsselt ist, aber öffentlichen Zugriff erlaubt. Das Ergebnis des Scans sieht dann wie folgt aus:
Passed checks: 3, Failed checks: 1, Skipped checks: 0
Check: "Ensure all data stored in the S3 bucket is securely encrypted at rest"
  PASSED for resource: aws_s3_ bucket.foo-bucket
  File: /example.tf:1-25
Check: "Ensure the S3 bucket has access logging enabled"
  PASSED for resource: aws_s3_ bucket.foo-bucket
  File: /example.tf:1-25
Check: "Ensure all data stored in the S3 bucket have versioning enabled"
  PASSED for resource: aws_s3_bucket.foo-bucket
  File: /example.tf:1-25
Check: "S3 Bucket has an ACL defined which allows public access."
  FAILED for resource: aws_s3_bucket.foo-bucket
  File: /example.tf:1-25
Dabei fällt auf, dass der Code eine Reihe von Tests bestanden hat – er ist verschlüsselt, hat Logging aktiviert und arbeitet mit Versionierung. Jedoch nicht bestanden ist der Check zum öffentlichen Zugriff. Daneben ist es auch möglich, den Output eines Terraform-Plan-Kommandos zu untersuchen:
terraform init
terraform plan -out tf.plan
terraform show -json tf.plan | jq ‘.‘ > tf.json
checkov -f tf.json
Listing 1: Beispielcode S3-Bucket
resource "aws_s3_bucket" "foo-bucket" {
  region = var.region
  bucket = local.bucket_name
  force_destroy = true
  tags = {
    Name = "foo-${data.aws_caller_identity.current. account_id}"
  }
  versioning {
    enabled = true
  }
  logging {
    target_bucket = "${aws_s3_bucket. log_bucket.id}"
    target_prefix = "log/"
  }
  server_side_encryption_configuration {
    rule {
        ;  apply_server_side_encryption_by_default {
        ;   kms_master_key_id =
    "${aws_kms_key.mykey.arn}"
        ;   sse_algorithm = "aws:kms"
        ;  }
    }
  }
  acl = "public-read"
}
Richtlinien selbst entwickeln
Eine der Stärken von Checkov ist es, dass Sie mittels Custom Policies spezifische Compliance- und Securityanforderungen überwachen und durchsetzen können. Beispielsweise lässt sich überprüfen, ob Tagging- oder Passwortrichtlinien eingehalten werden. Custom Policies können Sie in YAML oder Python verfassen und dabei auch komplexe Logik verwenden, wie das folgende Beispiel illustriert. Als Ausgangspunkt dient eine AWS-Lambda-Funktion, die in Terraform definiert ist und mit 2 GByte Arbeitsspeicher (Attribut "memory_size") daherkommt (Listing 2).
Listing 2: Beispielcode AWS-Lambda-Funktion
data "aws_iam_policy_document"
  "lambda_assume_role" {
  statement {
    effect = "Allow"
    principals {
        ;  type = "Service"
        ;  identifiers = ["lambda.amazonaws.com"]
    }
    actions = ["sts:AssumeRole"]
  }
}
resource "aws_iam_role" "lambda_role" {
  name = "lambda_role"
  assume_role_policy = data.aws_iam_policy_ document.lambda_assume_role.json
}
resource "aws_lambda_function" "test_lambda" {
  filename = "lambda.zip"
  function_name = "checkov_lambda"
  role = aws_iam_role.lambda_role.arn
  handler = "index.lambda_handler"
  memory_size = 2048
  runtime = "nodejs22.x"
}
Nun schreiben Sie eine Regel, die dem Arbeitsspeicher untersagt, auf mehr als 2 GByte anzuwachsen. Dazu legen Sie Datei mit dem Namen "CUSTOM_YAML. yaml" an und fügen folgenden Inhalt ein:
metadata:
       name: "Lambda Memory <=2GB"
       id: "CUSTOM_YAML"
       category: "GENERAL_SECURITY"
definition:
       cond_type: attribute
       resource_types:
       - aws_lambda_function
       attribute: memory_size
       operator: less_than_or_equal
       value: 2048
Die Policy besteht aus zwei Teilen: Im Abschnitt "metadata" sind der Name, die ID sowie die Kategorie der Custom Policy hinterlegt. Die eigentliche Definition erfolgt im zweiten Teil und unsere Policy bezieht sich auf das Attribut "memory_ size". Mit dem Operator "less_than_ or_equal" sowie dem "value" legen Sie fest, dass die Lambda-Funktion höchstens 2 GByte Arbeitsspeicher verwenden kann. Um die Richtlinie nun anzuwenden, nutzen Sie:
checkov -f tfplan.json --external-checks-dir policies --check CUSTOM_YAML
Für eine Custom Policy mit komplexerer Logik greifen Sie auf Python zurück. Dies schauen wir uns am Beispiel des AWS-Cloud-Control-API an. Diese Schnittstelle ermöglicht es, Cloudressourcen von AWS und Drittanbietern einheitlich zu verwalten und bietet dafür fünf grundlegende Operationen: Create, Read, Update, Delete und List (CRUD-L). Damit lässt sich der Lebenszyklus von Ressourcen wie Amazon-S3-Buckets, EC2-Instanzen oder Lambda-Funktionen steuern, ohne spezifische APIs für jeden Dienst schreiben zu müssen. Allerdings kann es beim Einsatz dieses API leicht passieren, dass in der Provider-Konfiguration ein hartcodierter AWS-Access-Key oder Secret-Key auftaucht.
Dies wollen wir mit einer Custom Policy in Python verhindern (Listing 3). Darin importieren wir zunächst die Basisklasse "BaseProviderCheck" für die Überprüfung von Terraform-Provider-Konfigurationen. Zudem definieren wir mit "CheckCategories.SECRETS" die Kategorie der Prüfung (hier: Geheimnisse wie Schlüssel). Schließlich enthält "CheckResult" mögliche Ergebnisse der Prüfung: PASSED (erfolgreich) oder FAILED (fehlerhaft). Anschließend findet die Klassendefinition statt, bei der die Klasse die "AWSCCCredentials" von "BaseProviderCheck" erbt. In der Initialisierung legen wir den Zweck der Prüfung sowie eine eindeutige ID ("CKV_AWS_41") fest. Mit dem Attribut "supported_provider" bestimmen Sie, dass die Custom Policy nur für den AWSCC-Provider (AWS Cloud Control API) gilt. Nun übergeben Sie noch die Kategorie (Secrets) und rufen den Konstruktor der Basisklasse auf.
Listing 3: Custom Policy für AWS-Cloud-Control-API
from checkov.terraform.checks.provider.base_
check import BaseProviderCheck
from checkov.common.models.enums import CheckCategories, CheckResult
class AWSCCCredentials(BaseProviderCheck):
  def __init__(self) -> None:
        ;  name = "Ensure no hard coded AWS access key and secret key exists in provider"
        ;  id = "CKV_AWS_41"
        ;  supported_provider = ["awscc"]
        ;  categories = [CheckCategories.SECRETS]
        ;  super().__init__(name=name, id=id, categories=categories, supported_ provider=supported_provider)
  def scan_provider_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:
        ;  result = CheckResult.PASSED
        ;  if self.secret_found(conf, "access_key", access_key_pattern):
  result = CheckResult.FAILED
  if self.secret_found(conf, "secret_key", secret_key_pattern):
  result = CheckResult.FAILED
  return result
Die eigentliche Prüflogik ist in der Funktion "scan_provider" hinterlegt. Sie erhält als Parameter ein Konfigurationselement (conf), dass die Terraform-Konfiguration des Providers als Dictionary mit Schlüsseln (Strings) und Werten (Listen beliebiger Typen) erhält. Die darauffolgende Logik überprüft mittels der geerbten Funktion "secret_found", ob im übergebenen Dictionary ein Secret enthalten ist – und schlägt fehl, falls dies festgestellt wird.
Integration in CI/CD-Pipelines
Neben dem manuellen Aufrufen lässt sich Checkov auch im Rahmen einer DevSecOps-Strategie früh im Entwicklungsprozess einsetzen. Denn laufen Security-Checks innerhalb einer CI/CD-Pipeline automatisiert ab, lassen sich Fehlkonfiguration und Schwachstellen ausräumen, bevor diese die Produktionsumgebung erreichen. Das spart Geld und Zeit, beim Bereinigen der entsprechenden Probleme.
Die von Unternehmen eingesetzten CI/CD Pipelines sind vielfältig, am häufigsten sind Jenkins, GitHub Actions, Azure DevOps und GitLab CI. Letztere soll uns als Beispiel dienen, um Checkov in eine Pipeline zu integrieren. Um Pipelines in GitLab CI wiederverwendbar zu implementieren, kommt seit GitLab 17 der GitLab-CI/CD-Katalog zum Einsatz. Um diesen zu nutzen, schreiben Sie die Logik in Form einer Komponente und veröffentlichen diese dann im CI/CD-Katalog. Zuerst erzeugen Sie ein neues Projekt und beschreiben die Komponente mittels einer "README. md"-Datei (siehe Bild 1).
Bild 1: Checkov integriert sich in die Entwicklung als Testwerkzeug in einer GitLab-CI/CD-Komponente.
 Nun erstellen Sie die YAML-Konfiguration für die Komponenten (Listing 4).
Die Struktur gliedert sich in zwei Hauptteile:"spec" (Spezifikation der Eingaben) und Jobdefinition. In der Spezifikation definieren wir die anpassbaren Parameter, die sich beim Inkludieren der Komponente übergeben lassen. Jeder Input hat eine Beschreibung, einen Default-Wert und optional einen Typ. Diese Inputs machen die Komponente flexibel und erlauben es, sie an verschiedene Projekte anzupassen:
- job_name: Beschreibt den Namen des Jobs in der Pipeline und definiert, wie der Job in der Pipeline erscheint.
- stage: Konfiguriert, in welcher Phase der Job ausgeführt wird. Standardmäßig ist dies "test", da Checkov Analysen durchführt.
- Mit dem Image-Parameter übergeben wir das für den Job zu verwendende Container-Image – dabei muss Checkov enthalten sein.
- context: Gibt den Ordner an, in dem die Terraform-Dateien liegen. Standardmäßig ist dies der Basis-Ordner des Repository – er kann aber auch überschrieben werden.
- scan_external_modules: Definiert, ob externe Module herunterzuladen sind.
Listing 4: YAML-Konfiguration für die Komponenten
---
spec:
  inputs:
    # General
    job_name:
        ;  description: "Name des Jobs"
        ;  default: "checkov"
    stage:
        ;  description: "Die Phase in der Checkov ausgeführt wird"
        ;  default: "test"
    image:
        ;  description: "Das genutzte Container- Image"
        ;  default: $TF_IMAGE
    context:
        ;  description: "Ordner mit Ihren Terraform-Files"
        ;  default: ""
    # Configuration checkov
    scan_external_modules:
        ;  description: "Sollen externe Module heruntergeladen und gescannt werden?"
        ;  type: boolean
        ;  default: false
---
# Startet Checkov für Codeanalyse
$[[ inputs.job_name ]]:
  stage: $[[ inputs.stage ]]
  image: $[[ inputs.image ]]
  script:
    - |
        ;  checkov \
        ;  --file ${TF_ROOT}/plan.json \
        ;  --output cli \
        ;  --output junitxml \
        ;  --output-file-path console, checkov-sast.xml \
        ;  --download-external-modules $[[ inputs.scan_external_modules ]] \
        ;  --repo-root-for-plan-enrichment ${TF_ROOT} \
        ;  --deep-analysis \
        ;  --quiet \
        ;  --compact
  artifacts:
    when: always
    paths:
        ;  - "checkov-sast.xml"
    reports:
        ;  junit: "checkov-sast.xml"
  allow_failure: false
  interruptible: false
  variables:
    TF_CONTEXT: $[[ inputs.context ]]
Im zweiten Teil der YAML-Datei geben wir den eigentlichen CI-Job an. Dabei setzen wir dessen Namen dynamisch mit "$[[ inputs.job_name ]]". Der Job führt Checkov aus, um einen Terraform-Plan zu analysieren. Dazu scannt das Tool die Datei "plan.json", die einen JSON-Export eines Terraform-Plans darstellt. Mit "--output junitxml" erzeugen wir ein JUnit-XML-Format für Testberichte und legen dies mit "output-file-path console,checkov-sast.xml" in der checkov-sast.xml-Datei ab. Auch schieben wir so alle CLI-Ausgaben in die Konsole. Mit der "artifacts"-Section erreichen wir, dass die erzeugten Dateien nach dem Pipeline-Run in GitLab persistiert und als Testreporte gespeichert werden. Nun können Sie die Komponente zum Einsatz bringen. Die erfolgt mithilfe der gitlab-ci.yml-Datei:
include:
       - component: gitlab.com/<your-org/ security/checkov@1.0.0> # Pfad
        inputs:
          ;job_name: "terraform- checkov-scan"
          ;stage: "test"
          ;scan_external_modules: true
Bild 2: Checkov verrichtet seinen Dienst in einer Terraform-Pipeline.
Anschließend sehen Sie im GitLab-GUI den Status der Ausführung wie in Bild 2. Ist alles durchgelaufen, finden Sie unter der Registerkarte "Tests" die veröffentlichten Ergebnisse. Bisweilen kann es vorkommen, dass Sie gefundene Issues ignorieren wollen. Zu diesem Zweck hinterlegen Sie eine checkov.yml-Datei im Terraform-Verzeichnis und definieren darin entsprechende Ausnahmen:
checkov:
skip-check:
       - CKV2_GCP_5
       - CKV_GCP_12
       - CKV_GCP_20
       - CKV_GCP_21
       - CKV_GCP_25
Fazit
Checkov leistet IT-Verantwortlichen wertvolle Hilfe bei Sicherheits- und Complianceprüfungen von Infrastructure-as-Code. Mit Unterstützung für zahlreiche IaC-Formate, über 750 vordefinierten Richtlinien und der Möglichkeit, benutzerdefinierte Regeln in Python oder YAML zu erstellen, erlaubt das Tool einfrühzeitiges Erkennen von Sicherheitslücken und Fehlkonfigurationen. DevSec-Ops-Teams dürfen sich zudem über die Integration in CI/CD-Pipelines und IDEs sowie die Unterstützung von SCA für Container und Open-Source-Pakete freuen. Checkov überzeugt dabei durch seine Flexibilität sowie einfache Handhabung.
(jp)
Links