Trivy для DevSecOps: сканирование контейнеров, IaC и SBOM в CI/CD 2026

Trivy 0.65+ для DevSecOps: сканирование контейнеров, Terraform и Kubernetes YAML, генерация SBOM (CycloneDX, SPDX), поиск секретов и готовые пайплайны для GitHub Actions, GitLab CI и Trivy Operator.

Trivy DevSecOps: CVE, IaC и SBOM (2026)

Обновлено: 2 июля 2026

Trivy, это open-source сканер уязвимостей от Aqua Security, который находит CVE в образах контейнеров, файловых системах, Git-репозиториях, Kubernetes-кластерах и IaC-манифестах, а также генерирует SBOM в форматах CycloneDX и SPDX. В моей практике архитектора инфраструктурной безопасности Trivy стал стандартом левого сдвига (shift-left): один бинарник закрывает сканирование образов, Terraform, Kubernetes YAML, секретов и лицензий, что позволяет свести всё в один этап CI/CD пайплайна. Честно говоря, после того как я собрал десяток таких пайплайнов, других вариантов почти не рассматриваю. В этой статье покажу production-конфигурацию Trivy 0.65+, интеграции с GitHub Actions и GitLab CI, а также как выстроить модель угроз вокруг результатов сканирования.

  • Trivy сканирует контейнерные образы, файловые системы, Git-репозитории, Kubernetes-кластеры, IaC (Terraform, CloudFormation, Helm) и генерирует SBOM в форматах CycloneDX 1.5 и SPDX 2.3.
  • База уязвимостей trivy-db обновляется каждые 6 часов и агрегирует данные из NVD, Red Hat, Ubuntu, Alpine secdb, GitHub Security Advisories и OSV.
  • Для CI/CD критично использовать флаги --severity HIGH,CRITICAL и --exit-code 1, иначе билд не будет падать на находках.
  • Trivy Operator в Kubernetes даёт непрерывное сканирование workload'ов и публикует результаты как CRD (VulnerabilityReport, ConfigAuditReport).
  • Против Grype и Snyk Trivy выигрывает по покрытию (IaC, SBOM и secrets в одном инструменте) и по цене (полностью open-source).
  • Для production критично кэшировать trivy-db в CI и использовать --skip-db-update с offline-режимом, иначе rate-limit GHCR приведёт к flake-билдам.

Что такое Trivy и зачем он нужен

Trivy, это универсальный сканер безопасности, написанный на Go и распространяемый как один статически слинкованный бинарник. В отличие от узкоспециализированных инструментов, он покрывает пять смежных доменов: контейнерные образы (OS packages плюс language libraries), файловые системы, Git-репозитории, IaC (Terraform, CloudFormation, Kubernetes YAML, Helm, Dockerfile) и Kubernetes-кластеры. Плюс отдельно ищет секреты по regex-правилам и генерирует SBOM.

Ключевое преимущество для DevSecOps в том, что у вас появляется единая точка интеграции в пайплайн. Раньше приходилось цеплять Grype для образов, Checkov для Terraform, gitleaks для секретов и Syft для SBOM. Trivy 0.65+ делает всё это одним вызовом с одним exit-кодом. Для команд, где security-инженер сопровождает 50+ репозиториев, это радикально снижает поверхность конфигурационных ошибок в CI.

С точки зрения threat model Trivy закрывает часть pre-deployment, то есть работает до того, как образ попадёт в registry или манифест применится в кластере. Runtime-угрозы (эксплуатация 0-day в уже развёрнутом приложении) остаются за Falco и eBPF-детекцией угроз в реальном времени, а корреляция событий безопасности за Wazuh SIEM с агентами и FIM. Эти три инструмента вместе дают приличное покрытие цепочки defense-in-depth.

Как установить Trivy на Linux

Trivy устанавливается через официальные репозитории для Debian/Ubuntu, RHEL/Fedora, Amazon Linux и Arch. Не советую тащить бинарник из GitHub Releases в production, теряется контроль версий и подписи APT/RPM. Ниже, production-совместимая установка на Ubuntu 24.04.

