← Blog / DevSecOps

Trivy w pipeline CI/CD — skanowanie obrazów Dockera automatycznie

Wprowadzenie

Podatna biblioteka w obrazie Docker to bomba z opóźnionym zapłonem. Może trafić na produkcję niezauważona i czekać miesiącami — do momentu gdy ktoś ją wykorzysta. Rozwiązaniem jest automatyczne skanowanie każdego obrazu przed deploymentem. Trivy robi to w ciągu kilkudziesięciu sekund i integruje się z każdym popularnym systemem CI/CD.


Co skanuje Trivy?

Trivy skanuje:
├── Obrazy Docker
│   ├── Podatności w pakietach systemowych (apt, rpm, apk)
│   ├── Podatności w bibliotekach aplikacyjnych (pip, npm, gem, go)
│   └── Sekrety i hasła zakodowane na stałe
├── Pliki konfiguracyjne Kubernetes
│   ├── Brak limitów zasobów
│   ├── Kontenery uruchamiane jako root
│   └── Privileged containers
└── Repozytoria Git
    └── Sekrety w historii commitów

Integracja z GitLab CI

Podstawowa integracja — blokowanie pipeline’u

variables:
  IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

stages:
  - build
  - security
  - deploy

build-image:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_NAME .
    - docker push $IMAGE_NAME

trivy-scan:
  stage: security
  image:
    name: aquasec/trivy:0.48.3
    entrypoint: [""]
  variables:
    TRIVY_USERNAME: $CI_REGISTRY_USER
    TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
    TRIVY_AUTH_URL: $CI_REGISTRY
    TRIVY_CACHE_DIR: .trivy-cache
  cache:
    paths:
      - .trivy-cache/
  script:
    - trivy image
        --exit-code 1
        --severity CRITICAL,HIGH
        --no-progress
        $IMAGE_NAME
  allow_failure: false

deploy-production:
  stage: deploy
  needs:
    - trivy-scan
  script:
    - echo "Deploy tylko jeśli trivy-scan przeszedł"

Rozbudowana integracja z raportami

trivy-scan-full:
  script:
    - trivy image
        --format template
        --template "@/contrib/gitlab.tpl"
        --output gl-container-scanning-report.json
        $IMAGE_NAME

    - trivy image
        --format template
        --template "@/contrib/html.tpl"
        --output trivy-report.html
        $IMAGE_NAME

  artifacts:
    when: always
    reports:
      container_scanning: gl-container-scanning-report.json
    paths:
      - trivy-report.html

Integracja z GitHub Actions

name: Security Scan

on:
  push:
    branches: [ main, develop ]

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

    steps:
      - uses: actions/checkout@v4

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

      - name: Run Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          severity: CRITICAL,HIGH
          exit-code: 1

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

Wykrywanie sekretów

trivy fs --scanners secret .

# W pipeline:
trivy-secret-scan:
  script:
    - trivy fs --scanners secret --exit-code 1 --severity CRITICAL,HIGH .

Wyjątki — ignorowanie fałszywych alarmów

# .trivyignore
CVE-2023-12345  # false positive — biblioteka nie jest używana
CVE-2023-67890  # oczekuje na fix upstream

Polityka progów

SeverityAkcja w pipeline
CRITICALBlokuj — brak deployu
HIGHBlokuj (zalecane)
MEDIUMOstrzeżenie
LOWInformacja w raportach

Podsumowanie

Integracja Trivy z pipeline’em to jeden z najlepszych zwrotów z inwestycji w bezpieczeństwo — kilkanaście linii konfiguracji eliminuje całą klasę podatności. Kluczowe zasady:

  • Skanuj każdy obraz przed deploymentem
  • Blokuj pipeline na CRITICAL — zawsze
  • Używaj cache bazy podatności — przyspiesza skany z ~2min do ~15s
  • Integruj raporty z GitLab Security Dashboard lub GitHub Security