Veröffentlicht am

Security Scanning automatisieren: Trivy und Falco CI/CD

Teilen:
Authors

Kubernetes Security Scanning automatisieren: Trivy und Falco in der CI/CD-Pipeline

TL;DR

  • Trivy scannt Container-Images in der CI/CD-Pipeline und bricht den Build bei kritischen CVEs ab -- das ist der einfachste Einstieg in automatisiertes Security Scanning.
  • Falco ueberwacht zur Laufzeit Syscalls und Kubernetes-API-Events und liefert Alerts innerhalb von Sekunden bei verdaechtigem Verhalten.
  • Beide Tools sind Open Source, lassen sich mit Helm deployen und brauchen keine externe Infrastruktur.
  • Die Kombination aus statischer Analyse (Trivy) und Runtime-Erkennung (Falco) deckt den gesamten Container-Lifecycle ab.
  • Wer nur ein Tool einsetzen will: Trivy im CI/CD ist der beste erste Schritt.

Das Problem: Warum manuelle Security-Checks nicht skalieren

Container-Images basieren auf Hunderten von Paketen. Jedes davon kann bekannte Schwachstellen enthalten. Manuell laesst sich das nicht pruefen -- nicht bei fuenf Images pro Woche und erst recht nicht bei fuenfzig.

Dazu kommt: Schwachstellen tauchen laufend neu auf. Ein Image, das gestern sauber war, kann heute eine kritische CVE haben. Ohne automatisiertes Scanning erfahren Teams das erst, wenn es zu spaet ist.

Die Loesung ist ein zweistufiger Ansatz: statische Analyse vor dem Deployment und Laufzeitueberwachung im Cluster.

Trivy: Statische Analyse in der Build-Phase

Trivy ist ein Vulnerability Scanner von Aqua Security. Er scannt Container-Images, Dateisysteme, Git-Repos und IaC-Dateien (Terraform, Kubernetes-Manifeste). Die Staerke von Trivy liegt in der einfachen Integration: Ein einziger CLI-Aufruf reicht.

Was Trivy scannt

Scan-TypWas wird geprueftTypische Funde
Image ScanningOS-Pakete, App-DependenciesCVEs in Alpine, Debian, npm, pip, Maven
IaC ScanningKubernetes YAML, Terraform, DockerfilesPrivilegierte Container, fehlende Resource Limits
Filesystem ScanningLokale VerzeichnisseSchwachstellen in lockfiles (package-lock.json, go.sum)
SBOMSoftware Bill of MaterialsVollstaendige Abhaengigkeitsliste fuer Compliance

Trivy in GitHub Actions

Das folgende Beispiel scannt jedes Image bei einem Push auf main und bricht den Build ab, wenn kritische oder hochgradige Schwachstellen gefunden werden.

# .github/workflows/security-scan.yml
name: Container Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  trivy-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL,HIGH'
          ignore-unfixed: true

      - name: Run Trivy IaC scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: './k8s/'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL'

Der Parameter ignore-unfixed: true ist wichtig: Er filtert CVEs heraus, fuer die es noch keinen Fix gibt. Ohne diesen Filter blockiert Trivy Builds wegen Schwachstellen, die sich gar nicht beheben lassen.

Trivy lokal testen

Bevor man Trivy in die Pipeline integriert, lohnt sich ein lokaler Test:

# Image scannen
trivy image --severity HIGH,CRITICAL nginx:1.25

# Kubernetes-Manifeste scannen
trivy config ./k8s/

# Nur fixbare Schwachstellen anzeigen
trivy image --ignore-unfixed --severity CRITICAL myapp:latest

# Ergebnis als JSON fuer weitere Verarbeitung
trivy image --format json --output results.json myapp:latest

Falco: Runtime-Erkennung im Cluster

Trivy findet Schwachstellen vor dem Deployment. Falco erkennt verdaechtiges Verhalten zur Laufzeit. Es ueberwacht Syscalls auf Kernel-Ebene und Kubernetes-Audit-Events.

Typische Szenarien, die Falco erkennt:

  • Ein Shell-Prozess startet in einem Container, der nur einen Webserver ausfuehren sollte
  • Ein Prozess schreibt in /etc/ oder /usr/bin/
  • Ein Container oeffnet eine ausgehende Verbindung zu einer unbekannten IP
  • Jemand erstellt einen privilegierten Pod ueber die Kubernetes API

