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.nodeSelectorcelery.worker.nodeSelectorcelery.beat.nodeSelectorinitializer.nodeSelectorpostgresql.primary.nodeSelectorvalkey.nodeSelector(bitnami standalone uses a top-level nodeSelector)
Label exactly one node before reconciling:
Confirm scheduling:
4. Configuration Guide¶
Environment variables¶
| Variable | Source | Purpose | Secret? |
|---|---|---|---|
| DD_ADMIN_PASSWORD | overlays/defectdojo |
Initial superuser password at first bootstrap | yes |
| DD_SECRET_KEY | overlays/defectdojo |
Django signing and session security | yes |
| DD_CREDENTIAL_AES_256_KEY | overlays/defectdojo |
Encryption key for stored credentials | yes |
| METRICS_HTTP_AUTH_PASSWORD | overlays/defectdojo |
Password for the nginx metrics endpoint | yes |
| DD_CSRF_TRUSTED_ORIGINS | overlays/ |
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
defectdojonamespace on each target cluster):defectdojo,defectdojo-postgresql-specific, anddefectdojo-valkey-specific(the last is created by the chart itself). - Fleet-values Secret (in
fleet-defaulton the management cluster):defectdojo-helm-values-<cluster>(-homelab,-local), keyvalues.yaml, holdingpostgresql.auth.password. Fleethelm.valuesFrominjects 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 (wherelookup()is a no-op). The value should equal thepostgresql-passwordkey of the matching runtime Secret. See the runbook for the full mechanism. - Source of truth: per-cluster
.envinputs underdefectdojo/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
secretKeyRefforDD_ADMIN_PASSWORDso 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-adminor 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-djangoready, 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
homelaband 1.9.37 onlocal. - 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-helmduring reconciliation. - 2026-07-20: added Fleet
helm.valuesFrominjection ofpostgresql.auth.passwordper cluster so the Bitnami PostgreSQL subchart's upgrade-password guard no longer fails during Fleet resyncs (Fleet renders Helm withlookup()as a no-op). Requires the newdefectdojo-helm-values-<cluster>Secret infleet-default. - 2026-07-02: promoted DefectDojo to the
localcluster (production-like). Addeddefectdojo/overlays/local, pinned every component tonode.io/defectdojo=true, added Authelia-fronted ingress with an/apibypass, and added Trivy/Gitleaks/Kubeconform/Nessus ingestion automation. - 2026-07-02: reconciled chart version drift —
fleet.yamlhomelab entry moved from 1.9.28 to 1.9.29 to matchoverlays/homelab/kustomization.yaml. - Earlier: bootstrap hardened so the initializer waits for
DD_ADMIN_PASSWORDinstead 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 Makefiledefectdojo-importtarget, 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 |