Automatisieren der Überprüfung von Container-Images

Abgeschlossen

Containerimages packen Anwendungen zusammen mit all ihren Abhängigkeiten, wodurch sie zu praktischen bereitstellungsfähigen Artefakten werden. Dieser Komfort führt jedoch zu erheblichen Sicherheitsproblemen – Sicherheitsrisiken in Basisimages, Systempaketen oder Anwendungsabhängigkeiten können bereitgestellte Container kompromittieren. Durch die Automatisierung der Containerimageüberprüfung während des gesamten Entwicklungs- und Bereitstellungslebenszyklus wird sichergestellt, dass nur sichere, kompatible Images Produktionsumgebungen erreichen.

Grundlegendes zu Containersicherheitsrisiken

Container-Images bergen mehrere Kategorien von Sicherheitsrisiken.

Sicherheitsrisiken für Basisimages

Betriebssystempakete:

  • Systembibliotheken: Basisimages umfassen Betriebssystembibliotheken (glibc, OpenSSL, zlib), die Sicherheitsrisiken enthalten können.
  • Paketmanager: Systempaketmanager (apt, yum, apk) und ihre Pakete haben häufig Sicherheitsprobleme.
  • Shell-Dienstprogramme: Allgemeine Hilfsprogramme (Bash, Curl, wget) in Basisimages können Sicherheitsrisiken aufweisen.
  • Aktualisierungsverzögerung: Offizielle Basisbilder können veraltete Pakete zwischen Versionen enthalten.

Auswirkungen der Basisbildauswahl:

  • Alpine vs Debian: Alpine Linux-Basisimages sind kleiner, verwenden jedoch verschiedene Bibliotheken (Musl anstelle von Glibc), die Sicherheitsrisikoprofile beeinträchtigen.
  • Distroless-Images: Die distroless-Images von Google enthalten nur die notwendigen Abhängigkeiten zur Ausführung von Anwendungen und verringern dadurch die Angriffsfläche erheblich.
  • Schlanke Varianten: Schlanke Imagevarianten schließen allgemeine Dienstprogramme aus, verringern die Größe und die Gefährdung durch Sicherheitsrisiken.
  • Versionswährung: Die Verwendung von latest Tags kann unerwartete Änderungen verursachen. Bestimmte Versionstags bieten Stabilität, erfordern jedoch manuelle Updates.

Anwendungsabhängigkeitsrisiken

Sprachspezifische Pakete:

  • npm-Pakete: Node.js Anwendungen enthalten Hunderte von npm-Abhängigkeiten, die möglicherweise Sicherheitsrisiken aufweisen.
  • Python-Pakete: Python-Anwendungen enthalten PyPI-Pakete mit potenziellen Sicherheitsproblemen.
  • Java-Abhängigkeiten: Maven- und Gradle-Abhängigkeiten enthalten transitiv viele JAR-Dateien.
  • .NET-Pakete: NuGet-Pakete in .NET-Anwendungen können Sicherheitsrisiken enthalten.

Transitive Abhängigkeiten:

  • Tiefe Abhängigkeitsbäume: Anwendungsabhängigkeiten verfügen über eigene Abhängigkeiten, wodurch tiefe Abhängigkeitsstrukturen erstellt werden.
  • Ausgeblendete Sicherheitsrisiken: Sicherheitsrisiken in transitiven Abhängigkeiten werden ohne automatisierte Überprüfung leicht übersehen.
  • Komplexität aktualisieren: Das Aktualisieren transitiver Abhängigkeiten erfordert ein Verständnis der Kompatibilität in der gesamten Abhängigkeitskette.

Akkumulation von Bildebenen

