Trivy Output Report là gì?

Trivy Output Report: Template SARIF/JSON/HTML chuẩn CI/CD (GitHub, GitLab, Jenkins)

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:

    1. Security UI (SARIF → GitHub Code Scanning)

    2. Automation (JSON → parse + gate)

    3. 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>

ads-rb
Index