Trivy Operator в Kubernetes: непрерывное сканирование уязвимостей

Published: 2026-02-26

trivy image в CI ловит уязвимости на этапе сборки. Но что с образами, которые уже работают в продакшене и месяц назад были чистыми? Trivy Operator непрерывно сканирует все рабочие нагрузки в кластере и публикует результаты в виде Kubernetes-ресурсов — с метриками Prometheus для алертов.


Установка через Helm / FluxCD

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: trivy-operator
spec:
  interval: 1h
  chart:
    spec:
      chart: trivy-operator
      version: "0.x"
      sourceRef:
        kind: HelmRepository
        name: aquasecurity
        namespace: flux-system
  values:
    operator:
      vulnerabilityScannerEnabled: true
      configAuditScannerEnabled: true
      rbacAssessmentScannerEnabled: true
      infraAssessmentScannerEnabled: true
      metricsVulnIdEnabled: true
      scanJobsConcurrentLimit: 2
    trivy:
      ignoreUnfixed: true
      mode: Standalone
      severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL
    serviceMonitor:
      enabled: true
      labels:
        release: kube-prom-stack
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 1000m
        memory: 2048Mi

ignoreUnfixed: true критически важен: уязвимости без исправлений неустранимы. Без этого дашборды забиваются тысячами CVE, с которыми ничего нельзя сделать.

scanJobsConcurrentLimit: 2 — без лимита оператор при первой установке одновременно запускает по одной джобе на каждую рабочую нагрузку и перегружает ноды.

mode: Standalone — Trivy скачивает базу уязвимостей прямо в джобе сканирования. Для изолированных (air-gapped) окружений используйте ClientServer.


Что сканируется

Оператор создаёт джобы сканирования для отчётов:

  • VulnerabilityReport — CVE в образах (на каждый контейнер в поде)
  • ConfigAuditReport — небезопасные настройки Kubernetes (нет securityContext, privileged-контейнеры и т.д.)
  • RbacAssessmentReport — избыточно широкие RBAC-роли
  • InfraAssessmentReport — проверки hardening для control plane
bashkubectl get vulnerabilityreport -A
kubectl get configauditreport -A
kubectl get rbacassessmentreport -A

Результаты хранятся как Kubernetes CRD в том же неймспейсе, что и рабочая нагрузка, и обновляются каждые 24 часа.


Чтение VulnerabilityReport

bash# Сводка
kubectl get vulnerabilityreport -n app my-app-deployment-my-container \
  -o jsonpath='{.report.summary}'
json{"criticalCount":0,"highCount":3,"lowCount":47,"mediumCount":12}

Детали HIGH CVE:

bashkubectl get vulnerabilityreport -n app my-app-deployment-my-container \
  -o json | jq '.report.vulnerabilities[] | select(.severity=="HIGH") | {id: .vulnerabilityID, pkg: .resource, fixed: .fixedVersion}'

Метрики Prometheus и алерты

promql# CRITICAL CVE по всем рабочим нагрузкам
sum(trivy_image_vulnerabilities{severity="CRITICAL"}) by (namespace, resource_name)
yaml- alert: TrivyCriticalVulnerabilities
  expr: sum(trivy_image_vulnerabilities{severity="CRITICAL"}) by (namespace, resource_name) > 0
  for: 10m
  labels:
    severity: high
  annotations:
    summary: "{{ $labels.resource_name }} в {{ $labels.namespace }}: {{ $value }} CRITICAL CVE"
    description: "Обновите базовый образ или добавьте .trivyignore для принятых рисков"

- alert: TrivyConfigAuditFailed
  expr: trivy_resource_configaudits{severity="CRITICAL"} > 0
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Config audit: критическая находка в {{ $labels.resource_name }}"

Дашборд Grafana: ID 17813 (Trivy Operator - Vulnerabilities Dashboard).


CI vs Trivy Operator: нужны оба

CI ловит уязвимости до попадания в продакшен. Оператор ловит то, что появляется после деплоя:

  • В ОС базового образа нашли новый CVE, а пересборки не было
  • Зависимость из работающего образа только что добавили в NVD
  • Новая рабочая нагрузка развёрнута мимо CI (хотфикс, ручной kubectl apply)

Не выбирайте — запускайте оба.


Trivy в GitLab CI

yamltrivy-scan:
  image: aquasec/trivy:latest
  script:
    - trivy image
        --format json
        --output trivy-report.json
        --severity HIGH,CRITICAL
        --exit-code 1
        registry.example.com/myapp:$CI_COMMIT_SHORT_SHA
  artifacts:
    reports:
      container_scanning: trivy-report.json
    when: always

--exit-code 1 останавливает пайплайн с ошибкой при находках HIGH или CRITICAL. Известные ложные срабатывания подавляются так:

# .trivyignore
# Известный false-positive, исправления нет (2026-02-26)
CVE-2023-12345

Коммитьте файл рядом с Dockerfile — так подавление на виду и его легко проверить при аудите.


Исключение namespace

yamlvalues:
  operator:
    excludeNamespaces: "kube-system,flux-system,cert-manager"

Это снижает шум и убирает лишние джобы сканирования для инфраструктурных компонентов.