Layered filesystem:

  • Layervererbung: Jede Dockerfile-Anweisung erstellt eine neue Ebene, und Sicherheitsrisiken in jeder Ebene wirken sich auf das endgültige Image aus.
  • Gelöschte Dateien bleiben erhalten: Dateien, die in späteren Ebenen gelöscht wurden, sind noch in früheren Ebenen vorhanden und tragen zur Bildgröße und zum Sicherheitsprofil bei.
  • Geheimnisse in der Geschichte: Geheimnisse, die versehentlich in frühen Ebenen gespeichert wurden, verbleiben im Bildverlauf, auch wenn sie in späteren Ebenen entfernt werden.
  • Buildzeitabhängigkeiten: Abhängigkeiten, die nur während des Builds (Compiler, Buildtools) benötigt werden, sollten nicht in endgültigen Laufzeitimages angezeigt werden.

Konfigurationsrisiken

Dockerfile-Fehlkonfigurationen:

  • Wird als Root ausgeführt: Container, die als Rootbenutzer ausgeführt werden, verfügen über unnötige Berechtigungen.
  • Verfügbar gemachte Ports: Unnötig offengelegte Ports erweitern die Angriffsfläche.
  • SUID-Binärdateien: SUID/SGID-Binärdateien ermöglichen Berechtigungseskalationsangriffe.
  • Unsichere Standardwerte: Standardkonfigurationen folgen möglicherweise nicht den bewährten Methoden der Sicherheit.

Container-Scan-Methoden

Die effektive Containersicherheit erfordert überprüfungen an mehreren Punkten im Lebenszyklus:

Registrierungsüberprüfung

Kontinuierliche Registrierungsüberwachung: Containerregistrierungen bieten zentrale Speicherorte für die Überprüfung und Richtlinienerzwingung.

Überprüfung der Azure-Containerregistrierung mit Microsoft Defender:

  • Automatische Überprüfung: Microsoft Defender für Container überprüft automatisch Bilder, die in die Azure-Containerregistrierung verschoben werden.
  • Triggerbasiertes Scannen: Scans werden bei Push-, Import- und Pullvorgängen ausgelöst.
  • Kontinuierliches Erneutes Scannen: Bilder werden regelmäßig nach neu offengelegten Sicherheitsrisiken überprüft.
  • Empfehlungen: Security Center bietet Korrekturempfehlungen für erkannte Sicherheitsrisiken.

Registrierungsdatenbank-Scan-Auslöser:

  • Pushtrigger: Neue Images werden automatisch überprüft, wenn sie an die Registrierung gepusht werden.
  • Importtrigger: Aus externen Registern importierte Bilder werden gescannt.
  • Pulltrigger: Images werden innerhalb von 24 Stunden nach dem Pullen überprüft.
  • Regelmäßiges Erneutes Scannen: Zuvor gescannte Bilder werden täglich neu gescannt (letzte 90 Tage für Pushbilder, letzte 30 Tage für pulled-Bilder).

Überprüfung zur Buildzeit

CI/CD-Pipeline-Integration: Das Scannen während der Image-Erstellungen erfasst Sicherheitslücken, bevor die Images die Registries erreichen.

Scannen von Azure Pipelines-Containern:

trigger:
  branches:
    include:
      - main

pool:
  vmImage: "ubuntu-latest"

variables:
  imageName: "myapp"
  dockerfilePath: "$(Build.SourcesDirectory)/Dockerfile"

steps:
  - task: Docker@2
    displayName: "Build container image"
    inputs:
      command: "build"
      repository: "$(imageName)"
      dockerfile: "$(dockerfilePath)"
      tags: "$(Build.BuildNumber)"

  - task: AquaScannerCLI@4
    displayName: "Scan image with Aqua Security"
    inputs:
      image: "$(imageName):$(Build.BuildNumber)"
      scanType: "local"
      register: false
      hideBase: false
      showNegligible: false

  - script: |
      docker run --rm \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v $(Build.SourcesDirectory):/src \
        aquasec/trivy image \
        --severity HIGH,CRITICAL \
        --exit-code 1 \
        $(imageName):$(Build.BuildNumber)
    displayName: "Scan with Trivy (fail on high/critical)"

  - task: Docker@2
    displayName: "Push image to registry"
    condition: succeeded()
    inputs:
      command: "push"
      repository: "$(imageName)"
      tags: "$(Build.BuildNumber)"

