Перейти к содержанию

Trivy-сканирование образов в CI

CI/CD · Security
Изучено

Проблема

Команда собирает Docker-образы, пушит в registry, деплоит в production. Про CVE узнаём, когда security-ресёрчер присылает письмо или когда утром приходит алерт от внешнего сканера. Образ с уязвимым openssl живёт в проде неделями.

Решение

Встроить Trivy в CI-пайплайн как обязательный шаг между docker build и docker push. Билд падает, если найдены HIGH/CRITICAL уязвимости с фиксом — это заставляет обновлять base images, а не игнорировать.

Сам сканер — тоже зависимость с доступом к секретам CI. Action закрепляется по полному SHA коммита, образ — по digest, версия Trivy указывается явно.

Компрометация Trivy, март 2026

19 марта 2026 года вышел вредоносный Trivy v0.69.4, 22 марта — вредоносные образы v0.69.5 и v0.69.6; 75 тегов trivy-action и теги setup-trivy были переписаны на коммиты, крадущие секреты раннера. Затронутыми считаются запуски CI с 19 по 23 марта. Если в этот период Trivy работал в CI по тегу — ротировать все секреты, доступные этим job. Подробности: CSA, SafeDep.

Пример

GitHub Actions:

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

- name: Scan with Trivy
  # v0.36.0, закреплено по SHA: тег можно переписать, коммит — нет
  uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25
  with:
    version: v0.76.1            # версия Trivy явно, не latest
    image-ref: myapp:${{ github.sha }}
    severity: HIGH,CRITICAL
    ignore-unfixed: true        # не шуметь на CVE без патча
    exit-code: 1                # ломать билд
    format: sarif
    output: trivy.sarif

- name: Upload SARIF
  if: always()
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: trivy.sarif     # видно в GitHub Security tab

GitLab CI — образ сканера по digest:

# .gitlab-ci.yml
trivy:
  stage: test
  image:
    # digest индекса 0.76.1 по Docker Hub на 2026-10-29; при обновлении взять новый:
    # docker buildx imagetools inspect aquasec/trivy:<версия>
    name: aquasec/trivy:0.76.1@sha256:790fd66d1697395d8693d1acaa1ea702406a20f109b6fc7bac8db623eca6c06c
    entrypoint: [""]
  script:
    - trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"

Локально перед пушем:

trivy image --severity HIGH,CRITICAL --ignore-unfixed myapp:dev

Когда применять

  • Любой репозиторий с Dockerfile, образ которого попадает в production.
  • Перед релизом base-образа — как gate, не как отчёт.

Источник

Как применить у себя

  1. Добавить шаг Trivy в CI, severity HIGH,CRITICAL, ignore-unfixed: true; action — по SHA, образ — по digest.
  2. Первый прогон: выписать список текущих CVE в issue, починить или осознанно заигнорить через .trivyignore.
  3. Включить exit-code: 1 и сделать job обязательным для merge.
  4. Когда первый PR упадёт на реальной CVE и команда починит base-образ — статус Изучено.