Zora Integration with DefectDojo
Zora Integration with DefectDojo
Zora is an open source Kubernetes security tool from Undistro, released under the Apache 2.0 license, that runs inside your clusters and scans them on a schedule with a set of plugins. Popeye and Marvin check for misconfigurations, and Trivy reports vulnerabilities in the container images your workloads run. Zora stores its scan configuration and results as Kubernetes custom resources rather than behind a REST API, and its documentation describes how to convert those results to CSV. DefectDojo reads Zora data two ways: a CSV file parser available in every edition, and an Upstream Connector in DefectDojo Pro that reads the results straight from your management cluster.
Zora Integration with DefectDojo
We picked Zora because it lives in the cluster and keeps scanning without anyone kicking off a job, and we send its output to DefectDojo because results stored as cluster resources are hard for anyone outside the platform team to act on. Once imported, each image CVE becomes a Finding on the Asset that represents the cluster, with a severity, an SLA clock, and an owner. Reimporting the next export closes what was patched and keeps one history per cluster, which is far easier to report on than a namespace full of custom resources.
Why Zora Matters
Kubernetes clusters accumulate risk in two places: the images that run in them and the way workloads are configured. Zora covers both from inside the cluster.
- It runs continuously on a schedule, so new CVEs in running images show up without a separate pipeline step.
- It brings together several established plugins (Popeye, Marvin, and Trivy) under one operator, so teams don't run and maintain each scanner separately.
- Its results name the image, the vulnerability ID, and the fixed version where one exists, which is enough for an image owner to plan an update.
- Results that live only as custom resources are invisible to people without cluster access. Security leads and application owners need them somewhere they already work.
Advantages of This Integration
What running Zora through DefectDojo adds:
- Cluster results outside the cluster. Findings land on DefectDojo Assets, so application owners can see and triage image CVEs without kubeconfig access.
- Reimport lifecycle. Sending each new export to the same Test mitigates findings that dropped out of the report, adds new ones, and reactivates any that return.
- Fix information preserved. The parser records the fixed version and flags whether a fix is available, so teams can filter for work they can actually do today.
- SLAs and risk acceptance. Zora severities map onto DefectDojo's Critical through Info scale, so cluster findings follow the same SLA rules as every other scanner, and unfixable CVEs can be risk-accepted with an expiration date.
- Automated pulls with DefectDojo Pro. The Zora Upstream Connector reads results from the management cluster on a schedule and creates one Record per scanned cluster, so nobody has to export and upload files.
How This Integration Works
There are two paths. The file parser uses the Zora Parser scan type and is available through UI Import, API Import, and Universal Importer (Pro). The Zora Upstream Connector is DefectDojo Pro only.
1. Produce a CSV file in the format the parser expects. The parser reads a comma-separated file with a header row and these exact column names: source, image, id, title, severity, status, description, fixVersion. Column names are case-sensitive. The sample report in the DefectDojo repository follows this layout, with one row per vulnerability per image. The CSV conversions in Zora's own documentation use different column names (for example "Vulnerability ID" and "Fix version"), so shape your export to the header above before importing, or rows will arrive with empty fields.
2. Import the file. In the UI, open an Engagement, choose Import Scan Results, select Zora Parser, and upload the CSV. For automation, call the API in Community Edition or DefectDojo Pro:
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Zora Parser"
-F "file=@zora-results.csv"
-F "product_name=prod-cluster-eu"
-F "engagement_name=Cluster Scans"
-F "auto_create_context=true"
DefectDojo Pro users can run the same import from a scheduled job with Universal Importer:
universal-importer import
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/"
--scan-type "Zora Parser"
--report-path "./zora-results.csv"
--product-name "prod-cluster-eu"
--engagement-name "Cluster Scans"
--auto-create-context
3. Reimport on a schedule. Zora rescans on its own cadence, so send later exports to /api/v2/reimport-scan/ against the same Test to keep the open-to-mitigated history in one place.
4. Or connect Zora directly (DefectDojo Pro). In Connect > Upstream, add the Zora connector and provide a kubeconfig that grants read access to the management cluster where the Zora Operator writes its results. No API token is involved, because Zora has no REST API; DefectDojo reads the Kubernetes resources directly. You can optionally set a Minimum Severity. Discover creates a Record for each cluster Zora scans, carrying the issues and vulnerability reports Zora recorded for it, and Sync imports them into a Global Connectors Engagement on the mapped Asset.
Data Granularity: What Gets Imported
The table below describes the CSV parser, read from its source code.
| DefectDojo Field | Source in Zora CSV | Notes |
|---|---|---|
| Title | title |
Taken as written, typically the vulnerability title |
| Severity | severity |
info/informational, low, medium/med, high, critical/crit are mapped; anything else, including UNKNOWN, becomes Info |
| Description | source, image, id, description |
Composed as labeled lines: Source, Image, ID, Details |
| Mitigation | description |
The same text as the Details line; the CSV has no separate remediation column |
| Vulnerability IDs | id |
For example a CVE identifier |
| Fix Available / Fix Version | fixVersion |
Fix Available is true only when a fix version is present |
| Unique ID from Tool | source, image, id |
Joined with hyphens |
| Mitigated flag | status |
PASS, OK, or FIXED (any case) sets the finding as mitigated |
| Finding type | Fixed | Every Zora finding is marked dynamic |
| Deduplication | Legacy algorithm | Zora Parser has no per-parser entry, so the Legacy algorithm applies |
The parser does not set CWE, component name, file path, or endpoints, and it does not merge rows: each CSV row becomes one Finding.
Use Cases
Platform team reporting: A team running a dozen clusters maps each one to its own Asset. Weekly reimports show which image CVEs were closed by node and add-on upgrades, and the rest stay assigned with SLA dates instead of sitting in a namespace nobody outside the platform team reads.
Image ownership: The Image line in every description tells you which image carries the CVE. Teams that own a workload can filter findings by that text and take the fixed version straight from the Fix Version field.
Hands-off collection with DefectDojo Pro: Instead of scripting exports, the Zora connector reads the management cluster on a schedule and keeps one Record per scanned cluster, so new clusters appear for mapping as Zora starts scanning them.
Audit evidence: Every cluster finding carries a discovery date, SLA status, and its mitigation history, which answers "how long were Critical image vulnerabilities open in production" without reconstructing it from old CSV files.
Operational Tips
- Check the
statuscolumn before your first import. The parser treats FIXED as mitigated, but in Trivy's vocabulary "fixed" usually means a patched package version has been published, not that your running image was updated. In the repository's sample file most Trivy rows carry that status, so decide whether to rewrite it before import if you want those rows to stay open. - Severity values outside the mapped set, such as UNKNOWN, import as Info. If you set
minimum_severityabove Info, those rows will be dropped along with genuine Info findings. - Legacy deduplication relies on endpoints or file path and line, and Zora findings carry none, so duplicates across separate Tests are generally not collapsed. Reimport into one Test per cluster rather than importing each export as a new Test.
- Reimport matching under Legacy uses title and severity, and the title comes from the vulnerability, not the image. Keeping one Test per cluster keeps those matches scoped sensibly.
- Use the Fix Available and Fix Version fields to separate actionable CVEs from those waiting on an upstream patch, and risk-accept the latter with an expiration date.
- Tag imports with the cluster name and environment (for example
tags=prod,eu-west) so metrics can be split by environment.