Containerüberprüfung für GitHub-Aktionen:

name: Container Build and Scan

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

env:
  IMAGE_NAME: myapp
  REGISTRY: ghcr.io

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      security-events: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Build container image
        uses: docker/build-push-action@v4
        with:
          context: .
          load: true
          tags: ${{ env.IMAGE_NAME }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Scan image with Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "${{ env.IMAGE_NAME }}:${{ github.sha }}"
          format: "sarif"
          output: "trivy-results.sarif"
          severity: "CRITICAL,HIGH"

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: "trivy-results.sarif"

      - name: Scan with Snyk
        uses: snyk/actions/docker@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          image: ${{ env.IMAGE_NAME }}:${{ github.sha }}
          args: --severity-threshold=high --file=Dockerfile

      - name: Log in to GitHub Container Registry
        if: github.event_name == 'push'
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Push image to registry
        if: github.event_name == 'push'
        run: |
          docker tag ${{ env.IMAGE_NAME }}:${{ github.sha }} \
            ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}
          docker push ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}

Scan des GitHub Advanced Security-Containers: GitHub Advanced Security bietet zusätzliche Containersicherheitsfunktionen über CodeQL und Abhängigkeitsscans.

name: Container Security with GitHub Advanced Security

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: "0 0 * * 0" # Weekly scheduled scan

env:
  IMAGE_NAME: myapp
  REGISTRY: ghcr.io

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write
      packages: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v2
        with:
          languages: "javascript" # Adjust based on your language

      - name: Build container image
        run: |
          docker build -t ${{ env.IMAGE_NAME }}:${{ github.sha }} .

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v2
        with:
          category: "/language:javascript"

      - name: Run CodeQL container scanning
        uses: github/codeql-action/analyze@v2
        with:
          category: "/language:dockerfile"

      - name: Scan container dependencies
        uses: anchore/scan-action@v3
        with:
          image: ${{ env.IMAGE_NAME }}:${{ github.sha }}
          fail-build: true
          severity-cutoff: high

      - name: Upload Anchore scan SARIF report
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: results.sarif

      - name: Push image to registry
        if: github.event_name == 'push'
        run: |
          echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
          docker tag ${{ env.IMAGE_NAME }}:${{ github.sha }} ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}
          docker push ${{ env.REGISTRY }}/${{ github.repository }}:${{ github.sha }}

Vorteile der Überprüfung zur Buildzeit:

  • Frühzeitig fehlschlagen: Verhindern, dass anfällige Bilder erstellt und in Register hochgeladen werden.
  • Entwicklerfeedback: Geben Sie Entwicklern während des Buildprozesses sofortiges Feedback.
  • Richtlinienerzwingung: Erzwingen Sie Sicherheitsrichtlinien, bevor Bilder Register oder Produktionsumgebungen erreichen.
  • Validierung der Buildartefakte: Stellen Sie sicher, dass nur konforme Images die Bereitstellungspipeline durchlaufen.

Laufzeitscan

Bereitgestellte Containerüberwachung: Die Laufzeitüberprüfung erkennt Sicherheitsrisiken in tatsächlich bereitgestellten Containern.

Kubernetes-Admission-Controller: Admission-Controller setzen Richtlinien durch, bevor Container in Kubernetes-Clustern bereitgestellt werden.

OPA Gatekeeper-Richtlinienbeispiel:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredscanstatus
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredScanStatus
      validation:
        openAPIV3Schema:
          type: object
          properties:
            maxSeverity:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredscanstatus

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not scan_clean(container.image)
          msg := sprintf("Image %v has not been scanned or has vulnerabilities", [container.image])
        }

        scan_clean(image) {
          # Query registry for scan status
          # This is simplified; actual implementation queries scan results
          scan_result := data.scans[image]
          scan_result.status == "passed"
        }