# Ubuntu / Debian, установка через официальный APT-репозиторий
sudo apt-get install -y wget apt-transport-https gnupg lsb-release

wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
    sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg

echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] \
    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 -y trivy

# Проверка версии, на июль 2026 актуальна 0.65.x
trivy --version

Для RHEL 9 / Rocky Linux 9 / AlmaLinux 9 используется DNF-репозиторий:

sudo tee /etc/yum.repos.d/trivy.repo <<'EOF'
[trivy]
name=Trivy repository
baseurl=https://aquasecurity.github.io/trivy-repo/rpm/releases/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://aquasecurity.github.io/trivy-repo/rpm/public.key
EOF

sudo dnf install -y trivy

Сканирование образов контейнеров

Базовый вызов, trivy image <image>. Но в production почти никогда не хочется дефолтного вывода: он показывает низкие и unknown severity, не падает при находках и качает базу CVE прямо из GHCR при каждом запуске. Ниже, production-конфигурация, которую я применяю в пайплайнах.

# Скачиваем базу заранее, отдельно от сканирования
trivy image --download-db-only

# Сканирование с production-флагами
trivy image \
    --severity HIGH,CRITICAL \
    --ignore-unfixed \
    --exit-code 1 \
    --skip-db-update \
    --scanners vuln,secret \
    --format sarif \
    --output trivy-report.sarif \
    --timeout 10m \
    myregistry.example.com/myapp:1.2.3

Разберём флаги. Каждый закрывает конкретную failure mode:

  • --severity HIGH,CRITICAL, режем шум. LOW/MEDIUM в базовом образе Debian обычно уязвимости, которые вы не можете исправить без пересборки upstream, и они блокируют пайплайн зря.
  • --ignore-unfixed, исключаем CVE, для которых upstream ещё не выпустил патч. Ловить такие, это работа Wazuh на runtime, а не сканера образов.
  • --exit-code 1, БЕЗ этого билд не упадёт, даже если найдено 500 CRITICAL. Классический footgun, я на нём обжигался в первый же месяц использования Trivy.
  • --skip-db-update, комбинируется с предварительным --download-db-only. GHCR имеет rate-limit 60 anonymous pulls в час на IP, что в parallel-CI гарантированно даёт flake.
  • --format sarif, для загрузки в GitHub Security tab через github/codeql-action/upload-sarif.

Сканирование IaC: Terraform, Kubernetes, Helm

Trivy умеет статически анализировать конфигурационные файлы на misconfiguration. Это функциональность, унаследованная от Aqua tfsec/CloudSploit. Правила покрывают AWS/GCP/Azure Terraform, Kubernetes манифесты, Helm charts, Dockerfile, CloudFormation и Ansible.

# Сканирование директории с Terraform-манифестами
trivy config \
    --severity HIGH,CRITICAL \
    --exit-code 1 \
    --format table \
    ./infrastructure/terraform/

# Сканирование Kubernetes YAML + Helm chart
trivy config \
    --helm-values-file values.production.yaml \
    --severity HIGH,CRITICAL \
    --exit-code 1 \
    ./charts/myapp/

# Только определённые проверки (misconfig-ID)
trivy config \
    --check-namespaces kubernetes,docker \
    --severity CRITICAL \
    ./manifests/

Типичные находки, которые Trivy ловит в Kubernetes YAML: контейнеры без runAsNonRoot: true, отсутствие readOnlyRootFilesystem, привилегированные поды, hostPath-монтирования, отсутствие resource limits. В Terraform это публичные S3-бакеты, security groups с 0.0.0.0/0 на 22 порту, отсутствие encryption at rest, IAM-политики с Action: "*".

