Skip to content

defectdojo

Metadata

Field Value
Service defectdojo
Purpose Vulnerability management platform and findings intake portal
Criticality Tier 2
Owner Platform / Security owner
Clusters homelab, local
Namespace defectdojo
Exposure internet
Stateful yes
Backup class snapshot
RPO / RTO Daily backup target, 4 to 8 hours to restore
Last reviewed 2026-07-02

1. Service Overview

DefectDojo provides the web UI, API, and background workers used to centralize vulnerability findings and security workflows.

Summary

If it fails, operators lose access to the findings portal, scan ingestion, and background processing for imports and notifications.

Dependencies

Dependency Type Why it matters
PostgreSQL database Stores users, findings, products, and application state
Valkey broker / cache Required by celery workers and async processing
Traefik ingress Exposes the HTTPS route
Kustomize-generated Secret defectdojo runtime secret Provides bootstrap admin password and Django runtime secrets

2. Architecture Diagram

[Browser / API client]
  -> [Traefik]
  -> [DefectDojo nginx]
  -> [DefectDojo uwsgi]
  -> [PostgreSQL]
  -> [Valkey]
  -> [Celery worker / beat]

3. Deployment Specifications

Item Value
Source path defectdojo/base and defectdojo/overlays/{homelab,local}
Deployment model Fleet-native Helm release plus a Helm-free Kustomize post-render overlay; helmCharts: remains only for local rendering
Namespace defectdojo
Workload kind Deployment, StatefulSets, and bootstrap Job
Chart or image version Helm chart defectdojo 1.9.29 on homelab; 1.9.37 on local
Config files base/kustomization.yaml, overlays/{homelab,local}/kustomization.yaml, overlays/{homelab,local}/fleet/kustomization.yaml, overlays/{homelab,local}/values.yaml, fleet.yaml

Cluster mapping

Cluster Overlay path Host Notes
homelab defectdojo/overlays/homelab defectdojo.home.mutana.fr Upstream/development deployment, native DefectDojo auth, no node pinning, media on truenas-nfs-apps
local defectdojo/overlays/local defectdojo.mutana.fr Production-like deployment on the Rancher multi-cloud cluster. UI behind Authelia; /api bypasses Authelia. All pods pinned to one node.io/defectdojo=true node; storage on local-path

Node placement (local only)

The local cluster spans three cloud providers, so all DefectDojo pods must co-locate on one node to avoid cross-cloud latency and storage fragmentation. The DefectDojo chart does not honor a single global nodeSelector, so the overlay sets it per component in overlays/local/values.yaml:

  • django.nodeSelector
  • celery.worker.nodeSelector
  • celery.beat.nodeSelector
  • initializer.nodeSelector
  • postgresql.primary.nodeSelector
  • valkey.nodeSelector (bitnami standalone uses a top-level nodeSelector)

Label exactly one node before reconciling:

kubectl label node <chosen-node> node.io/defectdojo=true --overwrite

Confirm scheduling:

kubectl -n defectdojo get pods -o wide

4. Configuration Guide

Environment variables

Variable Source Purpose Secret?
DD_ADMIN_PASSWORD overlays//.defectdojo-secrets.env -> Secret defectdojo Initial superuser password at first bootstrap yes
DD_SECRET_KEY overlays//.defectdojo-secrets.env -> Secret defectdojo Django signing and session security yes
DD_CREDENTIAL_AES_256_KEY overlays//.defectdojo-secrets.env -> Secret defectdojo Encryption key for stored credentials yes
METRICS_HTTP_AUTH_PASSWORD overlays//.defectdojo-secrets.env -> Secret defectdojo Password for the nginx metrics endpoint yes
DD_CSRF_TRUSTED_ORIGINS overlays//values.yaml Trust the external HTTPS origin no

Each cluster has its own secret material. The homelab and local overlays do not share DD_SECRET_KEY / DD_CREDENTIAL_AES_256_KEY / DD_ADMIN_PASSWORD.

The root overlay's secretGenerator is for the local Helm-enabled Kustomize entry point. Fleet instead renders the chart natively and uses the Helm-free overlays/<cluster>/fleet post-render directory. The defectdojo and defectdojo-postgresql-specific Secrets must therefore exist in the target namespace before the initial Fleet reconciliation.

ConfigMaps

Resource Path Purpose
Helm-generated DefectDojo config defectdojo/overlays/homelab/values.yaml Runtime settings, URL, replicas, probes, and resources

Secrets management

  • Runtime Secret names (in the defectdojo namespace on each target cluster): defectdojo, defectdojo-postgresql-specific, and defectdojo-valkey-specific (the last is created by the chart itself).
  • Fleet-values Secret (in fleet-default on the management cluster): defectdojo-helm-values-<cluster> (-homelab, -local), key values.yaml, holding postgresql.auth.password. Fleet helm.valuesFrom injects this as a Helm value at install time so the Bitnami PostgreSQL subchart's upgrade-password guard does not fail in Fleet's dry-run render context (where lookup() is a no-op). The value should equal the postgresql-password key of the matching runtime Secret. See the runbook for the full mechanism.
  • Source of truth: per-cluster .env inputs under defectdojo/overlays/<cluster>. The local Kustomize entry point generates the runtime Secret objects; for Fleet, apply the runtime Secrets out of band before reconciliation, and create the Fleet-values Secret on the management cluster.
  • Bootstrap guard: the initializer Job now has a required secretKeyRef for DD_ADMIN_PASSWORD so first boot fails fast if the Secret is missing, instead of generating a random password.
  • Recovery note: if the first bootstrap already ran without the expected password, use the runbook to reset dojo-admin or create a replacement superuser.