Azure Kubernetes Service-Laufzeitschutz: Microsoft Defender für Container bietet Laufzeit-Bedrohungserkennung:

  • Verhaltensanalysen: Überwacht das Containerverhalten, um anomale Aktivitäten zu erkennen.
  • Bedrohungserkennung: Vergleicht beobachtete Verhaltensweisen mit bekannten Angriffsmustern.
  • MITRE ATT&CK-Zuordnung: Ordnet erkannte Bedrohungen dem MITRE ATT&CK-Framework zu.
  • Warnungsgenerierung: Generiert Sicherheitswarnungen für verdächtige Containeraktivitäten.

Tools zur Containerüberprüfung

Trivy (Aqua Security)

Trivy ist ein umfassender Open-Source-Container-Sicherheitsrisikoscanner.

Wichtige Features:

  • Umfassendes Scannen: Überprüft Betriebssystempakete, Anwendungsabhängigkeiten, IaC-Konfigurationen und geheime Schlüssel.
  • Unterstützung für mehrere Formate: Überprüft Containerimages, Dateisysteme, Git-Repositorys und Kubernetes-Cluster.
  • Offline-Scan: Kann in isolierten Umgebungen mit Offline-Schwachstellendatenbanken ausgeführt werden.
  • Schnelle Leistung: Einfacher Scanner mit schnellen Scanzeiten.
  • SBOM-Generierung: Generiert CycloneDX- und SPDX-Softwarestücklisten.

Azure Pipelines Trivy-Integration:

- script: |
    wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
    echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
    sudo apt-get update
    sudo apt-get install trivy

    trivy image \
      --severity HIGH,CRITICAL \
      --exit-code 1 \
      --no-progress \
      --format json \
      --output trivy-results.json \
      $(imageName):$(Build.BuildNumber)
  displayName: "Scan image with Trivy"

Snyk-Container

Snyk-Container bietet Containerimageüberprüfungen, integriert in die entwicklerorientierte Plattform von Snyk.

Wichtige Features:

  • Empfehlungen für Basisbilder: Schlägt alternative Basisimages mit weniger Sicherheitsrisiken vor.
  • Priorisierung: Priorisiert Sicherheitsrisiken basierend auf exploitability und business impact.
  • Behebungsleitfaden: Stellt spezifische Korrekturschritte für erkannte Sicherheitsrisiken bereit.
  • Kubernetes-Integration: Scannt Bilder, die in Kubernetes-Clustern bereitgestellt werden.

Aqua Security

Aqua Security bietet Containersicherheit auf Unternehmensniveau im gesamten Lebenszyklus.

Wichtige Features:

  • Bildüberprüfung: Umfassende Bildüberprüfung mit anpassbaren Richtlinien.
  • Laufzeitschutz: Überwacht laufende Container auf verdächtiges Verhalten.
  • Überprüfung der Einhaltung: Validiert Images anhand des CIS Docker Benchmarks und benutzerdefinierter Richtlinien.
  • Lieferkettensicherheit: Überprüft die Image-Provenienz und erkennt Supply Chain-Angriffe.

Anchore Engine

Anchore Engine ist ein Open-Source-Containerimagescanner mit richtlinienbasierter Analyse.

Wichtige Features:

  • Richtliniengesteuert: Flexibles Richtlinienmodul zum Definieren von Sicherheits- und Complianceregeln.
  • Tiefe Inspektion: Analysiert Bildebenen, Pakete und Konfigurationen.
  • Benutzerdefinierte Richtlinien: Definieren Sie organisationsspezifische Sicherheits- und Compliancerichtlinien.
  • API-gesteuert: REST-API für die Integration in benutzerdefinierte Tools.