Для подавления заведомо ложных срабатываний используйте .trivyignore в корне репозитория или встроенные комментарии #trivy:ignore:AVD-KSV-0021 прямо в YAML. Не подавляйте оптом целые категории, это слепое пятно, которое рано или поздно даст инцидент. У меня однажды именно так проехал misconfig с privileged: true в тестовом namespace, который затем внезапно оказался в production.

Генерация SBOM в форматах CycloneDX и SPDX

SBOM (Software Bill of Materials) сейчас обязательное требование NIST SSDF, EU CRA (Cyber Resilience Act, вступил в силу декабрь 2025) и Executive Order 14028 в США. Trivy генерирует SBOM в двух основных стандартах.

# CycloneDX 1.5, рекомендую как основной формат
trivy image \
    --format cyclonedx \
    --output sbom-cyclonedx.json \
    myapp:1.2.3

# SPDX 2.3, если этого требует контракт с заказчиком
trivy image \
    --format spdx-json \
    --output sbom-spdx.json \
    myapp:1.2.3

# SBOM для файловой системы (не образа), полезно для monorepo
trivy fs \
    --format cyclonedx \
    --output sbom.json \
    ./

Готовый SBOM можно повторно скормить Trivy для сканирования без исходного образа. Это критично, когда вы хотите отслеживать новые CVE в уже задеплоенных релизах без пересборки: trivy sbom sbom-cyclonedx.json --severity HIGH,CRITICAL. Такой подход мы используем для post-deployment мониторинга: SBOM хранится в S3 с версионированием, cron раз в 6 часов запускает Trivy против всех SBOM и публикует delta в SIEM. Это тот же паттерн, что мы применяем при hardening ядра Linux через sysctl: фиксируешь baseline и следишь за отклонениями.

Поиск секретов и приватных ключей

Модуль secret в Trivy включён по умолчанию и использует те же regex-правила, что и gitleaks. Он ищет AWS/GCP/Azure ключи, GitHub PAT, Stripe-токены, приватные ключи RSA/OpenSSH, JWT, Slack tokens и ещё около 40 паттернов.

# Сканирование только на секреты (быстрее)
trivy fs --scanners secret --severity HIGH,CRITICAL ./

# Сканирование образа на встроенные секреты, часто попадает
# в COPY .env / .aws/credentials по невнимательности
trivy image --scanners secret myapp:1.2.3

# Кастомные правила через YAML
trivy fs \
    --scanners secret \
    --secret-config .trivy-secret.yaml \
    ./

Пример кастомного правила для внутренних API-ключей вашей компании:

# .trivy-secret.yaml
rules:
  - id: internal-api-key
    category: internal
    title: Внутренний API-ключ компании
    severity: CRITICAL
    regex: 'ACME_API_[A-Z0-9]{32}'
    keywords:
      - ACME_API_
allow-rules:
  - id: test-fixtures
    description: Тестовые фикстуры содержат dummy-значения
    path: 'tests/fixtures/.*'

Интеграция Trivy в GitHub Actions

Официальный action aquasecurity/trivy-action закрывает 90% сценариев. Ниже конфигурация, которую я использую в production: с кэшированием базы, SARIF-загрузкой в Security tab и разделением image/config/secret сканов на отдельные шаги для читаемости в UI.

# .github/workflows/security.yml
name: Security Scan
on:
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 4 * * *'  # nightly audit-run

jobs:
  trivy:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      security-events: write  # для upload-sarif
    steps:
      - uses: actions/checkout@v4

      - name: Cache Trivy DB
        uses: actions/cache@v4
        with:
          path: ~/.cache/trivy
          key: trivy-db-${{ github.run_id }}
          restore-keys: trivy-db-

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

      - name: Trivy image scan
        uses: aquasecurity/[email protected]
        with:
          image-ref: myapp:${{ github.sha }}
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          exit-code: '1'
          format: sarif
          output: trivy-image.sarif
          scanners: vuln,secret

      - name: Trivy config scan
        uses: aquasecurity/[email protected]
        with:
          scan-type: config
          scan-ref: ./
          severity: HIGH,CRITICAL
          exit-code: '1'
          format: sarif
          output: trivy-config.sarif

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-image.sarif
          category: trivy-image

