Scans in CI/CD

Dieses Dokument beschreibt das minimale Setup an kostenlosen Sicherheits-Scans, das erforderlich ist, um die ISO 27001 Anforderungen (Annex A.8.28/A.8.29) im Audit nachzuweisen. Jeder Scan muss automatisiert in der CI/CD-Pipeline laufen und Ergebnisse im Ticket-System dokumentiert werden.

Gemeinsame Anforderungen #

  • SAST: Statische Quellcodeanalyse
  • SCA: Prüfung auf bekannte Schwachstellen in Abhängigkeiten
  • Container/IaC (falls genutzt): Abgleich gegen Best Practices
  • Reporting: Findings mit Ticket und Abschluss dokumentieren

Scans nach Programmiersprache #

Java #

  • SAST: SpotBugs mit Security Plugin (Doku)
  • SCA: OWASP Dependency-Check (Doku)
  • Container/IaC: Trivy (Doku)
stages:
  - build
  - security

build:
  stage: build
  image: maven:3-eclipse-temurin-17
  script:
    - mvn -B clean package
  artifacts:
    paths:
      - target/

spotbugs:
  stage: security
  image: maven:3-eclipse-temurin-17
  script:
    - mvn -B com.github.spotbugs:spotbugs-maven-plugin:4.7.3.4:spotbugs
  allow_failure: false

dependency_check:
  stage: security
  image: owasp/dependency-check:latest
  script:
    - dependency-check.sh --project "app" --scan target/ --format "HTML"
  artifacts:
    paths:
      - dependency-check-report.html
  allow_failure: false

trivy_fs:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --exit-code 1 --severity HIGH,CRITICAL .
  allow_failure: false
name: java-security

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: '17'
      - run: mvn -B clean package

  security:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: SpotBugs
        run: mvn -B com.github.spotbugs:spotbugs-maven-plugin:4.7.3.4:spotbugs
      - name: Dependency-Check
        uses: dependency-check/Dependency-Check_Action@main
        with:
          project: app
          scan: target/
      - name: Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: HIGH,CRITICAL
          exit-code: '1'
# SpotBugs
docker run --rm -v "$PWD":/workspace -w /workspace \
  maven:3-eclipse-temurin-17 mvn -B \
  com.github.spotbugs:spotbugs-maven-plugin:4.7.3.4:spotbugs

# OWASP Dependency-Check
docker run --rm -v "$PWD":/workspace owasp/dependency-check:latest \
  --project "app" --scan /workspace --format HTML \
  --out /workspace/dependency-check-report

# Trivy
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace

Node.js #

  • SAST: Semgrep (Doku)
  • SCA: npm audit (Doku)
  • Container/IaC: Trivy (Doku)
stages:
  - install
  - security

install:
  stage: install
  image: node:20-alpine
  script:
    - npm ci

semgrep:
  stage: security
  image: returntocorp/semgrep:latest
  script:
    - semgrep scan --config=p/nodejs --error
  allow_failure: false

npm_audit:
  stage: security
  image: node:20-alpine
  script:
    - npm audit --production
  allow_failure: false

trivy_fs:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --exit-code 1 --severity HIGH,CRITICAL .
  allow_failure: false
name: node-security

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - name: Semgrep
        uses: returntocorp/semgrep-action@v1
        with:
          config: p/nodejs
      - run: npm audit --production
      - name: Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: HIGH,CRITICAL
          exit-code: '1'
# Dependencies installieren
docker run --rm -v "$PWD":/workspace -w /workspace \
  node:20-alpine npm ci

# Semgrep
docker run --rm -v "$PWD":/workspace \
  returntocorp/semgrep:latest scan --config=p/nodejs --error

# npm audit
docker run --rm -v "$PWD":/workspace -w /workspace \
  node:20-alpine npm audit --production

# Trivy
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace

PHP #

  • SAST: PHPStan (Doku) oder Psalm (Doku)
  • SCA: Composer Audit (Doku)
  • Container/IaC: Trivy (Doku)
stages:
  - install
  - security

install:
  stage: install
  image: php:8.2-cli
  script:
    - composer install --no-interaction --prefer-dist

phpstan:
  stage: security
  image: php:8.2-cli
  script:
    - composer exec phpstan analyse --level=max src/
  allow_failure: false

composer_audit:
  stage: security
  image: composer:2
  script:
    - composer audit --no-dev
  allow_failure: false

trivy_fs:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --exit-code 1 --severity HIGH,CRITICAL .
  allow_failure: false
name: php-security

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install --no-interaction --prefer-dist
      - name: PHPStan
        run: composer exec phpstan analyse --level=max src/
      - run: composer audit --no-dev
      - name: Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: HIGH,CRITICAL
          exit-code: '1'