GitHub Advanced Security

GitHub Advanced Security bietet Sicherheitsfeatures auf Unternehmensniveau für Repositorys, einschließlich Containerscanfunktionen.

Containersicherheitsmerkmale:

  • Abhängigkeitsscan: Erkennt automatisch anfällige Abhängigkeiten in Containerimages.
  • Geheimes Scannen: Identifiziert offengelegte Geheimschlüssel (API-Schlüssel, Token, Anmeldeinformationen) in Containerebenen und Dockerfiles.
  • Codescan: CodeQL-Analyse von Dockerfiles und Anwendungscode in Containern.
  • Sicherheitshinweise: Integration in die GitHub Advisory Database für Schwachstellenintelligenz.
  • Lieferkettensicherheit: Abhängigkeitsdiagramm und Dependabot-Integration für Containerabhängigkeiten.

Ausführen von CodeQL in Containern: GitHub Advanced Security unterstützt die Ausführung von CodeQL-Codeüberprüfungen in Containerumgebungen für eine umfassende Analyse:

Workflow zum Scannen von CodeQL-Containern:

name: CodeQL Container Analysis

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

jobs:
  analyze-container:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ["javascript", "python"]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v2
        with:
          languages: ${{ matrix.language }}
          queries: security-extended,security-and-quality

      - name: Build application in container
        run: |
          docker build -t app:latest .
          docker create --name temp-container app:latest
          docker cp temp-container:/app/built-artifacts ./artifacts
          docker rm temp-container

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v2
        with:
          category: "/language:${{ matrix.language }}"

      - name: Scan Dockerfile
        uses: github/codeql-action/analyze@v2
        with:
          category: "/language:dockerfile"

Geheimes Scannen nach Containern:

name: Container Secret Scanning

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

jobs:
  scan-secrets:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

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

      - name: Scan image for secrets
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.repository.default_branch }}
          head: HEAD

      - name: Scan container layers for secrets
        run: |
          docker save myapp:${{ github.sha }} -o image.tar
          docker run --rm -v $(pwd):/scan \
            trufflesecurity/trufflehog:latest \
            filesystem /scan/image.tar \
            --json > secrets-report.json

      - name: Upload secret scan results
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: secrets-report.sarif

Vorteile von GitHub Advanced Security:

  • Native Integration: Tief in GitHub-Workflows und Sicherheitsfeatures integriert.
  • Einheitliches Dashboard: Zentrale Sicherheitsübersicht auf der Registerkarte "GitHub-Sicherheit".
  • Richtlinienerzwingung: Branchenschutzregeln können das Bestehen von Sicherheitschecks erfordern.
  • Compliance-Berichterstattung: Eingebaute Compliance-Berichte für SOC 2, ISO 27001 und andere Rahmenwerke.
  • Teamzusammenarbeit: Sicherheitsergebnisse, die in Pull-Anforderungsüberprüfungen und Problemverfolgung integriert sind.

Aktivieren von GitHub Advanced Security:

Für Organisationen:

  1. Navigieren Sie zu den Organisationseinstellungen → Codesicherheit und -analyse.
  2. Aktivieren Sie GitHub Advanced Security für alle oder ausgewählte Repositorys.
  3. Konfigurieren Von Dependabot-Warnungen, geheimer Überprüfung und Codeüberprüfung.
  4. Einrichten von Sicherheitsrichtlinien und Sicherheitsempfehlungen.

Für Repositorys:

  1. Wechseln Sie zu Repositoryeinstellungen → Codesicherheit und -analyse.
  2. Aktivieren sie Abhängigkeitsdiagramm (kostenlos für öffentliche Repositorys).
  3. Aktivieren Von Dependabot-Warnungen und Dependabot-Sicherheitsupdates.
  4. Aktivieren der geheimen Überprüfung (erfordert GitHub Advanced Security-Lizenz für private Repositorys).
  5. Aktivieren Sie die Codeüberprüfung mit CodeQL- oder Drittanbietertools.