Интеграция Trivy в GitLab CI

В GitLab два пути: использовать встроенный Container-Scanning.gitlab-ci.yml template (он под капотом крутит Trivy) или свою конфигурацию с большим контролем. Для production я предпочитаю второе.

# .gitlab-ci.yml
stages:
  - build
  - scan

variables:
  TRIVY_VERSION: "0.65.0"
  TRIVY_CACHE_DIR: ".trivycache/"
  TRIVY_NO_PROGRESS: "true"

trivy_image_scan:
  stage: scan
  image:
    name: ghcr.io/aquasecurity/trivy:${TRIVY_VERSION}
    entrypoint: [""]
  cache:
    key: trivy-db
    paths:
      - .trivycache/
  before_script:
    - trivy image --download-db-only
  script:
    - trivy image
        --severity HIGH,CRITICAL
        --ignore-unfixed
        --exit-code 1
        --skip-db-update
        --format template
        --template "@contrib/gitlab.tpl"
        --output gl-container-scanning-report.json
        $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  artifacts:
    reports:
      container_scanning: gl-container-scanning-report.json
    expire_in: 1 week
  allow_failure: false

Формат gitlab.tpl критичен: только он даёт нативную визуализацию находок в MR через вкладку Security. Без него результаты будут лежать в артефакте, и никто их не увидит.

Trivy Operator для Kubernetes

Trivy Operator это CNCF Sandbox-проект, который непрерывно сканирует workload'ы в кластере и публикует результаты как Kubernetes CRD. Это закрывает продакшн-разрыв: пайплайн сканирует то, что вы собираетесь задеплоить, а Operator то, что уже работает, включая CVE, появившиеся после деплоя.

# Установка через Helm
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm install trivy-operator aqua/trivy-operator \
    --namespace trivy-system \
    --create-namespace \
    --version 0.24.0 \
    --set trivy.ignoreUnfixed=true \
    --set trivy.severity=HIGH,CRITICAL \
    --set operator.scanJobsConcurrentLimit=5

# Просмотр отчётов
kubectl get vulnerabilityreports -A
kubectl get configauditreports -A
kubectl get exposedsecretreports -A
kubectl get rbacassessmentreports -A

Отчёты можно экспортировать в Prometheus через встроенный metrics-endpoint и завести алерты через Alertmanager при появлении новой CRITICAL-уязвимости на production-неймспейсе. В связке с Falco для runtime-детекции угроз это даёт двухслойную защиту: Trivy Operator ловит known-CVE, Falco ловит попытки эксплуатации.

Сравнение: Trivy vs Grype vs Snyk vs Clair

Четыре инструмента, которые чаще всего рассматривают вместе. Ниже сравнение по параметрам, важным для production DevSecOps.

ПараметрTrivyGrypeSnykClair
ЛицензияApache 2.0Apache 2.0Проприетарная (freemium)Apache 2.0
СтоимостьБесплатноБесплатноОт $25/dev/месБесплатно
Сканирование образовДаДаДаДа
IaC сканированиеДа (TF/K8s/CFN/Helm)НетДа (Snyk IaC)Нет
Поиск секретовДа (встроен)НетДаНет
Генерация SBOMДа (CycloneDX и SPDX)Да (через Syft)ДаНет
K8s OperatorДа (CNCF Sandbox)НетSnyk ControllerТребует API
Скорость (образ 500MB)~15 сек~12 сек~30 сек (API)~40 сек

Мой выбор для 95% сценариев это Trivy. Grype от Anchore быстрее на пару секунд и глубже парсит Java-зависимости, но не покрывает IaC и секреты, что для DevSecOps ключевое ограничение. Snyk удобнее для команд, готовых платить за приоритизацию рисков и Reachability Analysis, но лок-ин на облачный API это красный флаг для регулируемых индустрий. Clair исторически используется в Quay/OpenShift, но за пределами Red Hat-экосистемы редко оправдан.