Falco mit Helm installieren

# Helm-Repo hinzufuegen
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

# Falco installieren mit Falcosidekick fuer Alerting
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/XXX" \
  --set falcosidekick.config.slack.minimumpriority="warning" \
  --set driver.kind=modern_ebpf

Die Option driver.kind=modern_ebpf nutzt den modernen eBPF-Treiber statt eines Kernel-Moduls. Das ist stabiler und erfordert keine Kernel-Header auf den Nodes.

Eigene Falco-Regeln schreiben

Falco bringt ueber 100 Standardregeln mit. Fuer eigene Workloads lohnen sich zusaetzliche Regeln:

# custom-rules.yaml
- rule: Unexpected outbound connection from web pod
  desc: Erkennt ausgehende Verbindungen von Web-Pods zu externen IPs
  condition: >
    evt.type in (connect) and
    evt.dir = < and
    fd.typechar = 4 and
    fd.ip != "0.0.0.0" and
    not fd.snet in (rfc_1918_addresses) and
    k8s.pod.label.app = "web"
  output: >
    Unexpected outbound connection from web pod
    (pod=%k8s.pod.name ip=%fd.sip command=%proc.cmdline connection=%fd.name)
  priority: WARNING
  tags: [network, web]

- rule: Write to sensitive mount path
  desc: Schreibzugriff auf sensible Verzeichnisse erkennen
  condition: >
    evt.type in (open, openat) and
    evt.is_open_write = true and
    (fd.name startswith /etc/ or fd.name startswith /usr/bin/) and
    not proc.name in (apt, dpkg, yum, rpm)
  output: >
    Write to sensitive path
    (user=%user.name command=%proc.cmdline file=%fd.name container=%container.name)
  priority: ERROR
  tags: [filesystem, security]

Trivy und Falco im Vergleich

KriteriumTrivyFalco
PhaseBuild-Zeit / CI/CDRuntime / Cluster
ErkennungsartBekannte CVEs, FehlkonfigurationenVerdaechtiges Verhalten, Anomalien
DatenquelleImage-Layer, Paketmanager, LockfilesSyscalls, K8s Audit Events
Alerting-LatenzSofort im CI/CD-LaufSekunden nach dem Event
False-Positive-RateNiedrig (basiert auf CVE-Datenbank)Mittel (erfordert Regel-Tuning)
InstallationsaufwandMinimal (CLI-Tool oder GitHub Action)Mittel (DaemonSet auf jedem Node)
RessourcenbedarfNur waehrend des ScansPermanent auf jedem Node

Die beiden Tools ergaenzen sich. Trivy verhindert, dass verwundbare Images deployed werden. Falco erkennt Angriffe und unerwartetes Verhalten im laufenden Betrieb.

Integration in den Alerting-Stack

Beide Tools liefern nur dann Wert, wenn die Alerts auch ankommen. Eine typische Integration sieht so aus:

Trivy-Alerts: Der CI/CD-Lauf schlaegt fehl, das Team sieht den Fehler in GitLab/GitHub. Fuer naechtliche Registry-Scans lassen sich Trivy-Ergebnisse per Webhook an Slack oder per JSON an ein SIEM senden.

Falco-Alerts: Falcosidekick leitet Alerts an Slack, PagerDuty, Elasticsearch oder Prometheus weiter. Fuer kritische Events (Priority ERROR oder hoeher) empfiehlt sich eine direkte PagerDuty-Integration.

# Falco-Logs pruefen
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=50

# Falcosidekick-Status pruefen
kubectl logs -n falco -l app.kubernetes.io/name=falcosidekick --tail=20

Naechtliche Registry-Scans mit CronJob

Images altern. Neue CVEs tauchen taeglich auf. Ein Image, das letzte Woche sauber war, kann heute kritische Schwachstellen haben. Deswegen reicht Scanning im CI/CD allein nicht aus.

Ein Kubernetes CronJob kann naechtlich alle Images in der Registry scannen und Ergebnisse an Slack oder ein SIEM senden:

# trivy-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: trivy-registry-scan
  namespace: security