# Abhängigkeiten installieren
docker run --rm -v "$PWD":/workspace -w /workspace \
  php:8.2-cli composer install --no-interaktion --prefer-dist

# PHPStan
docker run --rm -v "$PWD":/workspace -w /workspace \
  php:8.2-cli composer exec phpstan analyse --level=max src/

# Composer Audit
docker run --rm -v "$PWD":/workspace \
  composer:2 audit --no-dev

# Trivy
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace

Perl #

  • SAST: PerlCritic (Doku)
  • SCA: cpan-audit (Doku)
  • Container/IaC: Trivy (Doku)
stages:
  - security

perlcritic:
  stage: security
  image: perl:5.38
  script:
    - cpanm --quiet --notest Perl::Critic App::cpanminus App::cpanoutdated App::cpanminus::reporter
    - perlcritic --severity 3 --profile perlcriticrc src/
  allow_failure: false

cpan_audit:
  stage: security
  image: perl:5.38
  script:
    - cpanm --quiet --notest App::cpanminus::reporter
    - cpan-audit --cpanfile cpanfile
  allow_failure: false
name: perl-security

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Perl
        uses: shogo82148/actions-setup-perl@v1
        with:
          perl-version: '5.38'
      - run: cpanm --quiet --notest Perl::Critic App::cpanminus App::cpanoutdated App::cpanminus::reporter
      - run: perlcritic --severity 3 --profile perlcriticrc src/
      - run: cpan-audit --cpanfile cpanfile
      - name: Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: HIGH,CRITICAL
          exit-code: '1'
# PerlCritic & cpan-audit
docker run --rm -v "$PWD":/workspace -w /workspace perl:5.38 \
  bash -lc "cpanm --quiet --notest Perl::Critic App::cpanminus::reporter && \
  perlcritic --severity 3 src/ && cpan-audit --cpanfile cpanfile"

# Trivy
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace

Golang #

  • SAST: gosec (Doku)
  • SCA: govulncheck (Doku)
  • Container/IaC: Trivy (Doku)
stages:
  - security

gosec:
  stage: security
  image: golang:1.22
  script:
    - go install github.com/securego/gosec/v2/cmd/gosec@latest
    - gosec ./...
  allow_failure: false

govulncheck:
  stage: security
  image: golang:1.22
  script:
    - go install golang.org/x/vuln/cmd/govulncheck@latest
    - govulncheck ./...
  allow_failure: false

trivy_fs:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --exit-code 1 --severity HIGH,CRITICAL .
  allow_failure: false
name: go-security

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
      - name: Gosec
        run: |
          go install github.com/securego/gosec/v2/cmd/gosec@latest
          gosec ./...
      - name: govulncheck
        run: |
          go install golang.org/x/vuln/cmd/govulncheck@latest
          govulncheck ./...
      - name: Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: HIGH,CRITICAL
          exit-code: '1'
# Gosec & govulncheck
docker run --rm -v "$PWD":/workspace -w /workspace golang:1.22 \
  bash -lc "go install github.com/securego/gosec/v2/cmd/gosec@latest && \
  gosec ./... && go install golang.org/x/vuln/cmd/govulncheck@latest && \
  govulncheck ./..."

# Trivy
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace

Projekte in SVN #

Wenn ein Projekt noch Subversion (SVN) verwendet und keine automatisierte Pipeline zur Verfügung steht, kann das Audit bestehen, sofern Scans planmäßig laufen und Nachweise revisionssicher abgelegt werden.

  • Führe mindestens pro Sprint oder Release die gleichen SAST-, SCA- und Trivy-Scans aus wie oben beschrieben.
  • Lege Ergebnisse unter scan-reports/<YYYY-MM-DD>/ ab (Reports + kurze README.md mit Datum, Ticket, Verantwortliche).
  • Versioniere den Ordner im SVN (svn add/svn ci) oder lade die Reports in ein revisionssicheres Ticketsystem hoch.
  • Verknüpfe jedes Finding oder jede Ausnahme mit einem Ticket (siehe Umsetzungsphase Schritt „Ausnahmen dokumentieren“).
  • Stelle sicher, dass die Scans in Retro- oder Release-Meetings geprüft werden (Evidence Meeting Minutes).

Beispiel: Perl-Service in SVN #

# Checkout und Wechsel ins Arbeitsverzeichnis
svn checkout https://svn.example.com/repos/perl-service
cd perl-service

# Ordner für dne aktuellen Scan
scan_dir="scan-reports/$(date +%Y-%m-%d)"
mkdir -p "$scan_dir"