5. Access Protocols

Path URL or endpoint Audience Auth TLS terminates at
Internal Services inside the defectdojo namespace Cluster workloads namespace RBAC nginx / service
External (homelab) https://defectdojo.home.mutana.fr Operators on the home network DefectDojo native auth Traefik
External UI (local) https://defectdojo.mutana.fr Operators and security users Authelia forward auth (authelia@file) Traefik
External API (local) https://defectdojo.mutana.fr/api/v2/ CI and automation DefectDojo v2 API token (Authorization: Token <key>); /api route bypasses Authelia Traefik

The local IngressRoute declares two routes: a high-priority PathPrefix('/api') route without Authelia so token-based automation is not intercepted, and a lower-priority catch-all UI route that chains authelia@file.

6. Operations and Observability

  • Primary health indicators: defectdojo-django ready, initializer Job completed, login page reachable, and PostgreSQL plus Valkey healthy.
  • Dashboards or alerts: shared cluster monitoring and ingress health.
  • Log locations: uwsgi, nginx, initializer Job, celery worker, celery beat, PostgreSQL, and Valkey logs.
  • Known failure modes: missing bootstrap secret, OOM on uwsgi, PVC attachment problems, or ingress / CSRF misconfiguration.

7. Backup and Recovery Notes

  • Backup method: PostgreSQL backup plus media PVC snapshot.
  • Restore prerequisites: database state, runtime secrets, and media PVC if user-uploaded files matter.
  • Related runbook: ../runbooks/defectdojo.md

8. Release and Change Notes

  • Current chart versions: 1.9.29 on homelab and 1.9.37 on local.
  • 2026-07-20: corrected the Fleet render path so Fleet inflates the chart itself and post-renders only the Helm-free per-cluster resources. This avoids must specify --enable-helm during reconciliation.
  • 2026-07-20: added Fleet helm.valuesFrom injection of postgresql.auth.password per cluster so the Bitnami PostgreSQL subchart's upgrade-password guard no longer fails during Fleet resyncs (Fleet renders Helm with lookup() as a no-op). Requires the new defectdojo-helm-values-<cluster> Secret in fleet-default.
  • 2026-07-02: promoted DefectDojo to the local cluster (production-like). Added defectdojo/overlays/local, pinned every component to node.io/defectdojo=true, added Authelia-fronted ingress with an /api bypass, and added Trivy/Gitleaks/Kubeconform/Nessus ingestion automation.
  • 2026-07-02: reconciled chart version drift — fleet.yaml homelab entry moved from 1.9.28 to 1.9.29 to match overlays/homelab/kustomization.yaml.
  • Earlier: bootstrap hardened so the initializer waits for DD_ADMIN_PASSWORD instead of falling back to a random password.
  • Rollback reference: previous Git revision of defectdojo/overlays/local, defectdojo/fleet.yaml, fleet/layer7/gitrepo-main.yaml, the Makefile defectdojo-import target, and .forgejo/workflows/validate.yaml.

Findings Ingestion (local)

DefectDojo on the local cluster is the central intake for SecOps findings. Automation lives under defectdojo/scripts/ and is documented in detail in Findings Ingestion.

Source Scan type (DD) Trigger Script / path
Trivy filesystem scan (this repo) Trivy Scan Forgejo CI (make defectdojo-import) defectdojo/scripts/dd_import_ci.sh
Gitleaks secret scan (this repo) Gitleaks Scan Forgejo CI defectdojo/scripts/dd_import_ci.sh
Kubeconform manifest scan Generic Findings Import Forgejo CI, opt-in via DD_IMPORT_KUBECONFORM=1 defectdojo/scripts/dd_import_ci.sh
Nessus (homelab Docker) Tenable Scan systemd timer / cron on the homelab host defectdojo/scripts/nessus_to_defectdojo.sh
Ansible repo Trivy / Gitleaks Trivy Scan / Gitleaks Scan Ansible repo CI (out of scope here) copy of dd_import.py referenced from the Ansible repo

All imports use /api/v2/reimport-scan/ so repeated pipeline runs reuse the same Test and avoid duplicate findings. Product/engagement/test taxonomy:

The shared importer passes auto_create_context=true, so the first upload can create a missing Test within an existing Product and Engagement. Product and Engagement creation remains explicit through dd_bootstrap.py.

The versioned scan-feed contract is defectdojo/scripts/defectdojo-api-reference.md; it is derived from this instance's cached OpenAPI schema and should be consulted before changing an importer.

Product Engagement Tests
homelab-k8s ci-main (or ci-dev) trivy-fs, gitleaks, kubeconform
nessus-homelab nessus-scheduled nessus-scan