spec:
  schedule: "0 3 * * *"  # Jede Nacht um 3 Uhr
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: trivy
              image: aquasec/trivy:latest
              command:
                - /bin/sh
                - -c
                - |
                  # Alle Images aus der internen Registry scannen
                  for IMAGE in $(cat /config/images.txt); do
                    echo "Scanning $IMAGE..."
                    trivy image --severity CRITICAL,HIGH \
                      --format json \
                      --output /results/${IMAGE//\//_}.json \
                      $IMAGE
                  done
                  # Ergebnisse an Webhook senden
                  for RESULT in /results/*.json; do
                    curl -X POST -H "Content-Type: application/json" \
                      -d @$RESULT \
                      $WEBHOOK_URL
                  done
              env:
                - name: WEBHOOK_URL
                  valueFrom:
                    secretKeyRef:
                      name: trivy-webhook
                      key: url
              volumeMounts:
                - name: config
                  mountPath: /config
                - name: results
                  mountPath: /results
          volumes:
            - name: config
              configMap:
                name: trivy-image-list
            - name: results
              emptyDir: {}
          restartPolicy: OnFailure

Die ConfigMap trivy-image-list enthaelt eine Liste aller zu scannenden Images. Diese kann automatisch aus den laufenden Deployments generiert werden:

# Alle Images im Cluster auflisten
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | sort -u > images.txt

# ConfigMap erstellen
kubectl create configmap trivy-image-list -n security --from-file=images.txt

Admission Controller: Unsichere Images am Deployment hindern

Trivy im CI/CD und naechtliche Scans sind reaktiv. Ein Admission Controller ist praeventiv: Er lehnt Pods ab, die ein unsicheres Image verwenden, bevor sie ueberhaupt starten.

Kyverno ist ein Kubernetes-nativer Policy Engine, der ohne separate Sprache auskommt. Policies werden in YAML geschrieben:

# kyverno-policy.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-scan
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: check-image-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Images mit 'latest' Tag sind nicht erlaubt. Nutze einen spezifischen Tag oder SHA."
        pattern:
          spec:
            containers:
              - image: "!*:latest"
    - name: require-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Container muessen als non-root laufen."
        pattern:
          spec:
            containers:
              - securityContext:
                  runAsNonRoot: true

Der Vorteil von Kyverno gegenueber OPA/Gatekeeper: Die Policies sind reines YAML, kein Rego. Das senkt die Einstiegshuerde fuer Teams, die bereits Kubernetes-Manifeste schreiben.

Typische Stolperfallen

Zu strenge Trivy-Konfiguration am Anfang. Wenn der erste Scan 200 Findings liefert und den Build blockiert, wird das Team Trivy umgehen statt die Findings zu fixen. Besser: Anfangs nur CRITICAL blockieren, dann schrittweise HIGH hinzunehmen.

Falco-Regeln nicht an die eigenen Workloads angepasst. Die Standardregeln erzeugen in vielen Umgebungen zu viele False Positives. Wer Falco deployed, sollte eine Woche lang im Audit-Modus laufen und die Regeln danach anpassen.

Kein Prozess fuer gefundene Schwachstellen. Scanning ohne Remediation ist Monitoring ohne Alerting. Es braucht klare Verantwortlichkeiten: Wer triaged die Findings? Wer fixt sie? In welchem Zeitrahmen?

Registry-Scans vergessen. Ein Image, das bei Deployment sauber war, kann spaeter neue CVEs bekommen. Regelmaessige Scans der Container Registry (z.B. naechtlich per CronJob) fangen das ab.

Empfohlene Reihenfolge fuer die Einfuehrung

  1. Woche 1-2: Trivy lokal testen, ersten CI/CD-Job einrichten (nur CRITICAL, allow_failure: true)
  2. Woche 3-4: Trivy auf exit-code: 1 setzen fuer CRITICAL. IaC-Scanning hinzufuegen.
  3. Woche 5-6: Falco im Staging-Cluster installieren. Eine Woche Logs sammeln, Regeln tunen.
  4. Woche 7-8: Falco in Produktion deployen. Alerting an Slack/PagerDuty anbinden.
  5. Woche 9-10: Trivy-Severity auf HIGH erweitern. Naechtliche Registry-Scans einrichten.
  6. Woche 11-12: Eigene Falco-Regeln fuer kritische Workloads schreiben. Incident-Response-Prozess dokumentieren.

Weiterführende Themen


Wenn Sie Unterstuetzung bei der Einfuehrung von Security Scanning in Ihrem Kubernetes-Cluster brauchen oder Ihre bestehende Pipeline reviewen lassen moechten, melden Sie sich gerne bei uns unter /kontakt.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen