DefectDojo в Kubernetes: централизованное хранение результатов проверок безопасности

Published: 2026-03-05

CI-пайплайны генерируют отчёты по безопасности: SAST от SonarQube, сканирование контейнеров через Trivy, аудит зависимостей с OWASP Dependency-Check. Без единого места, где находки агрегируются, дедуплицируются и отслеживаются, они оседают во вкладках артефактов, на которые никто не смотрит. DefectDojo — именно такое место.


Что делает DefectDojo

  • Импортирует отчёты из более чем 100 форматов сканеров (Trivy JSON, SonarQube, Bandit, npm audit и т.д.)
  • Дедуплицирует находки между сканами (один CVE в одном компоненте → одна запись)
  • Отслеживает статус: Active, Mitigated, False Positive, Accepted Risk
  • Контролирует SLA по критичности (Critical: 7 дней, High: 30 дней, Medium: 90 дней)
  • REST API для интеграции с CI
  • Уведомления при нарушении SLA

Развёртывание через FluxCD HelmRelease

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: defectdojo
  namespace: defectdojo
spec:
  interval: 1h
  timeout: 30m
  chart:
    spec:
      chart: defectdojo
      version: "1.x"
      sourceRef:
        kind: HelmRepository
        name: defectdojo
        namespace: flux-system
  values:
    tag: latest
    createSecret: true
    createValkeySecret: true
    createPostgresqlSecret: true
    postgresql:
      enabled: true
    django:
      uwsgi:
        livenessProbe:
          enabled: true
          initialDelaySeconds: 120
          periodSeconds: 10
        readinessProbe:
          enabled: true
          initialDelaySeconds: 120
          periodSeconds: 5

initialDelaySeconds: 120 необходим: DefectDojo запускает Django-миграции при старте, что занимает 1–2 минуты. Без этого probe убивает под до завершения миграций.


Получение пароля администратора

bashkubectl get secret defectdojo \
  -n defectdojo \
  -o jsonpath='{.data.DD_ADMIN_PASSWORD}' | base64 -d

Войдите на https://defectdojo.example.com под пользователем admin. Сразу создайте для повседневной работы отдельную учётную запись без прав администратора.


Интеграция с CI: отправка результатов Trivy

yaml# .gitlab-ci.yml
trivy-scan:
  image: aquasec/trivy:latest
  script:
    - trivy image
        --format json
        --output trivy-report.json
        registry.example.com/myapp:$CI_COMMIT_SHORT_SHA
  artifacts:
    paths: [trivy-report.json]
    expire_in: 1 day

upload-to-defectdojo:
  image: curlimages/curl:latest
  needs: [trivy-scan]
  script:
    - |
      curl -s -X POST \
        -H "Authorization: Token ${DEFECTDOJO_API_TOKEN}" \
        -F "file=@trivy-report.json" \
        -F "scan_type=Trivy Scan" \
        -F "product_name=${CI_PROJECT_NAME}" \
        -F "engagement_name=${CI_COMMIT_BRANCH}" \
        -F "auto_create_context=True" \
        -F "close_old_findings=True" \
        https://defectdojo.example.com/api/v2/import-scan/

close_old_findings=True — помечает находки из предыдущего скана как устранённые, если они не появились в новом. Список актуален без ручной чистки.


Отправка результатов SonarQube

bash# Экспорт из SonarQube
curl -u "${SONAR_TOKEN}:" \
  "https://sonar.example.com/api/issues/search?componentKeys=my-project&resolved=false" \
  > sonar-report.json

# Отправка в DefectDojo
curl -X POST \
  -H "Authorization: Token ${DEFECTDOJO_API_TOKEN}" \
  -F "file=@sonar-report.json" \
  -F "scan_type=SonarQube Scan" \
  -F "product_name=my-service" \
  -F "engagement_name=main" \
  -F "auto_create_context=True" \
  https://defectdojo.example.com/api/v2/import-scan/

Отправка OWASP Dependency-Check

yamldependency-check:
  image: owasp/dependency-check:latest
  script:
    - /usr/share/dependency-check/bin/dependency-check.sh
        --project ${CI_PROJECT_NAME}
        --scan .
        --format JSON
        --out dependency-check-report.json
  artifacts:
    paths: [dependency-check-report.json]

upload-dc:
  image: curlimages/curl:latest
  needs: [dependency-check]
  script:
    - curl -X POST \
        -H "Authorization: Token ${DEFECTDOJO_API_TOKEN}" \
        -F "file=@dependency-check-report.json" \
        -F "scan_type=Dependency Check Scan" \
        -F "product_name=${CI_PROJECT_NAME}" \
        -F "engagement_name=${CI_COMMIT_BRANCH}" \
        -F "auto_create_context=True" \
        -F "close_old_findings=True" \
        https://defectdojo.example.com/api/v2/import-scan/

Контроль SLA и уведомления

Настройте SLA в Settings → SLA Configuration:

Критичность Дней на устранение
Critical 7
High 30
Medium 90
Low 180

DefectDojo отслеживает дату создания и отправляет email/Slack-уведомления при нарушении SLA. Находки с истёкшим SLA отображаются в отдельном дашборде.


Управление API-токенами

  1. Admin → Users → Add User → роль "API"
  2. Profile → API v2 Key → сгенерировать токен
  3. Добавить в GitLab CI как защищённую маскированную переменную DEFECTDOJO_API_TOKEN

Никогда не используйте admin-токен в CI. При утечке атакующий сможет удалить все находки или пометить их как ложно устранённые.


Типичные проблемы

Импорт падает с ошибкой 400:

  • Неверный scan_type — название должно совпадать точно (например, «Trivy Scan», а не «trivy»)
  • Смотрите логи: kubectl logs -n defectdojo deployment/defectdojo-django

Под уходит в CrashLoopBackOff при старте:

  • Не успевают миграции — увеличьте initialDelaySeconds до 180–240 на медленных нодах.

Дедупликация не работает:

  • DefectDojo дедуплицирует по хэшу. Если формат отчёта изменился между версиями сканера, хэши не совпадут и старые находки не будут закрыты.