Erweiterte Sicherheit für Containerregistrierungen:

name: Registry Security Monitoring

on:
  schedule:
    - cron: "0 */6 * * *" # Every 6 hours
  workflow_dispatch:

jobs:
  scan-registry:
    runs-on: ubuntu-latest
    permissions:
      packages: read
      security-events: write

    steps:
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Pull images from registry
        run: |
          docker pull ghcr.io/${{ github.repository }}/app:latest
          docker pull ghcr.io/${{ github.repository }}/app:staging

      - name: Scan registry images
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "ghcr.io/${{ github.repository }}/app:latest"
          format: "sarif"
          output: "trivy-registry.sarif"

      - name: Upload scan results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: trivy-registry.sarif
          category: "registry-scan"

      - name: Check for critical vulnerabilities
        run: |
          CRITICAL_COUNT=$(docker run --rm \
            -v /var/run/docker.sock:/var/run/docker.sock \
            aquasec/trivy image \
            --severity CRITICAL \
            --format json \
            ghcr.io/${{ github.repository }}/app:latest | \
            jq '.Results[].Vulnerabilities | length')

          if [ "$CRITICAL_COUNT" -gt 0 ]; then
            echo "::error::Found $CRITICAL_COUNT critical vulnerabilities"
            exit 1
          fi

Integration mit GitHub-Sicherheitsfeatures:

  • Sicherheitsübersicht: Organisationsweites Sicherheitsdashboard mit Containerrisiken.
  • Sicherheitswarnungen: Automatisierte Warnungen für anfällige Containerabhängigkeiten.
  • Dependabot-Updates: Automatisierte Pullanforderungen zum Aktualisieren anfälliger Basisimages und Abhängigkeiten.
  • Integration von Codebesitzern: Leiten Sie Sicherheitsergebnisse über die CODEOWNERS-Datei an geeignete Teams weiter.
  • Audit-Protokolle: Vollständige Prüfspur von Sicherheitsereignissen und Behebungsmaßnahmen.

Bewährte Methoden für Container-Scans

Implementieren von mehrstufigen Builds

Separate Build- und Laufzeitabhängigkeiten:

# Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime stage
FROM node:18-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

Vorteile:

  • Kleinere Bilder: Laufzeitimages enthalten keine Buildtools und Zwischenartefakte.
  • Weniger Schwachstellen: Buildabhängigkeiten (Compiler, SDKs) sind in endgültigen Images nicht enthalten.
  • Bessere Leistung: Kleinere Bilder verschieben, ziehen und beginnen schneller.

Verwenden von minimalen Basisimages

Wählen Sie geeignete Basisbilder aus:

  • Alpin: Kleines Basisbild (~5 MB) mit minimaler Angriffsfläche.
  • Distroless: Enthält nur Anwendungs- und Laufzeitabhängigkeiten, keine Shell oder Paketmanager.
  • Schlanke Varianten: Offizielle *-slim-Varianten schließen unnötige Hilfsprogramme aus.
  • Bestimmte Versionen: Verwenden Sie bestimmte Versionstags anstelle von latest, um die Reproduzierbarkeit zu gewährleisten.

Beispiel für ein distroless Abbild:

FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM gcr.io/distroless/static-debian11
COPY --from=builder /app/myapp /
USER nonroot:nonroot
CMD ["/myapp"]

Frühzeitig und häufig scannen

Scanhäufigkeit:

  • Entwicklerarbeitsstation: Scannen Sie Bilder lokal, bevor Sie die Änderungen übernehmen.
  • Pull Request-Überprüfung: Überprüfen Sie in CI-Pipelines auf jeden Pull Request.
  • Mainbranch-Builds: Umfassende Überprüfungen auf Mainbranch-Zusammenführungen.
  • Aufnahme in die Registrierung: Überprüfen Sie Images, bevor Sie dies in Registrierungen akzeptieren.
  • Geplante erneute Überprüfung: In regelmäßigen Abständen werden gespeicherte Bilder nach neu offengelegten Sicherheitsrisiken erneut überprüft.
  • Vor der Bereitstellung: Endgültige Überprüfung vor der Bereitstellung in der Produktion.

