Trivy の VEX ( experimental ) 機能を試しました

# はじめに
「[Trivy で GridDB リポジトリから脆弱性、シークレット情報、ライセンスのスキャンと SBOM の作成をやってみました](https://qiita.com/kanegoon/items/66e8e32b4df997f0308f)」という投稿で、Trivy に興味を持ちましたが、最近、Trivy で VEX ( Vulnerability Exploitability Exchange ) 機能が実験的に追加されたと聞きました。Changelog を見ると実は以前(v0.41.0?)から VEX 機能が組み込まれていたみたいです。今回は、Trivy の VEX 機能について試しに使ってみました。使用した手順と結果を備忘録としてまとめました。

# Trivy とは
Trivy は、オープンソースのセキュリティスキャナーです。スキャン対象には、コンテナイメージ、ファイルシステム、リモートの Git リポジトリ、仮想マシンイメージ、Kubernetes、AWS があります。Trivy は 脆弱性スキャン、ライセンススキャン、そしてソフトウェア部品表 ( SBOM )を出力が可能です。

# VEX とは
VEX は「 Vulnerability Exploitability eXchange 」の略で、ソフトウェアコンポーネントの透明性を高めるために NTIA ( 米国商務省電気通信情報局 ( National Telecommunications and Information Administration ) ) を中⼼に開発されました。VEX の主な目的は、特定の脆弱性が製品に脆弱性が影響を与えるか、また影響がある場合の対策を提供することで、脆弱性の情報を共有および交換するための標準化された形式です。
VEX は、共通セキュリティ勧告フレームワーク（ CSAF ）のプロファイルとして実装されています。CSAF は、OASIS Open CSAF 技術委員会によって開発された機械可読のセキュリティ勧告の標準です。CSAF で定義されているように、VEX はベンダー、システムインテグレーター、およびオペレーターによって提供される修正、回避策、再起動/ダウンタイムの必要性、スコア、およびリスクなどの豊富な情報を提供することもできます。

VEX の脆弱性ステータスは以下のようになっています。
| ステータス | 内容 |
|:--|:--|
| Not affected | この脆弱性に対する対策は不要 |
| Affected | この脆弱性に対する対策が推奨される |
| Fixed | この脆弱性に対する修正が含まれている |
| Under Investigation | この脆弱性に対する影響がまだ不明で、後日更新が提供される |

引用：[Vulnerability-Exploitability eXchange (VEX) – An Overview](https://www.ntia.gov/files/ntia/publications/vex_one-page_summary.pdf)

# Trivy の VEX 機能

Trivy は、検出された脆弱性をフィルタリングするために VEX をサポートしています。スキャン用に SBOM と VEX を利用することで、脆弱性のステータスに基づいてフィルタリングすることが可能です。現在、Trivy は以下の3つの形式をローカル VEX ファイルをサポートしています。

- CycloneDX
- OpenVEX
- CSAF

ただ、これはまだ実験的な実装であり、追加された機能は最小限とのことです。
今回は、Cyclone、OpenVEXについて動作を確認します。CSAFについて、後日確認します。

# Trivy のインストール

wget で github から Trivy のパッケージを入手して、dpkg コマンドでインストールします。今回、インストール、使用したバージョンは 0.58.0 です。
```bash
$ wget https://github.com/aquasecurity/trivy/releases/download/v0.58.0/trivy_0.58.0_Linux-64bit.deb
$ sudo dpkg -i trivy_0.58.0_Linux-64bit.deb
$ trivy -v
Version: 0.58.0
・・・
```

# CycloneDX 形式の VEX

CycloneDXには2つのVEX形式があります。

- 独立した SBOM と VEX BOM
- VEX が埋め込まれた SBOM

Trivy は、VEX が埋め込まれた SBOM をサポートしておらず、独立した SBOM と VEX BOM 形式のみをサポートしているため、SBOM と一緒に別の VEX ファイルを提供する必要があります。入力 SBOM 形式は CycloneDX 形式でなければなりません。
必要な手順は以下のように[ドキュメント](https://trivy.dev/latest/docs/supply-chain/vex/file/#cyclonedx)に書かれています。

1. CycloneDX SBOM を生成する
2. 手順1で生成された SBOM を基に VEX を作成する
3. CycloneDX SBOM をスキャンする際に VEX を利用する

ただ、手順2の VEX 作成はどうやら手動で作成するらしいです。

## CycloneDX SBOM の生成

まずは、CycloneDX 形式の SBOM を生成します。今回は、OSSインメモリデータベースの Redis の SBOM を作成します。
```bash
~$ trivy repo --format cyclonedx --output redis-sbom.cdx https://github.com/redis/redis
2024-12-14T20:44:01+09:00       INFO    "--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the "cyclonedx" report.
...
Total 15893 (delta 11512), reused 11317 (delta 7342), pack-reused 0 (from 0)
2024-12-14T20:44:33+09:00       INFO    Number of language-specific files       num=2
```

以下のような CycloneDX 形式の SBOM が生成されます。

```json
{
  "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "serialNumber": "urn:uuid:16c66bbd-eedd-4595-816d-2ee62c0edbf2",
  "version": 1,
  "metadata": {
    "timestamp": "2024-12-15T11:44:33+00:00",
    "tools": {
      "components": [
        {
          "type": "application",
          "group": "aquasecurity",
          "name": "trivy",
          "version": "0.58.0"
        }
      ]
    },
    "component": {
      "bom-ref": "ff349694-28cf-40d4-83c8-6011bce4b790",
      "type": "application",
      "name": "https://github.com/redis/redis",
      "properties": [
        {
          "name": "aquasecurity:trivy:SchemaVersion",
          "value": "2"
        }
      ]
    }
  },
  "components": [
    {
      "bom-ref": "0be82ef1-8ab1-409a-af10-b26259572681",
      "type": "application",
      "name": "utils/req-res-validator/requirements.txt",
・・・<<省略>>・・・
  "vulnerabilities": []
}
```

生成された SBOM を利用して、VEX を利用しない脆弱性スキャンを行います。

```bash
$ trivy sbom redis-sbom.cdx
2024-12-14T20:58:20+09:00       INFO    [vuln] Vulnerability scanning is enabled
2024-12-14T20:58:20+09:00       INFO    Detected SBOM format    format="cyclonedx-json"
...
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)

┌─────────┬────────────────┬──────────┬────────┬───────────────────┬─────────────────────┬─────────────────────────────────────────────┐
│ Library │ Vulnerability  │ Severity │ Status │ Installed Version │    Fixed Version    │                    Title                    │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼─────────────────────┼─────────────────────────────────────────────┤
│ redis   │ CVE-2023-28859 │ HIGH     │ fixed  │ 4.5.1             │ 4.5.4, 4.4.4        │ redis: Async command information disclosure │
│         │                │          │        │                   │                     │ https://avd.aquasec.com/nvd/cve-2023-28859  │
│         ├────────────────┼──────────┤        │                   ├─────────────────────┼─────────────────────────────────────────────┤
│         │ CVE-2023-28858 │ MEDIUM   │        │                   │ 4.4.3, 4.5.3, 4.3.6 │ redis: Async command information disclosure │
│         │                │          │        │                   │                     │ https://avd.aquasec.com/nvd/cve-2023-28858  │
└─────────┴────────────────┴──────────┴────────┴───────────────────┴─────────────────────┴─────────────────────────────────────────────┘
```

## CycloneDX形式の VEX 作成

次に、生成された SBOM に基づいて VEX を作成します。脆弱性の下には複数の脆弱性ステータスを定義することができます。現在、Trivy には VEX ドキュメントを作成するための組み込み機能がないため、手動で作成する必要があります。

```json
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "version": 1,
  "vulnerabilities": [
    {
      "id": "CVE-2023-28858",
      "analysis": {
        "state": "not_affected",
        "justification": "code_not_reachable",
        "response": ["will_not_fix", "update"],
        "detail": "The vulnerable function is not called"
      },
      "affects": [
        {
          "ref": "urn:cdx:16c66bbd-eedd-4595-816d-2ee62c0edbf2/1#ff349694-28cf-40d4-83c8-6011bce4b790"
        }
      ]
    }
  ]
}
```
vulnerability には "CVE-2023-28858" を記述して、status は "not_affected" とします。
BOM-Link は affects.ref に配置する必要があります。BOM-Link は次の構文を持ち、3つの要素で構成されます。

urn:cdx:serialNumber/version#bom-ref
- serialNumber
- version
- bom-ref

これらの値は CycloneDX SBOM から取得します。serialNumberはurn:uuid: で始まりますが、BOM-Link は urn:cdx:で始まることに注意してください。
bom-ref には、脆弱性の影響を受けるパッケージの BOM-Ref を含める必要があります。
CycloneDX VEX および BOM-Link の詳細については、以下のリンクを参照してください。
- [CycloneDX VEX](https://cyclonedx.org/capabilities/vex/)
- [BOM-Link](https://cyclonedx.org/capabilities/bomlink/)

## VEX を利用して、CycloneDX SBOM をスキャン
生成された SBOM と作成した VEX で、検出された脆弱性をフィルタリングします。
```bash
$ trivy sbom redis-sbom.cdx --vex trivy.vex.cdx
2024-12-14T21:10:28+09:00       INFO    [vuln] Vulnerability scanning is enabled
2024-12-14T21:10:28+09:00       INFO    Detected SBOM format    format="cyclonedx-json"
...
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)

┌─────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬─────────────────────────────────────────────┐
│ Library │ Vulnerability  │ Severity │ Status │ Installed Version │ Fixed Version │                    Title                    │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼─────────────────────────────────────────────┤
│ redis   │ CVE-2023-28859 │ HIGH     │ fixed  │ 4.5.1             │ 4.5.4, 4.4.4  │ redis: Async command information disclosure │
│         │                │          │        │                   │               │ https://avd.aquasec.com/nvd/cve-2023-28859  │
└─────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴─────────────────────────────────────────────┘
```
CVE-2023-28858は、指定されたCycloneDX VEXドキュメントに従ってフィルタリングされるため表示されません。

# OpenVEX
Trivy は、最小限で準拠し、相互運用可能で埋め込み可能な設計の OpenVEX もサポートしています。OpenVEX はSBOM 形式に依存しないため、CycloneDX および SPDX 形式の両方が Trivy て利用可能です。

必要な手順は、CyconeDX と同様に以下のように[ドキュメント]https://trivy.dev/latest/docs/supply-chain/vex/file/#openvex)に書かれています。

1. SBOM（ CycloneDX または SPDX ）を生成する
2. 手順1で生成された SBOM から VEX を作成する
3. SBOM をスキャンする際に VEX を利用する

## SPDX SBOM の生成

まずは、SPDX 形式の SBOM を作成します。今回も、OSS インメモリデータベースの Redis の SBOM を作成します。
```bash
~$ trivy repo --format spdx-json --output redis-sbom.spdx https://github.com/redis/redis
2024-12-14T22:58:08+09:00       INFO    "--format spdx-json" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the "spdx-json" report.
...
Total 15893 (delta 11520), reused 11308 (delta 7344), pack-reused 0 (from 0)
2024-12-14T22:58:52+09:00       INFO    Number of language-specific files       num=2
```

以下のような SPDX 形式の SBOM が生成されます。

```json
{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "https://github.com/redis/redis",
  "documentNamespace": "http://aquasecurity.github.io/trivy/repository/github.com/redis/redis-71ac5c87-aa62-4cf8-b9d0-e586976e84cb",
...
  "creationInfo": {
...
  },
  "packages": [
...
    {
      "name": "redis",
      "SPDXID": "SPDXRef-Package-f27120ddfcee128a",
      "versionInfo": "4.5.1",
      "supplier": "NOASSERTION",
      "downloadLocation": "git+https://github.com/redis/redis",
      "filesAnalyzed": false,
      "sourceInfo": "package found in: utils/req-res-validator/requirements.txt",
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "externalRefs": [
        {
          "referenceCategory": "PACKAGE-MANAGER",
          "referenceType": "purl",
          "referenceLocator": "pkg:pypi/redis@4.5.1"
        }
      ],
...
    },
...
    {
      "name": "https://github.com/redis/redis",
      "SPDXID": "SPDXRef-Repository-8dc75be4744eb679",
      "downloadLocation": "git+https://github.com/redis/redis",
      "filesAnalyzed": false,
      "primaryPackagePurpose": "SOURCE",
      "annotations": [
        {
          "annotator": "Tool: trivy-0.58.0",
          "annotationDate": "2024-12-15T13:58:52Z",
          "annotationType": "OTHER",
          "comment": "SchemaVersion: 2"
        }
      ]
    }
  ],
  "relationships": [
...
  ]
}
```

## OpenVex形式の VEX 作成

次に、生成された SBOM に基づいて VEX を作成します。脆弱性の下には複数の脆弱性ステータスを定義することができます。現在、Trivy には VEX ドキュメントを作成するための組み込み機能がないため、こちらも手動で作成する必要があります。

```json
{
  "@context": "https://openvex.dev/ns",
  "@id": "https://openvex.dev/docs/public/vex-test",
  "author": "Toshiba Corp",
  "timestamp": null,
  "version": 1,
  "statements": [
    {
      "vulnerability": {"name" : "CVE-2023-28859"},
      "products": [
        {"@id": "pkg:pypi/redis@4.5.1"}
      ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path"
    }
  ]
}
```
OpenVEXフォーマットについては以下のページをご覧ください。

https://github.com/openvex/examples

vulnerability には "CVE-2023-28859" を記述して、status は "not_affected" とします。
product 識別子に PURL ( Product URL ) を記述します。生成された SBOM の redis の referenceLocator識別子の値 "pkg:pypi/redis@4.5.1" を記述します。

## VEX を利用して、SPDX SBOM をスキャン
生成された SBOM と作成した VEX で、検出された脆弱性をフィルタリングします。
```bash
$ trivy sbom redis-sbom.spdx --vex trivy.openvex
2024-12-14T23:22:41+09:00       INFO    [vuln] Vulnerability scanning is enabled
2024-12-14T23:22:41+09:00       INFO    Detected SBOM format    format="spdx-json"
...
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

┌─────────┬────────────────┬──────────┬────────┬───────────────────┬─────────────────────┬─────────────────────────────────────────────┐
│ Library │ Vulnerability  │ Severity │ Status │ Installed Version │    Fixed Version    │                    Title                    │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼─────────────────────┼─────────────────────────────────────────────┤
│ redis   │ CVE-2023-28858 │ MEDIUM   │ fixed  │ 4.5.1             │ 4.4.3, 4.5.3, 4.3.6 │ redis: Async command information disclosure │
│         │                │          │        │                   │                     │ https://avd.aquasec.com/nvd/cve-2023-28858  │
└─────────┴────────────────┴──────────┴────────┴───────────────────┴─────────────────────┴─────────────────────────────────────────────┘
```
CVE-2023-28859は、指定された OpenVEX ドキュメントに従ってフィルタリングされるため表示されません。

また、コマンド実行時 --show-suppressed フラグを指定すると、表示されなかった CVE-2023-28859 を Suppressed Vulnerabilities として表示可能です。

```bash
$ trivy sbom redis-sbom.spdx --vex trivy.openvex --show-suppressed
2024-12-14T23:21:44+09:00       INFO    [vuln] Vulnerability scanning is enabled
...
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

┌─────────┬────────────────┬──────────┬────────┬───────────────────┬─────────────────────┬─────────────────────────────────────────────┐
│ Library │ Vulnerability  │ Severity │ Status │ Installed Version │    Fixed Version    │                    Title                    │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼─────────────────────┼─────────────────────────────────────────────┤
│ redis   │ CVE-2023-28858 │ MEDIUM   │ fixed  │ 4.5.1             │ 4.4.3, 4.5.3, 4.3.6 │ redis: Async command information disclosure │
│         │                │          │        │                   │                     │ https://avd.aquasec.com/nvd/cve-2023-28858  │
└─────────┴────────────────┴──────────┴────────┴───────────────────┴─────────────────────┴─────────────────────────────────────────────┘

Suppressed Vulnerabilities (Total: 1)

┌─────────┬────────────────┬──────────┬──────────────┬─────────────────────────────────────┬───────────────┐
│ Library │ Vulnerability  │ Severity │    Status    │              Statement              │    Source     │
├─────────┼────────────────┼──────────┼──────────────┼─────────────────────────────────────┼───────────────┤
│ redis   │ CVE-2023-28859 │ HIGH     │ not_affected │ vulnerable_code_not_in_execute_path │ trivy.openvex │
└─────────┴────────────────┴──────────┴──────────────┴─────────────────────────────────────┴───────────────┘
```

# まとめ
Trivy の VEX 機能を使用してみました。まだ実験的な実装とのことですが、検出された脆弱性をフィルタリングできることを確認しました。現在、VEX を生成する機能が確認できなかった。VEX のフォーマットが確定していないからか、VEX を生成するツールもほぼ無いような気がします。もし、VEX 生成ツールをご存知の方はコメント欄で教えていただけると助かります。
将来、Trivy の VEX 機能が正式にリリースされることを期待しています。

本記事を書くにあたり、 trivy vex という検索ワードで Google 検索する。検索結果の1番目に Trivy のドキュメントが表示されてこのドキュメントを参照していたのですが、なんかちゃんと動作しないと思っていたら、実は、これが古いバージョン(v0.41)のドキュメントだったのです:disappointed_relieved:。
途中でトラップへハマったことに気が付きました。正しくは[最新バージョン](https://trivy.dev/latest/docs/supply-chain/vex/)を参照してください。

もし、記述について、誤りや気になることがあれば、編集リクエストやコメントでフィードバックしていただけると助かります。