# PerlCritic & cpan-audit
# (liefert Log-Datei mit allen Findings)
docker run --rm -v "$PWD":/workspace -w /workspace perl:5.38 \
  bash -lc 'cpanm --quiet --notest Perl::Critic App::cpanminus::reporter && \
  perlcritic --severity 3 src/ && cpan-audit --cpanfile cpanfile' \
  > "$scan_dir/perlcritic-and-cpanaudit.log"

# Trivy Dateisystem-Scan
# (speichert JSON-Ausgabe für spätere Analyse)
docker run --rm -v "$PWD":/workspace aquasec/trivy:latest fs \
  --exit-code 1 --severity HIGH,CRITICAL /workspace \
  --format json --output "$scan_dir/trivy.json"

# Kurze README für Auditoren
cat <<'INFO' > "$scan_dir/README.md"
Datum: 2024-06-05
Ticket: SEC-123
Durchgeführt von: alice@example.com
Zusammenfassung: Keine kritischen Findings, zwei Low-Findings dokumentiert in SEC-124.
INFO

# Reports versionieren und Commit
du -sh scan-reports/2024-06-05
svn add "$scan_dir"
svn ci -m "SEC-123: Add security scan evidence"

Alternativ können die erzeugten Reports als ZIP in das Security-Ticket hochgeladen oder in einem Evidence-Store (Ticketsystem, S3 Bucket mit WORM, Nextcloud mit Versionierung) abgelegt werden. Wichtig ist, dass der Speicher revisionssicher ist und der Link im Repository beziehungsweise im Ticket festgehalten wird, damit Auditoren den Nachweis nachvollziehen können.

Behandlung von Findings #

  1. Sichtung & Priorisierung

    • Jedes Finding erhält eine Ticket-ID (z. B. SEC-FIND-<nr>). Nutze die vom Tool gemeldete Severity als Ausgangspunkt.
    • Ergänze Risikoeinschätzung (Impact × Wahrscheinlichkeit) und verweise auf betroffene Komponenten.
  2. Behebung & Nachweis

    • Kritische und hohe Findings sind zeitnah zu beheben (Regel: vor Release / innerhalb des nächsten Sprints).
    • Nachweis im Ticket: Commit-Link oder Merge Request mit Fix, erneuter Scan als Beleg.
  3. Kollision mit Kundenanforderungen oder Budget

    • Dokumentiere den Konflikt (z. B. Feature-Forderung, Budgetlimit) im Ticket.
    • Erstelle eine Risikoabwägung nach ISO 27001 (Owner, Impact, Kompensationen); Beispieltext für Jira:
Risiko-ID: SEC-RISK-048
Finding: Abhängigkeit xyz v1.2 mit CVE-2024-1234 (High)
Owner: alice@example.com (Security Champion)
Impact: Remote Code Execution gegen Admin-APIs möglich
Eintrittswahrscheinlichkeit: Mittel (nur interner Zugang)
Entscheid: Fix verschoben auf Sprint 2024-07 (Feature-Blocker für Kunde A)
Kompensation: WAF-Regel + erweitertes Monitoring, Log-Warnung an PagerDuty
Review-Datum: 2024-07-15
  • Lege eine formale Ausnahmegenehmigung vor (Security Champion + Product Owner + ggf. CISO) mit Frist und Review-Datum.
  • Führe Kompensationsmaßnahmen auf (z. B. Monitoring, zusätzliche Validierung) und plane eine erneute Bewertung im nächsten Audit.
  1. Langfristig inaktive Repositories

    • Für Repos ohne laufende Aktivitäten: Führe mindestens jährlich (oder vor Nutzung) einen manuellen Scan aus.
    • Dokumentiere Scan und Ergebnis im Evidence-Ordner (scan-reports/<Datum> oder Ticket-Archiv).
    • Vermerke im README oder im Portfolio, dass das Projekt „archiviert“ ist und welche Mindestkontrollen weiterhin laufen (z. B. jährlicher Review, Abhängigkeiten prüfen).
    • Bei Reaktivierung: Pipeline vor dem ersten Commit reaktivieren/verifizieren, ggf. behobene Security-Backlogs abarbeiten.
  2. Abschluss & Audit Trail

    • Aktualisiere das Finding-Ticket mit „Behoben“, „Akzeptiert“ oder „Veraltet / Projekt archiviert“.
    • Hinterlege Hinweis auf den Nachweisort (Pipeline-Log, Ticketanlage, ZIP).
    • In Sprint- oder Release-Reviews die Liste offener Findings durchgehen (Evidence: Meeting-Protokoll).