Implementieren von Sicherheitstoren

Kontrollpunkte für Richtliniendurchsetzung:

- task: Trivy@1
  inputs:
    image: "$(imageName):$(Build.BuildNumber)"
    severityThreshold: "HIGH"
    exitCode: 1
  displayName: "Security gate: block high/critical vulnerabilities"

Gate-Beispiele:

  • Schweregrad der Sicherheitsanfälligkeit: Fehler bei Builds mit kritischen oder schwerwiegenden Sicherheitsrisiken.
  • Lizenzcompliance: Blockieren von Bildern mit verbotenen Lizenzen.
  • Konfigurationsprobleme: Verhindern Sie der Bereitstellung von Images, die als Stamm ausgeführt werden.
  • Geheimerkennung: Fehler, wenn Geheimnisse in Bildebenen erkannt werden.

Automatisieren der Wartung

Automatisierte Updates:

  • Dependabot für Dockerfiles: Aktivieren Sie Dependabot, um Basisimageversionen und Abhängigkeiten in Dockerfiles zu aktualisieren.
  • Automatisierte Neuerstellungen: Konfigurieren Sie Pipelines, um Bilder automatisch neu zu erstellen, wenn Basisimages aktualisiert werden.
  • Patchautomatisierung: Verwenden Sie Tools, um Basisimages oder Abhängigkeiten automatisch zu patchen.
  • Testen von Pipelines: Stellen Sie sicher, dass automatisierte Updates umfassende Tests auslösen.

GitHub Dependabot-Konfiguration für Docker:

version: 2
updates:
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 5

Verwalten des Scanergebnisverlaufs

Tracking und Trending-Funktionen:

  • Zentralisierte Berichterstellung: Aggregierte Scanergebnisse in zentralisierten Dashboards.
  • Trendanalyse: Verfolgen Sie die Sicherheitsrisikoanzahl im Laufe der Zeit, um den Sicherheitsstatus zu messen.
  • Compliance-Prüfungen: Verwalten des Scanergebnisverlaufs für Nachweise zur Compliance.
  • SBOM-Archivierung: Archivieren Sie Softwarestücklisten für bereitgestellte Images.

Implementieren der Imagesignierung

Überprüfen Sie die Bild-Provenienz:

- task: Docker@2
  inputs:
    command: "sign"
    arguments: "--key $(signingKey) $(imageName):$(Build.BuildNumber)"
  displayName: "Sign container image"

- script: |
    docker trust inspect --pretty $(imageName):$(Build.BuildNumber)
  displayName: "Verify image signature"

Vorteile der Bildsignierung:

  • Überprüfung der Provenienz: Bestätigen Sie, dass Bilder von vertrauenswürdigen Quellen stammen.
  • Manipulationserkennung: Erkennen, ob Bilder nach dem Signieren geändert wurden.
  • Durchsetzung von Richtlinien: Bereiten Sie nur signierte Images für Produktionsumgebungen bereit.

Durch die Automatisierung von Containerimagescans über den Entwicklungs- und Bereitstellungslebenszyklus hinweg wird eine umfassende Erkennung von Sicherheitsrisiken und die Durchsetzung von Richtlinien sichergestellt. Durch frühzeitiges Scannen, häufiges Scannen und die Implementierung automatisierter Behebungen können Organisationen sichere Containerbereitstellungen verwalten, ohne auf Entwicklungsgeschwindigkeit zu verzichten. In der nächsten Lektion wird untersucht, wie Warnungen von Sicherheitsscannertools interpretiert und priorisiert werden.