Trivy Output Report là gì?

Trong DevSecOps, việc “quét ra lỗi” chưa đủ — quan trọng hơn là report phải đọc được, chia sẻ được, và tự động hóa được trong CI/CD.
Trivy hỗ trợ nhiều định dạng output, phổ biến nhất là:
- SARIF: chuẩn để đưa lên GitHub Code Scanning / Security tab
- JSON: hợp để parse, đẩy vào hệ thống nội bộ, SIEM, dashboard, hoặc convert sang format khác
- HTML: phù hợp khi cần report dễ đọc cho PM/QA/Team không kỹ thuật, hoặc lưu artifact trên CI
Khi nào dùng SARIF / JSON / HTML?
SARIF (khuyến nghị nếu dùng GitHub)
Dùng khi bạn muốn:
- Hiện findings trong GitHub Security / Code scanning alerts
- Review lỗ hổng ngay trong PR (tuỳ setup)
- Chuẩn hóa theo pipeline compliance
JSON (khuyến nghị để tự động hóa)
Dùng khi bạn muốn:
- Viết rule “fail pipeline nếu CRITICAL/HIGH”
- Tổng hợp theo nhiều repo, tạo dashboard
- Convert sang HTML/CSV/JUnit tùy nhu cầu
HTML (khuyến nghị để share nội bộ)
Dùng khi bạn muốn:
- Một file report “mở là đọc”
- Lưu artifact trên GitLab/Jenkins
- Gửi report cho khách hàng / audit nhanh
Best practice: xuất report trong CI/CD
-
Quét image (trước khi deploy) và fs/repo (ngay khi PR)
-
Luôn lưu report thành artifact:
reports/trivy.* -
Tách 2 luồng:
-
Security UI (SARIF → GitHub Code Scanning)
-
Automation (JSON → parse + gate)
-
Human-readable (HTML → artifact)
-
Template output report (SARIF/JSON/HTML)
Các lệnh dưới đây là template “copy chạy được”. Bạn chỉ cần thay
IMAGE,TARGET, hoặc thêm options.
1) SARIF report (GitHub Code Scanning)
Quét image → xuất SARIF
mkdir -p reports
trivy image \
--format sarif \
--output reports/trivy-image.sarif \
--severity CRITICAL,HIGH,MEDIUM \
--ignore-unfixed \
--scanners vuln,misconfig,secret,license \
IMAGE_NAME:TAG
Quét filesystem/repo → xuất SARIF
mkdir -p reports
trivy fs \
--format sarif \
--output reports/trivy-fs.sarif \
--severity CRITICAL,HIGH,MEDIUM \
--ignore-unfixed \
--scanners vuln,misconfig,secret,license \
.
Gợi ý CI: upload file *.sarif lên GitHub Code Scanning (thường dùng action github/codeql-action/upload-sarif).
2) JSON report (để parse & gate pipeline)
Quét image → xuất JSON
mkdir -p reports
trivy image \
--format json \
--output reports/trivy-image.json \
--severity CRITICAL,HIGH,MEDIUM \
--ignore-unfixed \
--scanners vuln,misconfig,secret,license \
IMAGE_NAME:TAG
“Gate” nhanh: fail pipeline nếu có CRITICAL/HIGH (ví dụ bằng jq)
# Yêu cầu: cài jq
# Fail nếu có bất kỳ finding severity CRITICAL/HIGH
jq -e '
[
.Results[]?
| (.Vulnerabilities[]? | select(.Severity=="CRITICAL" or .Severity=="HIGH")),
(.Misconfigurations[]? | select(.Severity=="CRITICAL" or .Severity=="HIGH")),
(.Secrets[]? | select(.Severity=="CRITICAL" or .Severity=="HIGH"))
] | flatten | length == 0
' reports/trivy-image.json
Nếu command trên trả exit code != 0 → pipeline fail.
3) HTML report (artifact “mở là đọc”)
Trivy có nhiều cách tạo HTML, phổ biến nhất là dùng template.
A) HTML từ JSON + template (khuyến nghị, linh hoạt)
Bước 1: xuất JSON
mkdir -p reports
trivy image --format json --output reports/trivy-image.json IMAGE_NAME:TAG
Bước 2: render HTML bằng template
Lưu ý: trivy convert là cách “đẹp” để convert JSON sang template output. Nếu bản Trivy bạn dùng không có convert, có thể dùng trivy image --format template --template ... trực tiếp.
B) HTML trực tiếp khi scan (nếu bạn muốn 1 bước)
mkdir -p reports
mkdir -p reports
trivy image \
--format template \
--template "@template.tpl" \
--output reports/trivy-report.html \
IMAGE_NAME:TAG
Mẫu template HTML tối giản (template.tpl)
Template này cố tình gọn, đọc dễ, hợp làm artifact. Bạn có thể mở rộng thêm bảng Misconfig/Secrets.
{{- /* template.tpl – Trivy HTML minimal report */ -}}
<!doctype html>
<html lang=”vi”>
<head>
<meta charset=”utf-8″ />
<meta name=”viewport” content=”width=device-width,initial-scale=1″ />
<title>Trivy Security Report</title>
<style>
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial; margin:24px; line-height:1.45}
.meta{color:#444; margin-bottom:16px}
.badge{display:inline-block; padding:2px 10px; border-radius:999px; border:1px solid #ccc; margin-right:6px; font-size:12px}
table{width:100%; border-collapse:collapse; margin-top:10px}
th,td{border:1px solid #ddd; padding:8px; font-size:14px; vertical-align:top}
th{background:#f6f6f6; text-align:left}
.sev-CRITICAL{font-weight:700}
.sev-HIGH{font-weight:700}
.muted{color:#666}
.section{margin-top:24px}
</style>
</head>
<body>
<h1>Trivy Security Report</h1>
<div class=”meta”>
<span class=”badge”>Generated: {{ now }}</span>
{{- if .ArtifactName }}<span class=”badge”>Target: {{ .ArtifactName }}</span>{{ end -}}
{{- if .ArtifactType }}<span class=”badge”>Type: {{ .ArtifactType }}</span>{{ end -}}
</div>
{{- $hasVuln := false -}}
{{- range .Results }}
{{- if .Vulnerabilities }}{{ $hasVuln = true }}{{ end -}}
{{- end -}}
{{- if not $hasVuln }}
<p><b>✅ Không phát hiện Vulnerabilities.</b> <span class=”muted”>(Chưa hiển thị Misconfig/Secrets trong template tối giản)</span></p>
{{- else }}
<div class=”section”>
<h2>Vulnerabilities</h2>
{{- range .Results }}
{{- if .Vulnerabilities }}
<h3>{{ .Target }}</h3>
<table>
<thead>
<tr>
<th>CVE</th>
<th>Package</th>
<th>Installed</th>
<th>Fixed</th>
<th>Severity</th>
<th>Title</th>
</tr>
</thead>
<tbody>
{{- range .Vulnerabilities }}
<tr>
<td>{{ .VulnerabilityID }}</td>
<td>{{ .PkgName }}</td>
<td>{{ .InstalledVersion }}</td>
<td>{{ if .FixedVersion }}{{ .FixedVersion }}{{ else }}-{{ end }}</td>
<td class=”sev-{{ .Severity }}”>{{ .Severity }}</td>
<td>{{ if .Title }}{{ .Title }}{{ else }}-{{ end }}</td>
</tr>
{{- end }}
</tbody>
</table>
{{- end }}
{{- end }}
</div>
{{- end }}
<div class=”section muted”>
<p>Tip: Dùng JSON để gate CI/CD, SARIF để đưa lên GitHub Code Scanning, HTML để lưu artifact dễ đọc.</p>
</div>
</body>
</html>