Модель угроз и что ломается первым

Trivy закрывает не всё. Я предпочитаю явно проговаривать blast radius каждого инструмента, чтобы не строить ложное чувство безопасности.

Что Trivy НЕ покрывает: runtime-эксплуатацию, side-channel атаки, логические уязвимости приложения (SQL injection, IDOR, SSRF, это работа DAST/SAST), zero-day до появления в NVD, уязвимости во внутренних форках (если вы не публикуете свой advisory-feed). Также Trivy не аутентифицирует источник образа, supply chain защиту делают Cosign и SLSA framework.

Что ломается первым в CI-пайплайне: в моей практике top-3 отказа это rate-limit на скачивание trivy-db (решается кэшированием), timeout при сканировании образов больше 2GB (решается --timeout 30m и Slim-образами), false positive на unfixed CVE в базовом образе (решается --ignore-unfixed плюс weekly audit-run). Если у вас пайплайн падает еженедельно из-за flake, не отключайте сканер, а стабилизируйте пайплайн, иначе команда научится игнорировать security-этап.

Про интеграцию advisory-feed: в 2026 Trivy умеет тянуть private advisories из VEX (Vulnerability Exploitability eXchange) в форматах CSAF 2.0 и OpenVEX. Это позволяет команде security по внутренним данным помечать CVE как not_affected с обоснованием, и Trivy автоматически исключит их из отчётов CI. Незаменимо для монорепо с сотнями Go-модулей, где upstream-CVE в 80% случаев неприменим к вашему use case.

Часто задаваемые вопросы

В чём разница между Trivy и Grype?

Trivy покрывает больше доменов: IaC, секреты и SBOM в одном бинарнике. Grype фокусируется только на образах и файловых системах, но парсит Java (Maven) и Go-модули чуть глубже и работает на 15–20% быстрее на больших образах. Для DevSecOps-пайплайна выбирайте Trivy, для узкой задачи "просканировать образ в один шаг" подходит Grype.

Как обновляется база уязвимостей Trivy?

База trivy-db публикуется в GHCR каждые 6 часов и агрегирует данные из NVD, GitHub Security Advisories, дистрибутивных feed'ов (Red Hat OVAL, Ubuntu USN, Alpine secdb, Debian Security Tracker) и OSV. Trivy автоматически скачивает её при первом запуске и обновляет каждые 24 часа. В CI используйте --download-db-only в отдельном шаге и кэшируйте директорию ~/.cache/trivy.

Как настроить severity threshold в Trivy?

Через флаг --severity CRITICAL,HIGH (список уровней через запятую) плюс --exit-code 1, чтобы билд падал. Без --exit-code Trivy выведет находки, но вернёт 0, и пайплайн не заметит проблемы. Для audit-запусков рекомендую отдельный джоб без threshold, который просто складывает полный SARIF в артефакты для еженедельного review.

Можно ли использовать Trivy оффлайн?

Да. Скачайте базу командой trivy image --download-db-only на машине с интернетом, перенесите директорию ~/.cache/trivy в air-gapped окружение и запускайте сканирование с флагом --skip-db-update. Для полностью автономных инсталляций можно поднять свой mirror trivy-db через oras и OCI-registry.

Заменяет ли Trivy runtime-инструменты вроде Falco?

Нет. Trivy это pre-deployment сканер: он находит известные CVE и misconfiguration в образах и манифестах до деплоя. Runtime-угрозы (эксплуатация 0-day, необычное поведение процессов, доступ к чувствительным файлам) закрывает Falco через eBPF-трейсинг syscalls. Эти инструменты дополняют друг друга и оба должны быть в защите продакшена.

Aisha Okonkwo
Об авторе Aisha Okonkwo

Infrastructure security architect at a hyperscaler. Spends her days on Zero Trust, secrets management, and yelling at unencrypted backups.